138fd1498Szrj /* Reassociation for trees.
238fd1498Szrj Copyright (C) 2005-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Daniel Berlin <dan@dberlin.org>
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify
838fd1498Szrj it under the terms of the GNU General Public License as published by
938fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
1038fd1498Szrj any later version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful,
1338fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1438fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1538fd1498Szrj GNU General Public License for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj #include "config.h"
2238fd1498Szrj #include "system.h"
2338fd1498Szrj #include "coretypes.h"
2438fd1498Szrj #include "backend.h"
2538fd1498Szrj #include "target.h"
2638fd1498Szrj #include "rtl.h"
2738fd1498Szrj #include "tree.h"
2838fd1498Szrj #include "gimple.h"
2938fd1498Szrj #include "cfghooks.h"
3038fd1498Szrj #include "alloc-pool.h"
3138fd1498Szrj #include "tree-pass.h"
3238fd1498Szrj #include "memmodel.h"
3338fd1498Szrj #include "tm_p.h"
3438fd1498Szrj #include "ssa.h"
3538fd1498Szrj #include "optabs-tree.h"
3638fd1498Szrj #include "gimple-pretty-print.h"
3738fd1498Szrj #include "diagnostic-core.h"
3838fd1498Szrj #include "fold-const.h"
3938fd1498Szrj #include "stor-layout.h"
4038fd1498Szrj #include "cfganal.h"
4138fd1498Szrj #include "gimple-fold.h"
4238fd1498Szrj #include "tree-eh.h"
4338fd1498Szrj #include "gimple-iterator.h"
4438fd1498Szrj #include "gimplify-me.h"
4538fd1498Szrj #include "tree-cfg.h"
4638fd1498Szrj #include "tree-ssa-loop.h"
4738fd1498Szrj #include "flags.h"
4838fd1498Szrj #include "tree-ssa.h"
4938fd1498Szrj #include "langhooks.h"
5038fd1498Szrj #include "cfgloop.h"
5138fd1498Szrj #include "params.h"
5238fd1498Szrj #include "builtins.h"
5338fd1498Szrj #include "gimplify.h"
5438fd1498Szrj #include "case-cfn-macros.h"
5538fd1498Szrj
5638fd1498Szrj /* This is a simple global reassociation pass. It is, in part, based
5738fd1498Szrj on the LLVM pass of the same name (They do some things more/less
5838fd1498Szrj than we do, in different orders, etc).
5938fd1498Szrj
6038fd1498Szrj It consists of five steps:
6138fd1498Szrj
6238fd1498Szrj 1. Breaking up subtract operations into addition + negate, where
6338fd1498Szrj it would promote the reassociation of adds.
6438fd1498Szrj
6538fd1498Szrj 2. Left linearization of the expression trees, so that (A+B)+(C+D)
6638fd1498Szrj becomes (((A+B)+C)+D), which is easier for us to rewrite later.
6738fd1498Szrj During linearization, we place the operands of the binary
6838fd1498Szrj expressions into a vector of operand_entry_*
6938fd1498Szrj
7038fd1498Szrj 3. Optimization of the operand lists, eliminating things like a +
7138fd1498Szrj -a, a & a, etc.
7238fd1498Szrj
7338fd1498Szrj 3a. Combine repeated factors with the same occurrence counts
7438fd1498Szrj into a __builtin_powi call that will later be optimized into
7538fd1498Szrj an optimal number of multiplies.
7638fd1498Szrj
7738fd1498Szrj 4. Rewrite the expression trees we linearized and optimized so
7838fd1498Szrj they are in proper rank order.
7938fd1498Szrj
8038fd1498Szrj 5. Repropagate negates, as nothing else will clean it up ATM.
8138fd1498Szrj
8238fd1498Szrj A bit of theory on #4, since nobody seems to write anything down
8338fd1498Szrj about why it makes sense to do it the way they do it:
8438fd1498Szrj
8538fd1498Szrj We could do this much nicer theoretically, but don't (for reasons
8638fd1498Szrj explained after how to do it theoretically nice :P).
8738fd1498Szrj
8838fd1498Szrj In order to promote the most redundancy elimination, you want
8938fd1498Szrj binary expressions whose operands are the same rank (or
9038fd1498Szrj preferably, the same value) exposed to the redundancy eliminator,
9138fd1498Szrj for possible elimination.
9238fd1498Szrj
9338fd1498Szrj So the way to do this if we really cared, is to build the new op
9438fd1498Szrj tree from the leaves to the roots, merging as you go, and putting the
9538fd1498Szrj new op on the end of the worklist, until you are left with one
9638fd1498Szrj thing on the worklist.
9738fd1498Szrj
9838fd1498Szrj IE if you have to rewrite the following set of operands (listed with
9938fd1498Szrj rank in parentheses), with opcode PLUS_EXPR:
10038fd1498Szrj
10138fd1498Szrj a (1), b (1), c (1), d (2), e (2)
10238fd1498Szrj
10338fd1498Szrj
10438fd1498Szrj We start with our merge worklist empty, and the ops list with all of
10538fd1498Szrj those on it.
10638fd1498Szrj
10738fd1498Szrj You want to first merge all leaves of the same rank, as much as
10838fd1498Szrj possible.
10938fd1498Szrj
11038fd1498Szrj So first build a binary op of
11138fd1498Szrj
11238fd1498Szrj mergetmp = a + b, and put "mergetmp" on the merge worklist.
11338fd1498Szrj
11438fd1498Szrj Because there is no three operand form of PLUS_EXPR, c is not going to
11538fd1498Szrj be exposed to redundancy elimination as a rank 1 operand.
11638fd1498Szrj
11738fd1498Szrj So you might as well throw it on the merge worklist (you could also
11838fd1498Szrj consider it to now be a rank two operand, and merge it with d and e,
11938fd1498Szrj but in this case, you then have evicted e from a binary op. So at
12038fd1498Szrj least in this situation, you can't win.)
12138fd1498Szrj
12238fd1498Szrj Then build a binary op of d + e
12338fd1498Szrj mergetmp2 = d + e
12438fd1498Szrj
12538fd1498Szrj and put mergetmp2 on the merge worklist.
12638fd1498Szrj
12738fd1498Szrj so merge worklist = {mergetmp, c, mergetmp2}
12838fd1498Szrj
12938fd1498Szrj Continue building binary ops of these operations until you have only
13038fd1498Szrj one operation left on the worklist.
13138fd1498Szrj
13238fd1498Szrj So we have
13338fd1498Szrj
13438fd1498Szrj build binary op
13538fd1498Szrj mergetmp3 = mergetmp + c
13638fd1498Szrj
13738fd1498Szrj worklist = {mergetmp2, mergetmp3}
13838fd1498Szrj
13938fd1498Szrj mergetmp4 = mergetmp2 + mergetmp3
14038fd1498Szrj
14138fd1498Szrj worklist = {mergetmp4}
14238fd1498Szrj
14338fd1498Szrj because we have one operation left, we can now just set the original
14438fd1498Szrj statement equal to the result of that operation.
14538fd1498Szrj
14638fd1498Szrj This will at least expose a + b and d + e to redundancy elimination
14738fd1498Szrj as binary operations.
14838fd1498Szrj
14938fd1498Szrj For extra points, you can reuse the old statements to build the
15038fd1498Szrj mergetmps, since you shouldn't run out.
15138fd1498Szrj
15238fd1498Szrj So why don't we do this?
15338fd1498Szrj
15438fd1498Szrj Because it's expensive, and rarely will help. Most trees we are
15538fd1498Szrj reassociating have 3 or less ops. If they have 2 ops, they already
15638fd1498Szrj will be written into a nice single binary op. If you have 3 ops, a
15738fd1498Szrj single simple check suffices to tell you whether the first two are of the
15838fd1498Szrj same rank. If so, you know to order it
15938fd1498Szrj
16038fd1498Szrj mergetmp = op1 + op2
16138fd1498Szrj newstmt = mergetmp + op3
16238fd1498Szrj
16338fd1498Szrj instead of
16438fd1498Szrj mergetmp = op2 + op3
16538fd1498Szrj newstmt = mergetmp + op1
16638fd1498Szrj
16738fd1498Szrj If all three are of the same rank, you can't expose them all in a
16838fd1498Szrj single binary operator anyway, so the above is *still* the best you
16938fd1498Szrj can do.
17038fd1498Szrj
17138fd1498Szrj Thus, this is what we do. When we have three ops left, we check to see
17238fd1498Szrj what order to put them in, and call it a day. As a nod to vector sum
17338fd1498Szrj reduction, we check if any of the ops are really a phi node that is a
17438fd1498Szrj destructive update for the associating op, and keep the destructive
17538fd1498Szrj update together for vector sum reduction recognition. */
17638fd1498Szrj
17738fd1498Szrj /* Enable insertion of __builtin_powi calls during execute_reassoc. See
17838fd1498Szrj point 3a in the pass header comment. */
17938fd1498Szrj static bool reassoc_insert_powi_p;
18038fd1498Szrj
18138fd1498Szrj /* Statistics */
18238fd1498Szrj static struct
18338fd1498Szrj {
18438fd1498Szrj int linearized;
18538fd1498Szrj int constants_eliminated;
18638fd1498Szrj int ops_eliminated;
18738fd1498Szrj int rewritten;
18838fd1498Szrj int pows_encountered;
18938fd1498Szrj int pows_created;
19038fd1498Szrj } reassociate_stats;
19138fd1498Szrj
19238fd1498Szrj /* Operator, rank pair. */
19338fd1498Szrj struct operand_entry
19438fd1498Szrj {
19538fd1498Szrj unsigned int rank;
19638fd1498Szrj unsigned int id;
19738fd1498Szrj tree op;
19838fd1498Szrj unsigned int count;
19938fd1498Szrj gimple *stmt_to_insert;
20038fd1498Szrj };
20138fd1498Szrj
20238fd1498Szrj static object_allocator<operand_entry> operand_entry_pool
20338fd1498Szrj ("operand entry pool");
20438fd1498Szrj
20538fd1498Szrj /* This is used to assign a unique ID to each struct operand_entry
20638fd1498Szrj so that qsort results are identical on different hosts. */
20738fd1498Szrj static unsigned int next_operand_entry_id;
20838fd1498Szrj
20938fd1498Szrj /* Starting rank number for a given basic block, so that we can rank
21038fd1498Szrj operations using unmovable instructions in that BB based on the bb
21138fd1498Szrj depth. */
21238fd1498Szrj static long *bb_rank;
21338fd1498Szrj
21438fd1498Szrj /* Operand->rank hashtable. */
21538fd1498Szrj static hash_map<tree, long> *operand_rank;
21638fd1498Szrj
21738fd1498Szrj /* Vector of SSA_NAMEs on which after reassociate_bb is done with
21838fd1498Szrj all basic blocks the CFG should be adjusted - basic blocks
21938fd1498Szrj split right after that SSA_NAME's definition statement and before
22038fd1498Szrj the only use, which must be a bit ior. */
22138fd1498Szrj static vec<tree> reassoc_branch_fixups;
22238fd1498Szrj
22338fd1498Szrj /* Forward decls. */
22438fd1498Szrj static long get_rank (tree);
22538fd1498Szrj static bool reassoc_stmt_dominates_stmt_p (gimple *, gimple *);
22638fd1498Szrj
22738fd1498Szrj /* Wrapper around gsi_remove, which adjusts gimple_uid of debug stmts
22838fd1498Szrj possibly added by gsi_remove. */
22938fd1498Szrj
23038fd1498Szrj bool
reassoc_remove_stmt(gimple_stmt_iterator * gsi)23138fd1498Szrj reassoc_remove_stmt (gimple_stmt_iterator *gsi)
23238fd1498Szrj {
23338fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
23438fd1498Szrj
23538fd1498Szrj if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI)
23638fd1498Szrj return gsi_remove (gsi, true);
23738fd1498Szrj
23838fd1498Szrj gimple_stmt_iterator prev = *gsi;
23938fd1498Szrj gsi_prev (&prev);
24038fd1498Szrj unsigned uid = gimple_uid (stmt);
24138fd1498Szrj basic_block bb = gimple_bb (stmt);
24238fd1498Szrj bool ret = gsi_remove (gsi, true);
24338fd1498Szrj if (!gsi_end_p (prev))
24438fd1498Szrj gsi_next (&prev);
24538fd1498Szrj else
24638fd1498Szrj prev = gsi_start_bb (bb);
24738fd1498Szrj gimple *end_stmt = gsi_stmt (*gsi);
24838fd1498Szrj while ((stmt = gsi_stmt (prev)) != end_stmt)
24938fd1498Szrj {
25038fd1498Szrj gcc_assert (stmt && is_gimple_debug (stmt) && gimple_uid (stmt) == 0);
25138fd1498Szrj gimple_set_uid (stmt, uid);
25238fd1498Szrj gsi_next (&prev);
25338fd1498Szrj }
25438fd1498Szrj return ret;
25538fd1498Szrj }
25638fd1498Szrj
25738fd1498Szrj /* Bias amount for loop-carried phis. We want this to be larger than
25838fd1498Szrj the depth of any reassociation tree we can see, but not larger than
25938fd1498Szrj the rank difference between two blocks. */
26038fd1498Szrj #define PHI_LOOP_BIAS (1 << 15)
26138fd1498Szrj
26238fd1498Szrj /* Rank assigned to a phi statement. If STMT is a loop-carried phi of
26338fd1498Szrj an innermost loop, and the phi has only a single use which is inside
26438fd1498Szrj the loop, then the rank is the block rank of the loop latch plus an
26538fd1498Szrj extra bias for the loop-carried dependence. This causes expressions
26638fd1498Szrj calculated into an accumulator variable to be independent for each
26738fd1498Szrj iteration of the loop. If STMT is some other phi, the rank is the
26838fd1498Szrj block rank of its containing block. */
26938fd1498Szrj static long
phi_rank(gimple * stmt)27038fd1498Szrj phi_rank (gimple *stmt)
27138fd1498Szrj {
27238fd1498Szrj basic_block bb = gimple_bb (stmt);
27338fd1498Szrj struct loop *father = bb->loop_father;
27438fd1498Szrj tree res;
27538fd1498Szrj unsigned i;
27638fd1498Szrj use_operand_p use;
27738fd1498Szrj gimple *use_stmt;
27838fd1498Szrj
27938fd1498Szrj /* We only care about real loops (those with a latch). */
28038fd1498Szrj if (!father->latch)
28138fd1498Szrj return bb_rank[bb->index];
28238fd1498Szrj
28338fd1498Szrj /* Interesting phis must be in headers of innermost loops. */
28438fd1498Szrj if (bb != father->header
28538fd1498Szrj || father->inner)
28638fd1498Szrj return bb_rank[bb->index];
28738fd1498Szrj
28838fd1498Szrj /* Ignore virtual SSA_NAMEs. */
28938fd1498Szrj res = gimple_phi_result (stmt);
29038fd1498Szrj if (virtual_operand_p (res))
29138fd1498Szrj return bb_rank[bb->index];
29238fd1498Szrj
29338fd1498Szrj /* The phi definition must have a single use, and that use must be
29438fd1498Szrj within the loop. Otherwise this isn't an accumulator pattern. */
29538fd1498Szrj if (!single_imm_use (res, &use, &use_stmt)
29638fd1498Szrj || gimple_bb (use_stmt)->loop_father != father)
29738fd1498Szrj return bb_rank[bb->index];
29838fd1498Szrj
29938fd1498Szrj /* Look for phi arguments from within the loop. If found, bias this phi. */
30038fd1498Szrj for (i = 0; i < gimple_phi_num_args (stmt); i++)
30138fd1498Szrj {
30238fd1498Szrj tree arg = gimple_phi_arg_def (stmt, i);
30338fd1498Szrj if (TREE_CODE (arg) == SSA_NAME
30438fd1498Szrj && !SSA_NAME_IS_DEFAULT_DEF (arg))
30538fd1498Szrj {
30638fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
30738fd1498Szrj if (gimple_bb (def_stmt)->loop_father == father)
30838fd1498Szrj return bb_rank[father->latch->index] + PHI_LOOP_BIAS;
30938fd1498Szrj }
31038fd1498Szrj }
31138fd1498Szrj
31238fd1498Szrj /* Must be an uninteresting phi. */
31338fd1498Szrj return bb_rank[bb->index];
31438fd1498Szrj }
31538fd1498Szrj
31638fd1498Szrj /* If EXP is an SSA_NAME defined by a PHI statement that represents a
31738fd1498Szrj loop-carried dependence of an innermost loop, return TRUE; else
31838fd1498Szrj return FALSE. */
31938fd1498Szrj static bool
loop_carried_phi(tree exp)32038fd1498Szrj loop_carried_phi (tree exp)
32138fd1498Szrj {
32238fd1498Szrj gimple *phi_stmt;
32338fd1498Szrj long block_rank;
32438fd1498Szrj
32538fd1498Szrj if (TREE_CODE (exp) != SSA_NAME
32638fd1498Szrj || SSA_NAME_IS_DEFAULT_DEF (exp))
32738fd1498Szrj return false;
32838fd1498Szrj
32938fd1498Szrj phi_stmt = SSA_NAME_DEF_STMT (exp);
33038fd1498Szrj
33138fd1498Szrj if (gimple_code (SSA_NAME_DEF_STMT (exp)) != GIMPLE_PHI)
33238fd1498Szrj return false;
33338fd1498Szrj
33438fd1498Szrj /* Non-loop-carried phis have block rank. Loop-carried phis have
33538fd1498Szrj an additional bias added in. If this phi doesn't have block rank,
33638fd1498Szrj it's biased and should not be propagated. */
33738fd1498Szrj block_rank = bb_rank[gimple_bb (phi_stmt)->index];
33838fd1498Szrj
33938fd1498Szrj if (phi_rank (phi_stmt) != block_rank)
34038fd1498Szrj return true;
34138fd1498Szrj
34238fd1498Szrj return false;
34338fd1498Szrj }
34438fd1498Szrj
34538fd1498Szrj /* Return the maximum of RANK and the rank that should be propagated
34638fd1498Szrj from expression OP. For most operands, this is just the rank of OP.
34738fd1498Szrj For loop-carried phis, the value is zero to avoid undoing the bias
34838fd1498Szrj in favor of the phi. */
34938fd1498Szrj static long
propagate_rank(long rank,tree op)35038fd1498Szrj propagate_rank (long rank, tree op)
35138fd1498Szrj {
35238fd1498Szrj long op_rank;
35338fd1498Szrj
35438fd1498Szrj if (loop_carried_phi (op))
35538fd1498Szrj return rank;
35638fd1498Szrj
35738fd1498Szrj op_rank = get_rank (op);
35838fd1498Szrj
35938fd1498Szrj return MAX (rank, op_rank);
36038fd1498Szrj }
36138fd1498Szrj
36238fd1498Szrj /* Look up the operand rank structure for expression E. */
36338fd1498Szrj
36438fd1498Szrj static inline long
find_operand_rank(tree e)36538fd1498Szrj find_operand_rank (tree e)
36638fd1498Szrj {
36738fd1498Szrj long *slot = operand_rank->get (e);
36838fd1498Szrj return slot ? *slot : -1;
36938fd1498Szrj }
37038fd1498Szrj
37138fd1498Szrj /* Insert {E,RANK} into the operand rank hashtable. */
37238fd1498Szrj
37338fd1498Szrj static inline void
insert_operand_rank(tree e,long rank)37438fd1498Szrj insert_operand_rank (tree e, long rank)
37538fd1498Szrj {
37638fd1498Szrj gcc_assert (rank > 0);
37738fd1498Szrj gcc_assert (!operand_rank->put (e, rank));
37838fd1498Szrj }
37938fd1498Szrj
38038fd1498Szrj /* Given an expression E, return the rank of the expression. */
38138fd1498Szrj
38238fd1498Szrj static long
get_rank(tree e)38338fd1498Szrj get_rank (tree e)
38438fd1498Szrj {
38538fd1498Szrj /* SSA_NAME's have the rank of the expression they are the result
38638fd1498Szrj of.
38738fd1498Szrj For globals and uninitialized values, the rank is 0.
38838fd1498Szrj For function arguments, use the pre-setup rank.
38938fd1498Szrj For PHI nodes, stores, asm statements, etc, we use the rank of
39038fd1498Szrj the BB.
39138fd1498Szrj For simple operations, the rank is the maximum rank of any of
39238fd1498Szrj its operands, or the bb_rank, whichever is less.
39338fd1498Szrj I make no claims that this is optimal, however, it gives good
39438fd1498Szrj results. */
39538fd1498Szrj
39638fd1498Szrj /* We make an exception to the normal ranking system to break
39738fd1498Szrj dependences of accumulator variables in loops. Suppose we
39838fd1498Szrj have a simple one-block loop containing:
39938fd1498Szrj
40038fd1498Szrj x_1 = phi(x_0, x_2)
40138fd1498Szrj b = a + x_1
40238fd1498Szrj c = b + d
40338fd1498Szrj x_2 = c + e
40438fd1498Szrj
40538fd1498Szrj As shown, each iteration of the calculation into x is fully
40638fd1498Szrj dependent upon the iteration before it. We would prefer to
40738fd1498Szrj see this in the form:
40838fd1498Szrj
40938fd1498Szrj x_1 = phi(x_0, x_2)
41038fd1498Szrj b = a + d
41138fd1498Szrj c = b + e
41238fd1498Szrj x_2 = c + x_1
41338fd1498Szrj
41438fd1498Szrj If the loop is unrolled, the calculations of b and c from
41538fd1498Szrj different iterations can be interleaved.
41638fd1498Szrj
41738fd1498Szrj To obtain this result during reassociation, we bias the rank
41838fd1498Szrj of the phi definition x_1 upward, when it is recognized as an
41938fd1498Szrj accumulator pattern. The artificial rank causes it to be
42038fd1498Szrj added last, providing the desired independence. */
42138fd1498Szrj
42238fd1498Szrj if (TREE_CODE (e) == SSA_NAME)
42338fd1498Szrj {
42438fd1498Szrj ssa_op_iter iter;
42538fd1498Szrj gimple *stmt;
42638fd1498Szrj long rank;
42738fd1498Szrj tree op;
42838fd1498Szrj
42938fd1498Szrj if (SSA_NAME_IS_DEFAULT_DEF (e))
43038fd1498Szrj return find_operand_rank (e);
43138fd1498Szrj
43238fd1498Szrj stmt = SSA_NAME_DEF_STMT (e);
43338fd1498Szrj if (gimple_code (stmt) == GIMPLE_PHI)
43438fd1498Szrj return phi_rank (stmt);
43538fd1498Szrj
43638fd1498Szrj if (!is_gimple_assign (stmt))
43738fd1498Szrj return bb_rank[gimple_bb (stmt)->index];
43838fd1498Szrj
43938fd1498Szrj /* If we already have a rank for this expression, use that. */
44038fd1498Szrj rank = find_operand_rank (e);
44138fd1498Szrj if (rank != -1)
44238fd1498Szrj return rank;
44338fd1498Szrj
44438fd1498Szrj /* Otherwise, find the maximum rank for the operands. As an
44538fd1498Szrj exception, remove the bias from loop-carried phis when propagating
44638fd1498Szrj the rank so that dependent operations are not also biased. */
44738fd1498Szrj /* Simply walk over all SSA uses - this takes advatage of the
44838fd1498Szrj fact that non-SSA operands are is_gimple_min_invariant and
44938fd1498Szrj thus have rank 0. */
45038fd1498Szrj rank = 0;
45138fd1498Szrj FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
45238fd1498Szrj rank = propagate_rank (rank, op);
45338fd1498Szrj
45438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
45538fd1498Szrj {
45638fd1498Szrj fprintf (dump_file, "Rank for ");
45738fd1498Szrj print_generic_expr (dump_file, e);
45838fd1498Szrj fprintf (dump_file, " is %ld\n", (rank + 1));
45938fd1498Szrj }
46038fd1498Szrj
46138fd1498Szrj /* Note the rank in the hashtable so we don't recompute it. */
46238fd1498Szrj insert_operand_rank (e, (rank + 1));
46338fd1498Szrj return (rank + 1);
46438fd1498Szrj }
46538fd1498Szrj
46638fd1498Szrj /* Constants, globals, etc., are rank 0 */
46738fd1498Szrj return 0;
46838fd1498Szrj }
46938fd1498Szrj
47038fd1498Szrj
47138fd1498Szrj /* We want integer ones to end up last no matter what, since they are
47238fd1498Szrj the ones we can do the most with. */
47338fd1498Szrj #define INTEGER_CONST_TYPE 1 << 4
47438fd1498Szrj #define FLOAT_ONE_CONST_TYPE 1 << 3
47538fd1498Szrj #define FLOAT_CONST_TYPE 1 << 2
47638fd1498Szrj #define OTHER_CONST_TYPE 1 << 1
47738fd1498Szrj
47838fd1498Szrj /* Classify an invariant tree into integer, float, or other, so that
47938fd1498Szrj we can sort them to be near other constants of the same type. */
48038fd1498Szrj static inline int
constant_type(tree t)48138fd1498Szrj constant_type (tree t)
48238fd1498Szrj {
48338fd1498Szrj if (INTEGRAL_TYPE_P (TREE_TYPE (t)))
48438fd1498Szrj return INTEGER_CONST_TYPE;
48538fd1498Szrj else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (t)))
48638fd1498Szrj {
48738fd1498Szrj /* Sort -1.0 and 1.0 constants last, while in some cases
48838fd1498Szrj const_binop can't optimize some inexact operations, multiplication
48938fd1498Szrj by -1.0 or 1.0 can be always merged with others. */
49038fd1498Szrj if (real_onep (t) || real_minus_onep (t))
49138fd1498Szrj return FLOAT_ONE_CONST_TYPE;
49238fd1498Szrj return FLOAT_CONST_TYPE;
49338fd1498Szrj }
49438fd1498Szrj else
49538fd1498Szrj return OTHER_CONST_TYPE;
49638fd1498Szrj }
49738fd1498Szrj
49838fd1498Szrj /* qsort comparison function to sort operand entries PA and PB by rank
49938fd1498Szrj so that the sorted array is ordered by rank in decreasing order. */
50038fd1498Szrj static int
sort_by_operand_rank(const void * pa,const void * pb)50138fd1498Szrj sort_by_operand_rank (const void *pa, const void *pb)
50238fd1498Szrj {
50338fd1498Szrj const operand_entry *oea = *(const operand_entry *const *)pa;
50438fd1498Szrj const operand_entry *oeb = *(const operand_entry *const *)pb;
50538fd1498Szrj
50638fd1498Szrj if (oeb->rank != oea->rank)
50738fd1498Szrj return oeb->rank > oea->rank ? 1 : -1;
50838fd1498Szrj
50938fd1498Szrj /* It's nicer for optimize_expression if constants that are likely
51038fd1498Szrj to fold when added/multiplied/whatever are put next to each
51138fd1498Szrj other. Since all constants have rank 0, order them by type. */
51238fd1498Szrj if (oea->rank == 0)
51338fd1498Szrj {
51438fd1498Szrj if (constant_type (oeb->op) != constant_type (oea->op))
51538fd1498Szrj return constant_type (oea->op) - constant_type (oeb->op);
51638fd1498Szrj else
51738fd1498Szrj /* To make sorting result stable, we use unique IDs to determine
51838fd1498Szrj order. */
51938fd1498Szrj return oeb->id > oea->id ? 1 : -1;
52038fd1498Szrj }
52138fd1498Szrj
52238fd1498Szrj if (TREE_CODE (oea->op) != SSA_NAME)
52338fd1498Szrj {
52438fd1498Szrj if (TREE_CODE (oeb->op) != SSA_NAME)
52538fd1498Szrj return oeb->id > oea->id ? 1 : -1;
52638fd1498Szrj else
52738fd1498Szrj return 1;
52838fd1498Szrj }
52938fd1498Szrj else if (TREE_CODE (oeb->op) != SSA_NAME)
53038fd1498Szrj return -1;
53138fd1498Szrj
53238fd1498Szrj /* Lastly, make sure the versions that are the same go next to each
53338fd1498Szrj other. */
53438fd1498Szrj if (SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op))
53538fd1498Szrj {
53638fd1498Szrj /* As SSA_NAME_VERSION is assigned pretty randomly, because we reuse
53738fd1498Szrj versions of removed SSA_NAMEs, so if possible, prefer to sort
53838fd1498Szrj based on basic block and gimple_uid of the SSA_NAME_DEF_STMT.
53938fd1498Szrj See PR60418. */
54038fd1498Szrj gimple *stmta = SSA_NAME_DEF_STMT (oea->op);
54138fd1498Szrj gimple *stmtb = SSA_NAME_DEF_STMT (oeb->op);
54238fd1498Szrj basic_block bba = gimple_bb (stmta);
54338fd1498Szrj basic_block bbb = gimple_bb (stmtb);
54438fd1498Szrj if (bbb != bba)
54538fd1498Szrj {
54638fd1498Szrj /* One of the SSA_NAMEs can be defined in oeN->stmt_to_insert
54738fd1498Szrj but the other might not. */
54838fd1498Szrj if (!bba)
54938fd1498Szrj return 1;
55038fd1498Szrj if (!bbb)
55138fd1498Szrj return -1;
55238fd1498Szrj /* If neither is, compare bb_rank. */
55338fd1498Szrj if (bb_rank[bbb->index] != bb_rank[bba->index])
55438fd1498Szrj return (bb_rank[bbb->index] >> 16) - (bb_rank[bba->index] >> 16);
55538fd1498Szrj }
55638fd1498Szrj
55738fd1498Szrj bool da = reassoc_stmt_dominates_stmt_p (stmta, stmtb);
55838fd1498Szrj bool db = reassoc_stmt_dominates_stmt_p (stmtb, stmta);
55938fd1498Szrj if (da != db)
56038fd1498Szrj return da ? 1 : -1;
56138fd1498Szrj
56238fd1498Szrj return SSA_NAME_VERSION (oeb->op) > SSA_NAME_VERSION (oea->op) ? 1 : -1;
56338fd1498Szrj }
56438fd1498Szrj
56538fd1498Szrj return oeb->id > oea->id ? 1 : -1;
56638fd1498Szrj }
56738fd1498Szrj
56838fd1498Szrj /* Add an operand entry to *OPS for the tree operand OP. */
56938fd1498Szrj
57038fd1498Szrj static void
57138fd1498Szrj add_to_ops_vec (vec<operand_entry *> *ops, tree op, gimple *stmt_to_insert = NULL)
57238fd1498Szrj {
57338fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
57438fd1498Szrj
57538fd1498Szrj oe->op = op;
57638fd1498Szrj oe->rank = get_rank (op);
57738fd1498Szrj oe->id = next_operand_entry_id++;
57838fd1498Szrj oe->count = 1;
57938fd1498Szrj oe->stmt_to_insert = stmt_to_insert;
58038fd1498Szrj ops->safe_push (oe);
58138fd1498Szrj }
58238fd1498Szrj
58338fd1498Szrj /* Add an operand entry to *OPS for the tree operand OP with repeat
58438fd1498Szrj count REPEAT. */
58538fd1498Szrj
58638fd1498Szrj static void
add_repeat_to_ops_vec(vec<operand_entry * > * ops,tree op,HOST_WIDE_INT repeat)58738fd1498Szrj add_repeat_to_ops_vec (vec<operand_entry *> *ops, tree op,
58838fd1498Szrj HOST_WIDE_INT repeat)
58938fd1498Szrj {
59038fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
59138fd1498Szrj
59238fd1498Szrj oe->op = op;
59338fd1498Szrj oe->rank = get_rank (op);
59438fd1498Szrj oe->id = next_operand_entry_id++;
59538fd1498Szrj oe->count = repeat;
59638fd1498Szrj oe->stmt_to_insert = NULL;
59738fd1498Szrj ops->safe_push (oe);
59838fd1498Szrj
59938fd1498Szrj reassociate_stats.pows_encountered++;
60038fd1498Szrj }
60138fd1498Szrj
60238fd1498Szrj /* Return true if STMT is reassociable operation containing a binary
60338fd1498Szrj operation with tree code CODE, and is inside LOOP. */
60438fd1498Szrj
60538fd1498Szrj static bool
is_reassociable_op(gimple * stmt,enum tree_code code,struct loop * loop)60638fd1498Szrj is_reassociable_op (gimple *stmt, enum tree_code code, struct loop *loop)
60738fd1498Szrj {
60838fd1498Szrj basic_block bb = gimple_bb (stmt);
60938fd1498Szrj
61038fd1498Szrj if (gimple_bb (stmt) == NULL)
61138fd1498Szrj return false;
61238fd1498Szrj
61338fd1498Szrj if (!flow_bb_inside_loop_p (loop, bb))
61438fd1498Szrj return false;
61538fd1498Szrj
61638fd1498Szrj if (is_gimple_assign (stmt)
61738fd1498Szrj && gimple_assign_rhs_code (stmt) == code
61838fd1498Szrj && has_single_use (gimple_assign_lhs (stmt)))
61938fd1498Szrj {
62038fd1498Szrj tree rhs1 = gimple_assign_rhs1 (stmt);
62138fd1498Szrj tree rhs2 = gimple_assign_rhs1 (stmt);
62238fd1498Szrj if (TREE_CODE (rhs1) == SSA_NAME
62338fd1498Szrj && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1))
62438fd1498Szrj return false;
62538fd1498Szrj if (rhs2
62638fd1498Szrj && TREE_CODE (rhs2) == SSA_NAME
62738fd1498Szrj && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs2))
62838fd1498Szrj return false;
62938fd1498Szrj return true;
63038fd1498Szrj }
63138fd1498Szrj
63238fd1498Szrj return false;
63338fd1498Szrj }
63438fd1498Szrj
63538fd1498Szrj
63638fd1498Szrj /* Return true if STMT is a nop-conversion. */
63738fd1498Szrj
63838fd1498Szrj static bool
gimple_nop_conversion_p(gimple * stmt)63938fd1498Szrj gimple_nop_conversion_p (gimple *stmt)
64038fd1498Szrj {
64138fd1498Szrj if (gassign *ass = dyn_cast <gassign *> (stmt))
64238fd1498Szrj {
64338fd1498Szrj if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (ass))
64438fd1498Szrj && tree_nop_conversion_p (TREE_TYPE (gimple_assign_lhs (ass)),
64538fd1498Szrj TREE_TYPE (gimple_assign_rhs1 (ass))))
64638fd1498Szrj return true;
64738fd1498Szrj }
64838fd1498Szrj return false;
64938fd1498Szrj }
65038fd1498Szrj
65138fd1498Szrj /* Given NAME, if NAME is defined by a unary operation OPCODE, return the
65238fd1498Szrj operand of the negate operation. Otherwise, return NULL. */
65338fd1498Szrj
65438fd1498Szrj static tree
get_unary_op(tree name,enum tree_code opcode)65538fd1498Szrj get_unary_op (tree name, enum tree_code opcode)
65638fd1498Szrj {
65738fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (name);
65838fd1498Szrj
65938fd1498Szrj /* Look through nop conversions (sign changes). */
66038fd1498Szrj if (gimple_nop_conversion_p (stmt)
66138fd1498Szrj && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
66238fd1498Szrj stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
66338fd1498Szrj
66438fd1498Szrj if (!is_gimple_assign (stmt))
66538fd1498Szrj return NULL_TREE;
66638fd1498Szrj
66738fd1498Szrj if (gimple_assign_rhs_code (stmt) == opcode)
66838fd1498Szrj return gimple_assign_rhs1 (stmt);
66938fd1498Szrj return NULL_TREE;
67038fd1498Szrj }
67138fd1498Szrj
67238fd1498Szrj /* Return true if OP1 and OP2 have the same value if casted to either type. */
67338fd1498Szrj
67438fd1498Szrj static bool
ops_equal_values_p(tree op1,tree op2)67538fd1498Szrj ops_equal_values_p (tree op1, tree op2)
67638fd1498Szrj {
67738fd1498Szrj if (op1 == op2)
67838fd1498Szrj return true;
67938fd1498Szrj
68038fd1498Szrj tree orig_op1 = op1;
68138fd1498Szrj if (TREE_CODE (op1) == SSA_NAME)
68238fd1498Szrj {
68338fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (op1);
68438fd1498Szrj if (gimple_nop_conversion_p (stmt))
68538fd1498Szrj {
68638fd1498Szrj op1 = gimple_assign_rhs1 (stmt);
68738fd1498Szrj if (op1 == op2)
68838fd1498Szrj return true;
68938fd1498Szrj }
69038fd1498Szrj }
69138fd1498Szrj
69238fd1498Szrj if (TREE_CODE (op2) == SSA_NAME)
69338fd1498Szrj {
69438fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (op2);
69538fd1498Szrj if (gimple_nop_conversion_p (stmt))
69638fd1498Szrj {
69738fd1498Szrj op2 = gimple_assign_rhs1 (stmt);
69838fd1498Szrj if (op1 == op2
69938fd1498Szrj || orig_op1 == op2)
70038fd1498Szrj return true;
70138fd1498Szrj }
70238fd1498Szrj }
70338fd1498Szrj
70438fd1498Szrj return false;
70538fd1498Szrj }
70638fd1498Szrj
70738fd1498Szrj
70838fd1498Szrj /* If CURR and LAST are a pair of ops that OPCODE allows us to
70938fd1498Szrj eliminate through equivalences, do so, remove them from OPS, and
71038fd1498Szrj return true. Otherwise, return false. */
71138fd1498Szrj
71238fd1498Szrj static bool
eliminate_duplicate_pair(enum tree_code opcode,vec<operand_entry * > * ops,bool * all_done,unsigned int i,operand_entry * curr,operand_entry * last)71338fd1498Szrj eliminate_duplicate_pair (enum tree_code opcode,
71438fd1498Szrj vec<operand_entry *> *ops,
71538fd1498Szrj bool *all_done,
71638fd1498Szrj unsigned int i,
71738fd1498Szrj operand_entry *curr,
71838fd1498Szrj operand_entry *last)
71938fd1498Szrj {
72038fd1498Szrj
72138fd1498Szrj /* If we have two of the same op, and the opcode is & |, min, or max,
72238fd1498Szrj we can eliminate one of them.
72338fd1498Szrj If we have two of the same op, and the opcode is ^, we can
72438fd1498Szrj eliminate both of them. */
72538fd1498Szrj
72638fd1498Szrj if (last && last->op == curr->op)
72738fd1498Szrj {
72838fd1498Szrj switch (opcode)
72938fd1498Szrj {
73038fd1498Szrj case MAX_EXPR:
73138fd1498Szrj case MIN_EXPR:
73238fd1498Szrj case BIT_IOR_EXPR:
73338fd1498Szrj case BIT_AND_EXPR:
73438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
73538fd1498Szrj {
73638fd1498Szrj fprintf (dump_file, "Equivalence: ");
73738fd1498Szrj print_generic_expr (dump_file, curr->op);
73838fd1498Szrj fprintf (dump_file, " [&|minmax] ");
73938fd1498Szrj print_generic_expr (dump_file, last->op);
74038fd1498Szrj fprintf (dump_file, " -> ");
74138fd1498Szrj print_generic_stmt (dump_file, last->op);
74238fd1498Szrj }
74338fd1498Szrj
74438fd1498Szrj ops->ordered_remove (i);
74538fd1498Szrj reassociate_stats.ops_eliminated ++;
74638fd1498Szrj
74738fd1498Szrj return true;
74838fd1498Szrj
74938fd1498Szrj case BIT_XOR_EXPR:
75038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
75138fd1498Szrj {
75238fd1498Szrj fprintf (dump_file, "Equivalence: ");
75338fd1498Szrj print_generic_expr (dump_file, curr->op);
75438fd1498Szrj fprintf (dump_file, " ^ ");
75538fd1498Szrj print_generic_expr (dump_file, last->op);
75638fd1498Szrj fprintf (dump_file, " -> nothing\n");
75738fd1498Szrj }
75838fd1498Szrj
75938fd1498Szrj reassociate_stats.ops_eliminated += 2;
76038fd1498Szrj
76138fd1498Szrj if (ops->length () == 2)
76238fd1498Szrj {
76338fd1498Szrj ops->truncate (0);
76438fd1498Szrj add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (last->op)));
76538fd1498Szrj *all_done = true;
76638fd1498Szrj }
76738fd1498Szrj else
76838fd1498Szrj {
76938fd1498Szrj ops->ordered_remove (i-1);
77038fd1498Szrj ops->ordered_remove (i-1);
77138fd1498Szrj }
77238fd1498Szrj
77338fd1498Szrj return true;
77438fd1498Szrj
77538fd1498Szrj default:
77638fd1498Szrj break;
77738fd1498Szrj }
77838fd1498Szrj }
77938fd1498Szrj return false;
78038fd1498Szrj }
78138fd1498Szrj
78238fd1498Szrj static vec<tree> plus_negates;
78338fd1498Szrj
78438fd1498Szrj /* If OPCODE is PLUS_EXPR, CURR->OP is a negate expression or a bitwise not
78538fd1498Szrj expression, look in OPS for a corresponding positive operation to cancel
78638fd1498Szrj it out. If we find one, remove the other from OPS, replace
78738fd1498Szrj OPS[CURRINDEX] with 0 or -1, respectively, and return true. Otherwise,
78838fd1498Szrj return false. */
78938fd1498Szrj
79038fd1498Szrj static bool
eliminate_plus_minus_pair(enum tree_code opcode,vec<operand_entry * > * ops,unsigned int currindex,operand_entry * curr)79138fd1498Szrj eliminate_plus_minus_pair (enum tree_code opcode,
79238fd1498Szrj vec<operand_entry *> *ops,
79338fd1498Szrj unsigned int currindex,
79438fd1498Szrj operand_entry *curr)
79538fd1498Szrj {
79638fd1498Szrj tree negateop;
79738fd1498Szrj tree notop;
79838fd1498Szrj unsigned int i;
79938fd1498Szrj operand_entry *oe;
80038fd1498Szrj
80138fd1498Szrj if (opcode != PLUS_EXPR || TREE_CODE (curr->op) != SSA_NAME)
80238fd1498Szrj return false;
80338fd1498Szrj
80438fd1498Szrj negateop = get_unary_op (curr->op, NEGATE_EXPR);
80538fd1498Szrj notop = get_unary_op (curr->op, BIT_NOT_EXPR);
80638fd1498Szrj if (negateop == NULL_TREE && notop == NULL_TREE)
80738fd1498Szrj return false;
80838fd1498Szrj
80938fd1498Szrj /* Any non-negated version will have a rank that is one less than
81038fd1498Szrj the current rank. So once we hit those ranks, if we don't find
81138fd1498Szrj one, we can stop. */
81238fd1498Szrj
81338fd1498Szrj for (i = currindex + 1;
81438fd1498Szrj ops->iterate (i, &oe)
81538fd1498Szrj && oe->rank >= curr->rank - 1 ;
81638fd1498Szrj i++)
81738fd1498Szrj {
81838fd1498Szrj if (negateop
81938fd1498Szrj && ops_equal_values_p (oe->op, negateop))
82038fd1498Szrj {
82138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
82238fd1498Szrj {
82338fd1498Szrj fprintf (dump_file, "Equivalence: ");
82438fd1498Szrj print_generic_expr (dump_file, negateop);
82538fd1498Szrj fprintf (dump_file, " + -");
82638fd1498Szrj print_generic_expr (dump_file, oe->op);
82738fd1498Szrj fprintf (dump_file, " -> 0\n");
82838fd1498Szrj }
82938fd1498Szrj
83038fd1498Szrj ops->ordered_remove (i);
83138fd1498Szrj add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (oe->op)));
83238fd1498Szrj ops->ordered_remove (currindex);
83338fd1498Szrj reassociate_stats.ops_eliminated ++;
83438fd1498Szrj
83538fd1498Szrj return true;
83638fd1498Szrj }
83738fd1498Szrj else if (notop
83838fd1498Szrj && ops_equal_values_p (oe->op, notop))
83938fd1498Szrj {
84038fd1498Szrj tree op_type = TREE_TYPE (oe->op);
84138fd1498Szrj
84238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
84338fd1498Szrj {
84438fd1498Szrj fprintf (dump_file, "Equivalence: ");
84538fd1498Szrj print_generic_expr (dump_file, notop);
84638fd1498Szrj fprintf (dump_file, " + ~");
84738fd1498Szrj print_generic_expr (dump_file, oe->op);
84838fd1498Szrj fprintf (dump_file, " -> -1\n");
84938fd1498Szrj }
85038fd1498Szrj
85138fd1498Szrj ops->ordered_remove (i);
85238fd1498Szrj add_to_ops_vec (ops, build_all_ones_cst (op_type));
85338fd1498Szrj ops->ordered_remove (currindex);
85438fd1498Szrj reassociate_stats.ops_eliminated ++;
85538fd1498Szrj
85638fd1498Szrj return true;
85738fd1498Szrj }
85838fd1498Szrj }
85938fd1498Szrj
86038fd1498Szrj /* If CURR->OP is a negate expr without nop conversion in a plus expr:
86138fd1498Szrj save it for later inspection in repropagate_negates(). */
86238fd1498Szrj if (negateop != NULL_TREE
86338fd1498Szrj && gimple_assign_rhs_code (SSA_NAME_DEF_STMT (curr->op)) == NEGATE_EXPR)
86438fd1498Szrj plus_negates.safe_push (curr->op);
86538fd1498Szrj
86638fd1498Szrj return false;
86738fd1498Szrj }
86838fd1498Szrj
86938fd1498Szrj /* If OPCODE is BIT_IOR_EXPR, BIT_AND_EXPR, and, CURR->OP is really a
87038fd1498Szrj bitwise not expression, look in OPS for a corresponding operand to
87138fd1498Szrj cancel it out. If we find one, remove the other from OPS, replace
87238fd1498Szrj OPS[CURRINDEX] with 0, and return true. Otherwise, return
87338fd1498Szrj false. */
87438fd1498Szrj
87538fd1498Szrj static bool
eliminate_not_pairs(enum tree_code opcode,vec<operand_entry * > * ops,unsigned int currindex,operand_entry * curr)87638fd1498Szrj eliminate_not_pairs (enum tree_code opcode,
87738fd1498Szrj vec<operand_entry *> *ops,
87838fd1498Szrj unsigned int currindex,
87938fd1498Szrj operand_entry *curr)
88038fd1498Szrj {
88138fd1498Szrj tree notop;
88238fd1498Szrj unsigned int i;
88338fd1498Szrj operand_entry *oe;
88438fd1498Szrj
88538fd1498Szrj if ((opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR)
88638fd1498Szrj || TREE_CODE (curr->op) != SSA_NAME)
88738fd1498Szrj return false;
88838fd1498Szrj
88938fd1498Szrj notop = get_unary_op (curr->op, BIT_NOT_EXPR);
89038fd1498Szrj if (notop == NULL_TREE)
89138fd1498Szrj return false;
89238fd1498Szrj
89338fd1498Szrj /* Any non-not version will have a rank that is one less than
89438fd1498Szrj the current rank. So once we hit those ranks, if we don't find
89538fd1498Szrj one, we can stop. */
89638fd1498Szrj
89738fd1498Szrj for (i = currindex + 1;
89838fd1498Szrj ops->iterate (i, &oe)
89938fd1498Szrj && oe->rank >= curr->rank - 1;
90038fd1498Szrj i++)
90138fd1498Szrj {
90238fd1498Szrj if (oe->op == notop)
90338fd1498Szrj {
90438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
90538fd1498Szrj {
90638fd1498Szrj fprintf (dump_file, "Equivalence: ");
90738fd1498Szrj print_generic_expr (dump_file, notop);
90838fd1498Szrj if (opcode == BIT_AND_EXPR)
90938fd1498Szrj fprintf (dump_file, " & ~");
91038fd1498Szrj else if (opcode == BIT_IOR_EXPR)
91138fd1498Szrj fprintf (dump_file, " | ~");
91238fd1498Szrj print_generic_expr (dump_file, oe->op);
91338fd1498Szrj if (opcode == BIT_AND_EXPR)
91438fd1498Szrj fprintf (dump_file, " -> 0\n");
91538fd1498Szrj else if (opcode == BIT_IOR_EXPR)
91638fd1498Szrj fprintf (dump_file, " -> -1\n");
91738fd1498Szrj }
91838fd1498Szrj
91938fd1498Szrj if (opcode == BIT_AND_EXPR)
92038fd1498Szrj oe->op = build_zero_cst (TREE_TYPE (oe->op));
92138fd1498Szrj else if (opcode == BIT_IOR_EXPR)
92238fd1498Szrj oe->op = build_all_ones_cst (TREE_TYPE (oe->op));
92338fd1498Szrj
92438fd1498Szrj reassociate_stats.ops_eliminated += ops->length () - 1;
92538fd1498Szrj ops->truncate (0);
92638fd1498Szrj ops->quick_push (oe);
92738fd1498Szrj return true;
92838fd1498Szrj }
92938fd1498Szrj }
93038fd1498Szrj
93138fd1498Szrj return false;
93238fd1498Szrj }
93338fd1498Szrj
93438fd1498Szrj /* Use constant value that may be present in OPS to try to eliminate
93538fd1498Szrj operands. Note that this function is only really used when we've
93638fd1498Szrj eliminated ops for other reasons, or merged constants. Across
93738fd1498Szrj single statements, fold already does all of this, plus more. There
93838fd1498Szrj is little point in duplicating logic, so I've only included the
93938fd1498Szrj identities that I could ever construct testcases to trigger. */
94038fd1498Szrj
94138fd1498Szrj static void
eliminate_using_constants(enum tree_code opcode,vec<operand_entry * > * ops)94238fd1498Szrj eliminate_using_constants (enum tree_code opcode,
94338fd1498Szrj vec<operand_entry *> *ops)
94438fd1498Szrj {
94538fd1498Szrj operand_entry *oelast = ops->last ();
94638fd1498Szrj tree type = TREE_TYPE (oelast->op);
94738fd1498Szrj
94838fd1498Szrj if (oelast->rank == 0
94938fd1498Szrj && (ANY_INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type)))
95038fd1498Szrj {
95138fd1498Szrj switch (opcode)
95238fd1498Szrj {
95338fd1498Szrj case BIT_AND_EXPR:
95438fd1498Szrj if (integer_zerop (oelast->op))
95538fd1498Szrj {
95638fd1498Szrj if (ops->length () != 1)
95738fd1498Szrj {
95838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
95938fd1498Szrj fprintf (dump_file, "Found & 0, removing all other ops\n");
96038fd1498Szrj
96138fd1498Szrj reassociate_stats.ops_eliminated += ops->length () - 1;
96238fd1498Szrj
96338fd1498Szrj ops->truncate (0);
96438fd1498Szrj ops->quick_push (oelast);
96538fd1498Szrj return;
96638fd1498Szrj }
96738fd1498Szrj }
96838fd1498Szrj else if (integer_all_onesp (oelast->op))
96938fd1498Szrj {
97038fd1498Szrj if (ops->length () != 1)
97138fd1498Szrj {
97238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
97338fd1498Szrj fprintf (dump_file, "Found & -1, removing\n");
97438fd1498Szrj ops->pop ();
97538fd1498Szrj reassociate_stats.ops_eliminated++;
97638fd1498Szrj }
97738fd1498Szrj }
97838fd1498Szrj break;
97938fd1498Szrj case BIT_IOR_EXPR:
98038fd1498Szrj if (integer_all_onesp (oelast->op))
98138fd1498Szrj {
98238fd1498Szrj if (ops->length () != 1)
98338fd1498Szrj {
98438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
98538fd1498Szrj fprintf (dump_file, "Found | -1, removing all other ops\n");
98638fd1498Szrj
98738fd1498Szrj reassociate_stats.ops_eliminated += ops->length () - 1;
98838fd1498Szrj
98938fd1498Szrj ops->truncate (0);
99038fd1498Szrj ops->quick_push (oelast);
99138fd1498Szrj return;
99238fd1498Szrj }
99338fd1498Szrj }
99438fd1498Szrj else if (integer_zerop (oelast->op))
99538fd1498Szrj {
99638fd1498Szrj if (ops->length () != 1)
99738fd1498Szrj {
99838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
99938fd1498Szrj fprintf (dump_file, "Found | 0, removing\n");
100038fd1498Szrj ops->pop ();
100138fd1498Szrj reassociate_stats.ops_eliminated++;
100238fd1498Szrj }
100338fd1498Szrj }
100438fd1498Szrj break;
100538fd1498Szrj case MULT_EXPR:
100638fd1498Szrj if (integer_zerop (oelast->op)
100738fd1498Szrj || (FLOAT_TYPE_P (type)
100838fd1498Szrj && !HONOR_NANS (type)
100938fd1498Szrj && !HONOR_SIGNED_ZEROS (type)
101038fd1498Szrj && real_zerop (oelast->op)))
101138fd1498Szrj {
101238fd1498Szrj if (ops->length () != 1)
101338fd1498Szrj {
101438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
101538fd1498Szrj fprintf (dump_file, "Found * 0, removing all other ops\n");
101638fd1498Szrj
101738fd1498Szrj reassociate_stats.ops_eliminated += ops->length () - 1;
1018*58e805e6Szrj ops->truncate (0);
101938fd1498Szrj ops->quick_push (oelast);
102038fd1498Szrj return;
102138fd1498Szrj }
102238fd1498Szrj }
102338fd1498Szrj else if (integer_onep (oelast->op)
102438fd1498Szrj || (FLOAT_TYPE_P (type)
102538fd1498Szrj && !HONOR_SNANS (type)
102638fd1498Szrj && real_onep (oelast->op)))
102738fd1498Szrj {
102838fd1498Szrj if (ops->length () != 1)
102938fd1498Szrj {
103038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
103138fd1498Szrj fprintf (dump_file, "Found * 1, removing\n");
103238fd1498Szrj ops->pop ();
103338fd1498Szrj reassociate_stats.ops_eliminated++;
103438fd1498Szrj return;
103538fd1498Szrj }
103638fd1498Szrj }
103738fd1498Szrj break;
103838fd1498Szrj case BIT_XOR_EXPR:
103938fd1498Szrj case PLUS_EXPR:
104038fd1498Szrj case MINUS_EXPR:
104138fd1498Szrj if (integer_zerop (oelast->op)
104238fd1498Szrj || (FLOAT_TYPE_P (type)
104338fd1498Szrj && (opcode == PLUS_EXPR || opcode == MINUS_EXPR)
104438fd1498Szrj && fold_real_zero_addition_p (type, oelast->op,
104538fd1498Szrj opcode == MINUS_EXPR)))
104638fd1498Szrj {
104738fd1498Szrj if (ops->length () != 1)
104838fd1498Szrj {
104938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
105038fd1498Szrj fprintf (dump_file, "Found [|^+] 0, removing\n");
105138fd1498Szrj ops->pop ();
105238fd1498Szrj reassociate_stats.ops_eliminated++;
105338fd1498Szrj return;
105438fd1498Szrj }
105538fd1498Szrj }
105638fd1498Szrj break;
105738fd1498Szrj default:
105838fd1498Szrj break;
105938fd1498Szrj }
106038fd1498Szrj }
106138fd1498Szrj }
106238fd1498Szrj
106338fd1498Szrj
106438fd1498Szrj static void linearize_expr_tree (vec<operand_entry *> *, gimple *,
106538fd1498Szrj bool, bool);
106638fd1498Szrj
106738fd1498Szrj /* Structure for tracking and counting operands. */
106838fd1498Szrj struct oecount {
106938fd1498Szrj unsigned int cnt;
107038fd1498Szrj unsigned int id;
107138fd1498Szrj enum tree_code oecode;
107238fd1498Szrj tree op;
107338fd1498Szrj };
107438fd1498Szrj
107538fd1498Szrj
107638fd1498Szrj /* The heap for the oecount hashtable and the sorted list of operands. */
107738fd1498Szrj static vec<oecount> cvec;
107838fd1498Szrj
107938fd1498Szrj
108038fd1498Szrj /* Oecount hashtable helpers. */
108138fd1498Szrj
108238fd1498Szrj struct oecount_hasher : int_hash <int, 0, 1>
108338fd1498Szrj {
108438fd1498Szrj static inline hashval_t hash (int);
108538fd1498Szrj static inline bool equal (int, int);
108638fd1498Szrj };
108738fd1498Szrj
108838fd1498Szrj /* Hash function for oecount. */
108938fd1498Szrj
109038fd1498Szrj inline hashval_t
hash(int p)109138fd1498Szrj oecount_hasher::hash (int p)
109238fd1498Szrj {
109338fd1498Szrj const oecount *c = &cvec[p - 42];
109438fd1498Szrj return htab_hash_pointer (c->op) ^ (hashval_t)c->oecode;
109538fd1498Szrj }
109638fd1498Szrj
109738fd1498Szrj /* Comparison function for oecount. */
109838fd1498Szrj
109938fd1498Szrj inline bool
equal(int p1,int p2)110038fd1498Szrj oecount_hasher::equal (int p1, int p2)
110138fd1498Szrj {
110238fd1498Szrj const oecount *c1 = &cvec[p1 - 42];
110338fd1498Szrj const oecount *c2 = &cvec[p2 - 42];
110438fd1498Szrj return c1->oecode == c2->oecode && c1->op == c2->op;
110538fd1498Szrj }
110638fd1498Szrj
110738fd1498Szrj /* Comparison function for qsort sorting oecount elements by count. */
110838fd1498Szrj
110938fd1498Szrj static int
oecount_cmp(const void * p1,const void * p2)111038fd1498Szrj oecount_cmp (const void *p1, const void *p2)
111138fd1498Szrj {
111238fd1498Szrj const oecount *c1 = (const oecount *)p1;
111338fd1498Szrj const oecount *c2 = (const oecount *)p2;
111438fd1498Szrj if (c1->cnt != c2->cnt)
111538fd1498Szrj return c1->cnt > c2->cnt ? 1 : -1;
111638fd1498Szrj else
111738fd1498Szrj /* If counts are identical, use unique IDs to stabilize qsort. */
111838fd1498Szrj return c1->id > c2->id ? 1 : -1;
111938fd1498Szrj }
112038fd1498Szrj
112138fd1498Szrj /* Return TRUE iff STMT represents a builtin call that raises OP
112238fd1498Szrj to some exponent. */
112338fd1498Szrj
112438fd1498Szrj static bool
stmt_is_power_of_op(gimple * stmt,tree op)112538fd1498Szrj stmt_is_power_of_op (gimple *stmt, tree op)
112638fd1498Szrj {
112738fd1498Szrj if (!is_gimple_call (stmt))
112838fd1498Szrj return false;
112938fd1498Szrj
113038fd1498Szrj switch (gimple_call_combined_fn (stmt))
113138fd1498Szrj {
113238fd1498Szrj CASE_CFN_POW:
113338fd1498Szrj CASE_CFN_POWI:
113438fd1498Szrj return (operand_equal_p (gimple_call_arg (stmt, 0), op, 0));
113538fd1498Szrj
113638fd1498Szrj default:
113738fd1498Szrj return false;
113838fd1498Szrj }
113938fd1498Szrj }
114038fd1498Szrj
114138fd1498Szrj /* Given STMT which is a __builtin_pow* call, decrement its exponent
114238fd1498Szrj in place and return the result. Assumes that stmt_is_power_of_op
114338fd1498Szrj was previously called for STMT and returned TRUE. */
114438fd1498Szrj
114538fd1498Szrj static HOST_WIDE_INT
decrement_power(gimple * stmt)114638fd1498Szrj decrement_power (gimple *stmt)
114738fd1498Szrj {
114838fd1498Szrj REAL_VALUE_TYPE c, cint;
114938fd1498Szrj HOST_WIDE_INT power;
115038fd1498Szrj tree arg1;
115138fd1498Szrj
115238fd1498Szrj switch (gimple_call_combined_fn (stmt))
115338fd1498Szrj {
115438fd1498Szrj CASE_CFN_POW:
115538fd1498Szrj arg1 = gimple_call_arg (stmt, 1);
115638fd1498Szrj c = TREE_REAL_CST (arg1);
115738fd1498Szrj power = real_to_integer (&c) - 1;
115838fd1498Szrj real_from_integer (&cint, VOIDmode, power, SIGNED);
115938fd1498Szrj gimple_call_set_arg (stmt, 1, build_real (TREE_TYPE (arg1), cint));
116038fd1498Szrj return power;
116138fd1498Szrj
116238fd1498Szrj CASE_CFN_POWI:
116338fd1498Szrj arg1 = gimple_call_arg (stmt, 1);
116438fd1498Szrj power = TREE_INT_CST_LOW (arg1) - 1;
116538fd1498Szrj gimple_call_set_arg (stmt, 1, build_int_cst (TREE_TYPE (arg1), power));
116638fd1498Szrj return power;
116738fd1498Szrj
116838fd1498Szrj default:
116938fd1498Szrj gcc_unreachable ();
117038fd1498Szrj }
117138fd1498Szrj }
117238fd1498Szrj
117338fd1498Szrj /* Replace SSA defined by STMT and replace all its uses with new
117438fd1498Szrj SSA. Also return the new SSA. */
117538fd1498Szrj
117638fd1498Szrj static tree
make_new_ssa_for_def(gimple * stmt,enum tree_code opcode,tree op)117738fd1498Szrj make_new_ssa_for_def (gimple *stmt, enum tree_code opcode, tree op)
117838fd1498Szrj {
117938fd1498Szrj gimple *use_stmt;
118038fd1498Szrj use_operand_p use;
118138fd1498Szrj imm_use_iterator iter;
118238fd1498Szrj tree new_lhs, new_debug_lhs = NULL_TREE;
118338fd1498Szrj tree lhs = gimple_get_lhs (stmt);
118438fd1498Szrj
118538fd1498Szrj new_lhs = make_ssa_name (TREE_TYPE (lhs));
118638fd1498Szrj gimple_set_lhs (stmt, new_lhs);
118738fd1498Szrj
118838fd1498Szrj /* Also need to update GIMPLE_DEBUGs. */
118938fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
119038fd1498Szrj {
119138fd1498Szrj tree repl = new_lhs;
119238fd1498Szrj if (is_gimple_debug (use_stmt))
119338fd1498Szrj {
119438fd1498Szrj if (new_debug_lhs == NULL_TREE)
119538fd1498Szrj {
119638fd1498Szrj new_debug_lhs = make_node (DEBUG_EXPR_DECL);
119738fd1498Szrj gdebug *def_temp
119838fd1498Szrj = gimple_build_debug_bind (new_debug_lhs,
119938fd1498Szrj build2 (opcode, TREE_TYPE (lhs),
120038fd1498Szrj new_lhs, op),
120138fd1498Szrj stmt);
120238fd1498Szrj DECL_ARTIFICIAL (new_debug_lhs) = 1;
120338fd1498Szrj TREE_TYPE (new_debug_lhs) = TREE_TYPE (lhs);
120438fd1498Szrj SET_DECL_MODE (new_debug_lhs, TYPE_MODE (TREE_TYPE (lhs)));
120538fd1498Szrj gimple_set_uid (def_temp, gimple_uid (stmt));
120638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
120738fd1498Szrj gsi_insert_after (&gsi, def_temp, GSI_SAME_STMT);
120838fd1498Szrj }
120938fd1498Szrj repl = new_debug_lhs;
121038fd1498Szrj }
121138fd1498Szrj FOR_EACH_IMM_USE_ON_STMT (use, iter)
121238fd1498Szrj SET_USE (use, repl);
121338fd1498Szrj update_stmt (use_stmt);
121438fd1498Szrj }
121538fd1498Szrj return new_lhs;
121638fd1498Szrj }
121738fd1498Szrj
121838fd1498Szrj /* Replace all SSAs defined in STMTS_TO_FIX and replace its
121938fd1498Szrj uses with new SSAs. Also do this for the stmt that defines DEF
122038fd1498Szrj if *DEF is not OP. */
122138fd1498Szrj
122238fd1498Szrj static void
make_new_ssa_for_all_defs(tree * def,enum tree_code opcode,tree op,vec<gimple * > & stmts_to_fix)122338fd1498Szrj make_new_ssa_for_all_defs (tree *def, enum tree_code opcode, tree op,
122438fd1498Szrj vec<gimple *> &stmts_to_fix)
122538fd1498Szrj {
122638fd1498Szrj unsigned i;
122738fd1498Szrj gimple *stmt;
122838fd1498Szrj
122938fd1498Szrj if (*def != op
123038fd1498Szrj && TREE_CODE (*def) == SSA_NAME
123138fd1498Szrj && (stmt = SSA_NAME_DEF_STMT (*def))
123238fd1498Szrj && gimple_code (stmt) != GIMPLE_NOP)
123338fd1498Szrj *def = make_new_ssa_for_def (stmt, opcode, op);
123438fd1498Szrj
123538fd1498Szrj FOR_EACH_VEC_ELT (stmts_to_fix, i, stmt)
123638fd1498Szrj make_new_ssa_for_def (stmt, opcode, op);
123738fd1498Szrj }
123838fd1498Szrj
123938fd1498Szrj /* Find the single immediate use of STMT's LHS, and replace it
124038fd1498Szrj with OP. Remove STMT. If STMT's LHS is the same as *DEF,
124138fd1498Szrj replace *DEF with OP as well. */
124238fd1498Szrj
124338fd1498Szrj static void
propagate_op_to_single_use(tree op,gimple * stmt,tree * def)124438fd1498Szrj propagate_op_to_single_use (tree op, gimple *stmt, tree *def)
124538fd1498Szrj {
124638fd1498Szrj tree lhs;
124738fd1498Szrj gimple *use_stmt;
124838fd1498Szrj use_operand_p use;
124938fd1498Szrj gimple_stmt_iterator gsi;
125038fd1498Szrj
125138fd1498Szrj if (is_gimple_call (stmt))
125238fd1498Szrj lhs = gimple_call_lhs (stmt);
125338fd1498Szrj else
125438fd1498Szrj lhs = gimple_assign_lhs (stmt);
125538fd1498Szrj
125638fd1498Szrj gcc_assert (has_single_use (lhs));
125738fd1498Szrj single_imm_use (lhs, &use, &use_stmt);
125838fd1498Szrj if (lhs == *def)
125938fd1498Szrj *def = op;
126038fd1498Szrj SET_USE (use, op);
126138fd1498Szrj if (TREE_CODE (op) != SSA_NAME)
126238fd1498Szrj update_stmt (use_stmt);
126338fd1498Szrj gsi = gsi_for_stmt (stmt);
126438fd1498Szrj unlink_stmt_vdef (stmt);
126538fd1498Szrj reassoc_remove_stmt (&gsi);
126638fd1498Szrj release_defs (stmt);
126738fd1498Szrj }
126838fd1498Szrj
126938fd1498Szrj /* Walks the linear chain with result *DEF searching for an operation
127038fd1498Szrj with operand OP and code OPCODE removing that from the chain. *DEF
127138fd1498Szrj is updated if there is only one operand but no operation left. */
127238fd1498Szrj
127338fd1498Szrj static void
zero_one_operation(tree * def,enum tree_code opcode,tree op)127438fd1498Szrj zero_one_operation (tree *def, enum tree_code opcode, tree op)
127538fd1498Szrj {
127638fd1498Szrj tree orig_def = *def;
127738fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (*def);
127838fd1498Szrj /* PR72835 - Record the stmt chain that has to be updated such that
127938fd1498Szrj we dont use the same LHS when the values computed are different. */
128038fd1498Szrj auto_vec<gimple *, 64> stmts_to_fix;
128138fd1498Szrj
128238fd1498Szrj do
128338fd1498Szrj {
128438fd1498Szrj tree name;
128538fd1498Szrj
128638fd1498Szrj if (opcode == MULT_EXPR)
128738fd1498Szrj {
128838fd1498Szrj if (stmt_is_power_of_op (stmt, op))
128938fd1498Szrj {
129038fd1498Szrj if (decrement_power (stmt) == 1)
129138fd1498Szrj {
129238fd1498Szrj if (stmts_to_fix.length () > 0)
129338fd1498Szrj stmts_to_fix.pop ();
129438fd1498Szrj propagate_op_to_single_use (op, stmt, def);
129538fd1498Szrj }
129638fd1498Szrj break;
129738fd1498Szrj }
129838fd1498Szrj else if (gimple_assign_rhs_code (stmt) == NEGATE_EXPR)
129938fd1498Szrj {
130038fd1498Szrj if (gimple_assign_rhs1 (stmt) == op)
130138fd1498Szrj {
130238fd1498Szrj tree cst = build_minus_one_cst (TREE_TYPE (op));
130338fd1498Szrj if (stmts_to_fix.length () > 0)
130438fd1498Szrj stmts_to_fix.pop ();
130538fd1498Szrj propagate_op_to_single_use (cst, stmt, def);
130638fd1498Szrj break;
130738fd1498Szrj }
130838fd1498Szrj else if (integer_minus_onep (op)
130938fd1498Szrj || real_minus_onep (op))
131038fd1498Szrj {
131138fd1498Szrj gimple_assign_set_rhs_code
131238fd1498Szrj (stmt, TREE_CODE (gimple_assign_rhs1 (stmt)));
131338fd1498Szrj break;
131438fd1498Szrj }
131538fd1498Szrj }
131638fd1498Szrj }
131738fd1498Szrj
131838fd1498Szrj name = gimple_assign_rhs1 (stmt);
131938fd1498Szrj
132038fd1498Szrj /* If this is the operation we look for and one of the operands
132138fd1498Szrj is ours simply propagate the other operand into the stmts
132238fd1498Szrj single use. */
132338fd1498Szrj if (gimple_assign_rhs_code (stmt) == opcode
132438fd1498Szrj && (name == op
132538fd1498Szrj || gimple_assign_rhs2 (stmt) == op))
132638fd1498Szrj {
132738fd1498Szrj if (name == op)
132838fd1498Szrj name = gimple_assign_rhs2 (stmt);
132938fd1498Szrj if (stmts_to_fix.length () > 0)
133038fd1498Szrj stmts_to_fix.pop ();
133138fd1498Szrj propagate_op_to_single_use (name, stmt, def);
133238fd1498Szrj break;
133338fd1498Szrj }
133438fd1498Szrj
133538fd1498Szrj /* We might have a multiply of two __builtin_pow* calls, and
133638fd1498Szrj the operand might be hiding in the rightmost one. Likewise
133738fd1498Szrj this can happen for a negate. */
133838fd1498Szrj if (opcode == MULT_EXPR
133938fd1498Szrj && gimple_assign_rhs_code (stmt) == opcode
134038fd1498Szrj && TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME
134138fd1498Szrj && has_single_use (gimple_assign_rhs2 (stmt)))
134238fd1498Szrj {
134338fd1498Szrj gimple *stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
134438fd1498Szrj if (stmt_is_power_of_op (stmt2, op))
134538fd1498Szrj {
134638fd1498Szrj if (decrement_power (stmt2) == 1)
134738fd1498Szrj propagate_op_to_single_use (op, stmt2, def);
134838fd1498Szrj else
134938fd1498Szrj stmts_to_fix.safe_push (stmt2);
135038fd1498Szrj break;
135138fd1498Szrj }
135238fd1498Szrj else if (is_gimple_assign (stmt2)
135338fd1498Szrj && gimple_assign_rhs_code (stmt2) == NEGATE_EXPR)
135438fd1498Szrj {
135538fd1498Szrj if (gimple_assign_rhs1 (stmt2) == op)
135638fd1498Szrj {
135738fd1498Szrj tree cst = build_minus_one_cst (TREE_TYPE (op));
135838fd1498Szrj propagate_op_to_single_use (cst, stmt2, def);
135938fd1498Szrj break;
136038fd1498Szrj }
136138fd1498Szrj else if (integer_minus_onep (op)
136238fd1498Szrj || real_minus_onep (op))
136338fd1498Szrj {
136438fd1498Szrj stmts_to_fix.safe_push (stmt2);
136538fd1498Szrj gimple_assign_set_rhs_code
136638fd1498Szrj (stmt2, TREE_CODE (gimple_assign_rhs1 (stmt2)));
136738fd1498Szrj break;
136838fd1498Szrj }
136938fd1498Szrj }
137038fd1498Szrj }
137138fd1498Szrj
137238fd1498Szrj /* Continue walking the chain. */
137338fd1498Szrj gcc_assert (name != op
137438fd1498Szrj && TREE_CODE (name) == SSA_NAME);
137538fd1498Szrj stmt = SSA_NAME_DEF_STMT (name);
137638fd1498Szrj stmts_to_fix.safe_push (stmt);
137738fd1498Szrj }
137838fd1498Szrj while (1);
137938fd1498Szrj
138038fd1498Szrj if (stmts_to_fix.length () > 0 || *def == orig_def)
138138fd1498Szrj make_new_ssa_for_all_defs (def, opcode, op, stmts_to_fix);
138238fd1498Szrj }
138338fd1498Szrj
138438fd1498Szrj /* Returns true if statement S1 dominates statement S2. Like
138538fd1498Szrj stmt_dominates_stmt_p, but uses stmt UIDs to optimize. */
138638fd1498Szrj
138738fd1498Szrj static bool
reassoc_stmt_dominates_stmt_p(gimple * s1,gimple * s2)138838fd1498Szrj reassoc_stmt_dominates_stmt_p (gimple *s1, gimple *s2)
138938fd1498Szrj {
139038fd1498Szrj basic_block bb1 = gimple_bb (s1), bb2 = gimple_bb (s2);
139138fd1498Szrj
139238fd1498Szrj /* If bb1 is NULL, it should be a GIMPLE_NOP def stmt of an (D)
139338fd1498Szrj SSA_NAME. Assume it lives at the beginning of function and
139438fd1498Szrj thus dominates everything. */
139538fd1498Szrj if (!bb1 || s1 == s2)
139638fd1498Szrj return true;
139738fd1498Szrj
139838fd1498Szrj /* If bb2 is NULL, it doesn't dominate any stmt with a bb. */
139938fd1498Szrj if (!bb2)
140038fd1498Szrj return false;
140138fd1498Szrj
140238fd1498Szrj if (bb1 == bb2)
140338fd1498Szrj {
140438fd1498Szrj /* PHIs in the same basic block are assumed to be
140538fd1498Szrj executed all in parallel, if only one stmt is a PHI,
140638fd1498Szrj it dominates the other stmt in the same basic block. */
140738fd1498Szrj if (gimple_code (s1) == GIMPLE_PHI)
140838fd1498Szrj return true;
140938fd1498Szrj
141038fd1498Szrj if (gimple_code (s2) == GIMPLE_PHI)
141138fd1498Szrj return false;
141238fd1498Szrj
141338fd1498Szrj gcc_assert (gimple_uid (s1) && gimple_uid (s2));
141438fd1498Szrj
141538fd1498Szrj if (gimple_uid (s1) < gimple_uid (s2))
141638fd1498Szrj return true;
141738fd1498Szrj
141838fd1498Szrj if (gimple_uid (s1) > gimple_uid (s2))
141938fd1498Szrj return false;
142038fd1498Szrj
142138fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (s1);
142238fd1498Szrj unsigned int uid = gimple_uid (s1);
142338fd1498Szrj for (gsi_next (&gsi); !gsi_end_p (gsi); gsi_next (&gsi))
142438fd1498Szrj {
142538fd1498Szrj gimple *s = gsi_stmt (gsi);
142638fd1498Szrj if (gimple_uid (s) != uid)
142738fd1498Szrj break;
142838fd1498Szrj if (s == s2)
142938fd1498Szrj return true;
143038fd1498Szrj }
143138fd1498Szrj
143238fd1498Szrj return false;
143338fd1498Szrj }
143438fd1498Szrj
143538fd1498Szrj return dominated_by_p (CDI_DOMINATORS, bb2, bb1);
143638fd1498Szrj }
143738fd1498Szrj
143838fd1498Szrj /* Insert STMT after INSERT_POINT. */
143938fd1498Szrj
144038fd1498Szrj static void
insert_stmt_after(gimple * stmt,gimple * insert_point)144138fd1498Szrj insert_stmt_after (gimple *stmt, gimple *insert_point)
144238fd1498Szrj {
144338fd1498Szrj gimple_stmt_iterator gsi;
144438fd1498Szrj basic_block bb;
144538fd1498Szrj
144638fd1498Szrj if (gimple_code (insert_point) == GIMPLE_PHI)
144738fd1498Szrj bb = gimple_bb (insert_point);
144838fd1498Szrj else if (!stmt_ends_bb_p (insert_point))
144938fd1498Szrj {
145038fd1498Szrj gsi = gsi_for_stmt (insert_point);
145138fd1498Szrj gimple_set_uid (stmt, gimple_uid (insert_point));
145238fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
145338fd1498Szrj return;
145438fd1498Szrj }
145538fd1498Szrj else
145638fd1498Szrj /* We assume INSERT_POINT is a SSA_NAME_DEF_STMT of some SSA_NAME,
145738fd1498Szrj thus if it must end a basic block, it should be a call that can
145838fd1498Szrj throw, or some assignment that can throw. If it throws, the LHS
145938fd1498Szrj of it will not be initialized though, so only valid places using
146038fd1498Szrj the SSA_NAME should be dominated by the fallthru edge. */
146138fd1498Szrj bb = find_fallthru_edge (gimple_bb (insert_point)->succs)->dest;
146238fd1498Szrj gsi = gsi_after_labels (bb);
146338fd1498Szrj if (gsi_end_p (gsi))
146438fd1498Szrj {
146538fd1498Szrj gimple_stmt_iterator gsi2 = gsi_last_bb (bb);
146638fd1498Szrj gimple_set_uid (stmt,
146738fd1498Szrj gsi_end_p (gsi2) ? 1 : gimple_uid (gsi_stmt (gsi2)));
146838fd1498Szrj }
146938fd1498Szrj else
147038fd1498Szrj gimple_set_uid (stmt, gimple_uid (gsi_stmt (gsi)));
147138fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
147238fd1498Szrj }
147338fd1498Szrj
147438fd1498Szrj /* Builds one statement performing OP1 OPCODE OP2 using TMPVAR for
147538fd1498Szrj the result. Places the statement after the definition of either
147638fd1498Szrj OP1 or OP2. Returns the new statement. */
147738fd1498Szrj
147838fd1498Szrj static gimple *
build_and_add_sum(tree type,tree op1,tree op2,enum tree_code opcode)147938fd1498Szrj build_and_add_sum (tree type, tree op1, tree op2, enum tree_code opcode)
148038fd1498Szrj {
148138fd1498Szrj gimple *op1def = NULL, *op2def = NULL;
148238fd1498Szrj gimple_stmt_iterator gsi;
148338fd1498Szrj tree op;
148438fd1498Szrj gassign *sum;
148538fd1498Szrj
148638fd1498Szrj /* Create the addition statement. */
148738fd1498Szrj op = make_ssa_name (type);
148838fd1498Szrj sum = gimple_build_assign (op, opcode, op1, op2);
148938fd1498Szrj
149038fd1498Szrj /* Find an insertion place and insert. */
149138fd1498Szrj if (TREE_CODE (op1) == SSA_NAME)
149238fd1498Szrj op1def = SSA_NAME_DEF_STMT (op1);
149338fd1498Szrj if (TREE_CODE (op2) == SSA_NAME)
149438fd1498Szrj op2def = SSA_NAME_DEF_STMT (op2);
149538fd1498Szrj if ((!op1def || gimple_nop_p (op1def))
149638fd1498Szrj && (!op2def || gimple_nop_p (op2def)))
149738fd1498Szrj {
149838fd1498Szrj gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
149938fd1498Szrj if (gsi_end_p (gsi))
150038fd1498Szrj {
150138fd1498Szrj gimple_stmt_iterator gsi2
150238fd1498Szrj = gsi_last_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
150338fd1498Szrj gimple_set_uid (sum,
150438fd1498Szrj gsi_end_p (gsi2) ? 1 : gimple_uid (gsi_stmt (gsi2)));
150538fd1498Szrj }
150638fd1498Szrj else
150738fd1498Szrj gimple_set_uid (sum, gimple_uid (gsi_stmt (gsi)));
150838fd1498Szrj gsi_insert_before (&gsi, sum, GSI_NEW_STMT);
150938fd1498Szrj }
151038fd1498Szrj else
151138fd1498Szrj {
151238fd1498Szrj gimple *insert_point;
151338fd1498Szrj if ((!op1def || gimple_nop_p (op1def))
151438fd1498Szrj || (op2def && !gimple_nop_p (op2def)
151538fd1498Szrj && reassoc_stmt_dominates_stmt_p (op1def, op2def)))
151638fd1498Szrj insert_point = op2def;
151738fd1498Szrj else
151838fd1498Szrj insert_point = op1def;
151938fd1498Szrj insert_stmt_after (sum, insert_point);
152038fd1498Szrj }
152138fd1498Szrj update_stmt (sum);
152238fd1498Szrj
152338fd1498Szrj return sum;
152438fd1498Szrj }
152538fd1498Szrj
152638fd1498Szrj /* Perform un-distribution of divisions and multiplications.
152738fd1498Szrj A * X + B * X is transformed into (A + B) * X and A / X + B / X
152838fd1498Szrj to (A + B) / X for real X.
152938fd1498Szrj
153038fd1498Szrj The algorithm is organized as follows.
153138fd1498Szrj
153238fd1498Szrj - First we walk the addition chain *OPS looking for summands that
153338fd1498Szrj are defined by a multiplication or a real division. This results
153438fd1498Szrj in the candidates bitmap with relevant indices into *OPS.
153538fd1498Szrj
153638fd1498Szrj - Second we build the chains of multiplications or divisions for
153738fd1498Szrj these candidates, counting the number of occurrences of (operand, code)
153838fd1498Szrj pairs in all of the candidates chains.
153938fd1498Szrj
154038fd1498Szrj - Third we sort the (operand, code) pairs by number of occurrence and
154138fd1498Szrj process them starting with the pair with the most uses.
154238fd1498Szrj
154338fd1498Szrj * For each such pair we walk the candidates again to build a
154438fd1498Szrj second candidate bitmap noting all multiplication/division chains
154538fd1498Szrj that have at least one occurrence of (operand, code).
154638fd1498Szrj
154738fd1498Szrj * We build an alternate addition chain only covering these
154838fd1498Szrj candidates with one (operand, code) operation removed from their
154938fd1498Szrj multiplication/division chain.
155038fd1498Szrj
155138fd1498Szrj * The first candidate gets replaced by the alternate addition chain
155238fd1498Szrj multiplied/divided by the operand.
155338fd1498Szrj
155438fd1498Szrj * All candidate chains get disabled for further processing and
155538fd1498Szrj processing of (operand, code) pairs continues.
155638fd1498Szrj
155738fd1498Szrj The alternate addition chains built are re-processed by the main
155838fd1498Szrj reassociation algorithm which allows optimizing a * x * y + b * y * x
155938fd1498Szrj to (a + b ) * x * y in one invocation of the reassociation pass. */
156038fd1498Szrj
156138fd1498Szrj static bool
undistribute_ops_list(enum tree_code opcode,vec<operand_entry * > * ops,struct loop * loop)156238fd1498Szrj undistribute_ops_list (enum tree_code opcode,
156338fd1498Szrj vec<operand_entry *> *ops, struct loop *loop)
156438fd1498Szrj {
156538fd1498Szrj unsigned int length = ops->length ();
156638fd1498Szrj operand_entry *oe1;
156738fd1498Szrj unsigned i, j;
156838fd1498Szrj unsigned nr_candidates, nr_candidates2;
156938fd1498Szrj sbitmap_iterator sbi0;
157038fd1498Szrj vec<operand_entry *> *subops;
157138fd1498Szrj bool changed = false;
157238fd1498Szrj unsigned int next_oecount_id = 0;
157338fd1498Szrj
157438fd1498Szrj if (length <= 1
157538fd1498Szrj || opcode != PLUS_EXPR)
157638fd1498Szrj return false;
157738fd1498Szrj
157838fd1498Szrj /* Build a list of candidates to process. */
157938fd1498Szrj auto_sbitmap candidates (length);
158038fd1498Szrj bitmap_clear (candidates);
158138fd1498Szrj nr_candidates = 0;
158238fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe1)
158338fd1498Szrj {
158438fd1498Szrj enum tree_code dcode;
158538fd1498Szrj gimple *oe1def;
158638fd1498Szrj
158738fd1498Szrj if (TREE_CODE (oe1->op) != SSA_NAME)
158838fd1498Szrj continue;
158938fd1498Szrj oe1def = SSA_NAME_DEF_STMT (oe1->op);
159038fd1498Szrj if (!is_gimple_assign (oe1def))
159138fd1498Szrj continue;
159238fd1498Szrj dcode = gimple_assign_rhs_code (oe1def);
159338fd1498Szrj if ((dcode != MULT_EXPR
159438fd1498Szrj && dcode != RDIV_EXPR)
159538fd1498Szrj || !is_reassociable_op (oe1def, dcode, loop))
159638fd1498Szrj continue;
159738fd1498Szrj
159838fd1498Szrj bitmap_set_bit (candidates, i);
159938fd1498Szrj nr_candidates++;
160038fd1498Szrj }
160138fd1498Szrj
160238fd1498Szrj if (nr_candidates < 2)
160338fd1498Szrj return false;
160438fd1498Szrj
160538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
160638fd1498Szrj {
160738fd1498Szrj fprintf (dump_file, "searching for un-distribute opportunities ");
160838fd1498Szrj print_generic_expr (dump_file,
160938fd1498Szrj (*ops)[bitmap_first_set_bit (candidates)]->op, 0);
161038fd1498Szrj fprintf (dump_file, " %d\n", nr_candidates);
161138fd1498Szrj }
161238fd1498Szrj
161338fd1498Szrj /* Build linearized sub-operand lists and the counting table. */
161438fd1498Szrj cvec.create (0);
161538fd1498Szrj
161638fd1498Szrj hash_table<oecount_hasher> ctable (15);
161738fd1498Szrj
161838fd1498Szrj /* ??? Macro arguments cannot have multi-argument template types in
161938fd1498Szrj them. This typedef is needed to workaround that limitation. */
162038fd1498Szrj typedef vec<operand_entry *> vec_operand_entry_t_heap;
162138fd1498Szrj subops = XCNEWVEC (vec_operand_entry_t_heap, ops->length ());
162238fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (candidates, 0, i, sbi0)
162338fd1498Szrj {
162438fd1498Szrj gimple *oedef;
162538fd1498Szrj enum tree_code oecode;
162638fd1498Szrj unsigned j;
162738fd1498Szrj
162838fd1498Szrj oedef = SSA_NAME_DEF_STMT ((*ops)[i]->op);
162938fd1498Szrj oecode = gimple_assign_rhs_code (oedef);
163038fd1498Szrj linearize_expr_tree (&subops[i], oedef,
163138fd1498Szrj associative_tree_code (oecode), false);
163238fd1498Szrj
163338fd1498Szrj FOR_EACH_VEC_ELT (subops[i], j, oe1)
163438fd1498Szrj {
163538fd1498Szrj oecount c;
163638fd1498Szrj int *slot;
163738fd1498Szrj int idx;
163838fd1498Szrj c.oecode = oecode;
163938fd1498Szrj c.cnt = 1;
164038fd1498Szrj c.id = next_oecount_id++;
164138fd1498Szrj c.op = oe1->op;
164238fd1498Szrj cvec.safe_push (c);
164338fd1498Szrj idx = cvec.length () + 41;
164438fd1498Szrj slot = ctable.find_slot (idx, INSERT);
164538fd1498Szrj if (!*slot)
164638fd1498Szrj {
164738fd1498Szrj *slot = idx;
164838fd1498Szrj }
164938fd1498Szrj else
165038fd1498Szrj {
165138fd1498Szrj cvec.pop ();
165238fd1498Szrj cvec[*slot - 42].cnt++;
165338fd1498Szrj }
165438fd1498Szrj }
165538fd1498Szrj }
165638fd1498Szrj
165738fd1498Szrj /* Sort the counting table. */
165838fd1498Szrj cvec.qsort (oecount_cmp);
165938fd1498Szrj
166038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
166138fd1498Szrj {
166238fd1498Szrj oecount *c;
166338fd1498Szrj fprintf (dump_file, "Candidates:\n");
166438fd1498Szrj FOR_EACH_VEC_ELT (cvec, j, c)
166538fd1498Szrj {
166638fd1498Szrj fprintf (dump_file, " %u %s: ", c->cnt,
166738fd1498Szrj c->oecode == MULT_EXPR
166838fd1498Szrj ? "*" : c->oecode == RDIV_EXPR ? "/" : "?");
166938fd1498Szrj print_generic_expr (dump_file, c->op);
167038fd1498Szrj fprintf (dump_file, "\n");
167138fd1498Szrj }
167238fd1498Szrj }
167338fd1498Szrj
167438fd1498Szrj /* Process the (operand, code) pairs in order of most occurrence. */
167538fd1498Szrj auto_sbitmap candidates2 (length);
167638fd1498Szrj while (!cvec.is_empty ())
167738fd1498Szrj {
167838fd1498Szrj oecount *c = &cvec.last ();
167938fd1498Szrj if (c->cnt < 2)
168038fd1498Szrj break;
168138fd1498Szrj
168238fd1498Szrj /* Now collect the operands in the outer chain that contain
168338fd1498Szrj the common operand in their inner chain. */
168438fd1498Szrj bitmap_clear (candidates2);
168538fd1498Szrj nr_candidates2 = 0;
168638fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (candidates, 0, i, sbi0)
168738fd1498Szrj {
168838fd1498Szrj gimple *oedef;
168938fd1498Szrj enum tree_code oecode;
169038fd1498Szrj unsigned j;
169138fd1498Szrj tree op = (*ops)[i]->op;
169238fd1498Szrj
169338fd1498Szrj /* If we undistributed in this chain already this may be
169438fd1498Szrj a constant. */
169538fd1498Szrj if (TREE_CODE (op) != SSA_NAME)
169638fd1498Szrj continue;
169738fd1498Szrj
169838fd1498Szrj oedef = SSA_NAME_DEF_STMT (op);
169938fd1498Szrj oecode = gimple_assign_rhs_code (oedef);
170038fd1498Szrj if (oecode != c->oecode)
170138fd1498Szrj continue;
170238fd1498Szrj
170338fd1498Szrj FOR_EACH_VEC_ELT (subops[i], j, oe1)
170438fd1498Szrj {
170538fd1498Szrj if (oe1->op == c->op)
170638fd1498Szrj {
170738fd1498Szrj bitmap_set_bit (candidates2, i);
170838fd1498Szrj ++nr_candidates2;
170938fd1498Szrj break;
171038fd1498Szrj }
171138fd1498Szrj }
171238fd1498Szrj }
171338fd1498Szrj
171438fd1498Szrj if (nr_candidates2 >= 2)
171538fd1498Szrj {
171638fd1498Szrj operand_entry *oe1, *oe2;
171738fd1498Szrj gimple *prod;
171838fd1498Szrj int first = bitmap_first_set_bit (candidates2);
171938fd1498Szrj
172038fd1498Szrj /* Build the new addition chain. */
172138fd1498Szrj oe1 = (*ops)[first];
172238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
172338fd1498Szrj {
172438fd1498Szrj fprintf (dump_file, "Building (");
172538fd1498Szrj print_generic_expr (dump_file, oe1->op);
172638fd1498Szrj }
172738fd1498Szrj zero_one_operation (&oe1->op, c->oecode, c->op);
172838fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (candidates2, first+1, i, sbi0)
172938fd1498Szrj {
173038fd1498Szrj gimple *sum;
173138fd1498Szrj oe2 = (*ops)[i];
173238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
173338fd1498Szrj {
173438fd1498Szrj fprintf (dump_file, " + ");
173538fd1498Szrj print_generic_expr (dump_file, oe2->op);
173638fd1498Szrj }
173738fd1498Szrj zero_one_operation (&oe2->op, c->oecode, c->op);
173838fd1498Szrj sum = build_and_add_sum (TREE_TYPE (oe1->op),
173938fd1498Szrj oe1->op, oe2->op, opcode);
174038fd1498Szrj oe2->op = build_zero_cst (TREE_TYPE (oe2->op));
174138fd1498Szrj oe2->rank = 0;
174238fd1498Szrj oe1->op = gimple_get_lhs (sum);
174338fd1498Szrj }
174438fd1498Szrj
174538fd1498Szrj /* Apply the multiplication/division. */
174638fd1498Szrj prod = build_and_add_sum (TREE_TYPE (oe1->op),
174738fd1498Szrj oe1->op, c->op, c->oecode);
174838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
174938fd1498Szrj {
175038fd1498Szrj fprintf (dump_file, ") %s ", c->oecode == MULT_EXPR ? "*" : "/");
175138fd1498Szrj print_generic_expr (dump_file, c->op);
175238fd1498Szrj fprintf (dump_file, "\n");
175338fd1498Szrj }
175438fd1498Szrj
175538fd1498Szrj /* Record it in the addition chain and disable further
175638fd1498Szrj undistribution with this op. */
175738fd1498Szrj oe1->op = gimple_assign_lhs (prod);
175838fd1498Szrj oe1->rank = get_rank (oe1->op);
175938fd1498Szrj subops[first].release ();
176038fd1498Szrj
176138fd1498Szrj changed = true;
176238fd1498Szrj }
176338fd1498Szrj
176438fd1498Szrj cvec.pop ();
176538fd1498Szrj }
176638fd1498Szrj
176738fd1498Szrj for (i = 0; i < ops->length (); ++i)
176838fd1498Szrj subops[i].release ();
176938fd1498Szrj free (subops);
177038fd1498Szrj cvec.release ();
177138fd1498Szrj
177238fd1498Szrj return changed;
177338fd1498Szrj }
177438fd1498Szrj
177538fd1498Szrj /* If OPCODE is BIT_IOR_EXPR or BIT_AND_EXPR and CURR is a comparison
177638fd1498Szrj expression, examine the other OPS to see if any of them are comparisons
177738fd1498Szrj of the same values, which we may be able to combine or eliminate.
177838fd1498Szrj For example, we can rewrite (a < b) | (a == b) as (a <= b). */
177938fd1498Szrj
178038fd1498Szrj static bool
eliminate_redundant_comparison(enum tree_code opcode,vec<operand_entry * > * ops,unsigned int currindex,operand_entry * curr)178138fd1498Szrj eliminate_redundant_comparison (enum tree_code opcode,
178238fd1498Szrj vec<operand_entry *> *ops,
178338fd1498Szrj unsigned int currindex,
178438fd1498Szrj operand_entry *curr)
178538fd1498Szrj {
178638fd1498Szrj tree op1, op2;
178738fd1498Szrj enum tree_code lcode, rcode;
178838fd1498Szrj gimple *def1, *def2;
178938fd1498Szrj int i;
179038fd1498Szrj operand_entry *oe;
179138fd1498Szrj
179238fd1498Szrj if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR)
179338fd1498Szrj return false;
179438fd1498Szrj
179538fd1498Szrj /* Check that CURR is a comparison. */
179638fd1498Szrj if (TREE_CODE (curr->op) != SSA_NAME)
179738fd1498Szrj return false;
179838fd1498Szrj def1 = SSA_NAME_DEF_STMT (curr->op);
179938fd1498Szrj if (!is_gimple_assign (def1))
180038fd1498Szrj return false;
180138fd1498Szrj lcode = gimple_assign_rhs_code (def1);
180238fd1498Szrj if (TREE_CODE_CLASS (lcode) != tcc_comparison)
180338fd1498Szrj return false;
180438fd1498Szrj op1 = gimple_assign_rhs1 (def1);
180538fd1498Szrj op2 = gimple_assign_rhs2 (def1);
180638fd1498Szrj
180738fd1498Szrj /* Now look for a similar comparison in the remaining OPS. */
180838fd1498Szrj for (i = currindex + 1; ops->iterate (i, &oe); i++)
180938fd1498Szrj {
181038fd1498Szrj tree t;
181138fd1498Szrj
181238fd1498Szrj if (TREE_CODE (oe->op) != SSA_NAME)
181338fd1498Szrj continue;
181438fd1498Szrj def2 = SSA_NAME_DEF_STMT (oe->op);
181538fd1498Szrj if (!is_gimple_assign (def2))
181638fd1498Szrj continue;
181738fd1498Szrj rcode = gimple_assign_rhs_code (def2);
181838fd1498Szrj if (TREE_CODE_CLASS (rcode) != tcc_comparison)
181938fd1498Szrj continue;
182038fd1498Szrj
182138fd1498Szrj /* If we got here, we have a match. See if we can combine the
182238fd1498Szrj two comparisons. */
182338fd1498Szrj if (opcode == BIT_IOR_EXPR)
182438fd1498Szrj t = maybe_fold_or_comparisons (lcode, op1, op2,
182538fd1498Szrj rcode, gimple_assign_rhs1 (def2),
182638fd1498Szrj gimple_assign_rhs2 (def2));
182738fd1498Szrj else
182838fd1498Szrj t = maybe_fold_and_comparisons (lcode, op1, op2,
182938fd1498Szrj rcode, gimple_assign_rhs1 (def2),
183038fd1498Szrj gimple_assign_rhs2 (def2));
183138fd1498Szrj if (!t)
183238fd1498Szrj continue;
183338fd1498Szrj
183438fd1498Szrj /* maybe_fold_and_comparisons and maybe_fold_or_comparisons
183538fd1498Szrj always give us a boolean_type_node value back. If the original
183638fd1498Szrj BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type,
183738fd1498Szrj we need to convert. */
183838fd1498Szrj if (!useless_type_conversion_p (TREE_TYPE (curr->op), TREE_TYPE (t)))
183938fd1498Szrj t = fold_convert (TREE_TYPE (curr->op), t);
184038fd1498Szrj
184138fd1498Szrj if (TREE_CODE (t) != INTEGER_CST
184238fd1498Szrj && !operand_equal_p (t, curr->op, 0))
184338fd1498Szrj {
184438fd1498Szrj enum tree_code subcode;
184538fd1498Szrj tree newop1, newop2;
184638fd1498Szrj if (!COMPARISON_CLASS_P (t))
184738fd1498Szrj continue;
184838fd1498Szrj extract_ops_from_tree (t, &subcode, &newop1, &newop2);
184938fd1498Szrj STRIP_USELESS_TYPE_CONVERSION (newop1);
185038fd1498Szrj STRIP_USELESS_TYPE_CONVERSION (newop2);
185138fd1498Szrj if (!is_gimple_val (newop1) || !is_gimple_val (newop2))
185238fd1498Szrj continue;
185338fd1498Szrj }
185438fd1498Szrj
185538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
185638fd1498Szrj {
185738fd1498Szrj fprintf (dump_file, "Equivalence: ");
185838fd1498Szrj print_generic_expr (dump_file, curr->op);
185938fd1498Szrj fprintf (dump_file, " %s ", op_symbol_code (opcode));
186038fd1498Szrj print_generic_expr (dump_file, oe->op);
186138fd1498Szrj fprintf (dump_file, " -> ");
186238fd1498Szrj print_generic_expr (dump_file, t);
186338fd1498Szrj fprintf (dump_file, "\n");
186438fd1498Szrj }
186538fd1498Szrj
186638fd1498Szrj /* Now we can delete oe, as it has been subsumed by the new combined
186738fd1498Szrj expression t. */
186838fd1498Szrj ops->ordered_remove (i);
186938fd1498Szrj reassociate_stats.ops_eliminated ++;
187038fd1498Szrj
187138fd1498Szrj /* If t is the same as curr->op, we're done. Otherwise we must
187238fd1498Szrj replace curr->op with t. Special case is if we got a constant
187338fd1498Szrj back, in which case we add it to the end instead of in place of
187438fd1498Szrj the current entry. */
187538fd1498Szrj if (TREE_CODE (t) == INTEGER_CST)
187638fd1498Szrj {
187738fd1498Szrj ops->ordered_remove (currindex);
187838fd1498Szrj add_to_ops_vec (ops, t);
187938fd1498Szrj }
188038fd1498Szrj else if (!operand_equal_p (t, curr->op, 0))
188138fd1498Szrj {
188238fd1498Szrj gimple *sum;
188338fd1498Szrj enum tree_code subcode;
188438fd1498Szrj tree newop1;
188538fd1498Szrj tree newop2;
188638fd1498Szrj gcc_assert (COMPARISON_CLASS_P (t));
188738fd1498Szrj extract_ops_from_tree (t, &subcode, &newop1, &newop2);
188838fd1498Szrj STRIP_USELESS_TYPE_CONVERSION (newop1);
188938fd1498Szrj STRIP_USELESS_TYPE_CONVERSION (newop2);
189038fd1498Szrj gcc_checking_assert (is_gimple_val (newop1)
189138fd1498Szrj && is_gimple_val (newop2));
189238fd1498Szrj sum = build_and_add_sum (TREE_TYPE (t), newop1, newop2, subcode);
189338fd1498Szrj curr->op = gimple_get_lhs (sum);
189438fd1498Szrj }
189538fd1498Szrj return true;
189638fd1498Szrj }
189738fd1498Szrj
189838fd1498Szrj return false;
189938fd1498Szrj }
190038fd1498Szrj
190138fd1498Szrj
190238fd1498Szrj /* Transform repeated addition of same values into multiply with
190338fd1498Szrj constant. */
190438fd1498Szrj static bool
transform_add_to_multiply(vec<operand_entry * > * ops)190538fd1498Szrj transform_add_to_multiply (vec<operand_entry *> *ops)
190638fd1498Szrj {
190738fd1498Szrj operand_entry *oe;
190838fd1498Szrj tree op = NULL_TREE;
190938fd1498Szrj int j;
191038fd1498Szrj int i, start = -1, end = 0, count = 0;
191138fd1498Szrj auto_vec<std::pair <int, int> > indxs;
191238fd1498Szrj bool changed = false;
191338fd1498Szrj
191438fd1498Szrj if (!INTEGRAL_TYPE_P (TREE_TYPE ((*ops)[0]->op))
191538fd1498Szrj && (!SCALAR_FLOAT_TYPE_P (TREE_TYPE ((*ops)[0]->op))
191638fd1498Szrj || !flag_unsafe_math_optimizations))
191738fd1498Szrj return false;
191838fd1498Szrj
191938fd1498Szrj /* Look for repeated operands. */
192038fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe)
192138fd1498Szrj {
192238fd1498Szrj if (start == -1)
192338fd1498Szrj {
192438fd1498Szrj count = 1;
192538fd1498Szrj op = oe->op;
192638fd1498Szrj start = i;
192738fd1498Szrj }
192838fd1498Szrj else if (operand_equal_p (oe->op, op, 0))
192938fd1498Szrj {
193038fd1498Szrj count++;
193138fd1498Szrj end = i;
193238fd1498Szrj }
193338fd1498Szrj else
193438fd1498Szrj {
193538fd1498Szrj if (count > 1)
193638fd1498Szrj indxs.safe_push (std::make_pair (start, end));
193738fd1498Szrj count = 1;
193838fd1498Szrj op = oe->op;
193938fd1498Szrj start = i;
194038fd1498Szrj }
194138fd1498Szrj }
194238fd1498Szrj
194338fd1498Szrj if (count > 1)
194438fd1498Szrj indxs.safe_push (std::make_pair (start, end));
194538fd1498Szrj
194638fd1498Szrj for (j = indxs.length () - 1; j >= 0; --j)
194738fd1498Szrj {
194838fd1498Szrj /* Convert repeated operand addition to multiplication. */
194938fd1498Szrj start = indxs[j].first;
195038fd1498Szrj end = indxs[j].second;
195138fd1498Szrj op = (*ops)[start]->op;
195238fd1498Szrj count = end - start + 1;
195338fd1498Szrj for (i = end; i >= start; --i)
195438fd1498Szrj ops->unordered_remove (i);
195538fd1498Szrj tree tmp = make_ssa_name (TREE_TYPE (op));
195638fd1498Szrj tree cst = build_int_cst (integer_type_node, count);
195738fd1498Szrj gassign *mul_stmt
195838fd1498Szrj = gimple_build_assign (tmp, MULT_EXPR,
195938fd1498Szrj op, fold_convert (TREE_TYPE (op), cst));
196038fd1498Szrj gimple_set_visited (mul_stmt, true);
196138fd1498Szrj add_to_ops_vec (ops, tmp, mul_stmt);
196238fd1498Szrj changed = true;
196338fd1498Szrj }
196438fd1498Szrj
196538fd1498Szrj return changed;
196638fd1498Szrj }
196738fd1498Szrj
196838fd1498Szrj
196938fd1498Szrj /* Perform various identities and other optimizations on the list of
197038fd1498Szrj operand entries, stored in OPS. The tree code for the binary
197138fd1498Szrj operation between all the operands is OPCODE. */
197238fd1498Szrj
197338fd1498Szrj static void
optimize_ops_list(enum tree_code opcode,vec<operand_entry * > * ops)197438fd1498Szrj optimize_ops_list (enum tree_code opcode,
197538fd1498Szrj vec<operand_entry *> *ops)
197638fd1498Szrj {
197738fd1498Szrj unsigned int length = ops->length ();
197838fd1498Szrj unsigned int i;
197938fd1498Szrj operand_entry *oe;
198038fd1498Szrj operand_entry *oelast = NULL;
198138fd1498Szrj bool iterate = false;
198238fd1498Szrj
198338fd1498Szrj if (length == 1)
198438fd1498Szrj return;
198538fd1498Szrj
198638fd1498Szrj oelast = ops->last ();
198738fd1498Szrj
198838fd1498Szrj /* If the last two are constants, pop the constants off, merge them
198938fd1498Szrj and try the next two. */
199038fd1498Szrj if (oelast->rank == 0 && is_gimple_min_invariant (oelast->op))
199138fd1498Szrj {
199238fd1498Szrj operand_entry *oelm1 = (*ops)[length - 2];
199338fd1498Szrj
199438fd1498Szrj if (oelm1->rank == 0
199538fd1498Szrj && is_gimple_min_invariant (oelm1->op)
199638fd1498Szrj && useless_type_conversion_p (TREE_TYPE (oelm1->op),
199738fd1498Szrj TREE_TYPE (oelast->op)))
199838fd1498Szrj {
199938fd1498Szrj tree folded = fold_binary (opcode, TREE_TYPE (oelm1->op),
200038fd1498Szrj oelm1->op, oelast->op);
200138fd1498Szrj
200238fd1498Szrj if (folded && is_gimple_min_invariant (folded))
200338fd1498Szrj {
200438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
200538fd1498Szrj fprintf (dump_file, "Merging constants\n");
200638fd1498Szrj
200738fd1498Szrj ops->pop ();
200838fd1498Szrj ops->pop ();
200938fd1498Szrj
201038fd1498Szrj add_to_ops_vec (ops, folded);
201138fd1498Szrj reassociate_stats.constants_eliminated++;
201238fd1498Szrj
201338fd1498Szrj optimize_ops_list (opcode, ops);
201438fd1498Szrj return;
201538fd1498Szrj }
201638fd1498Szrj }
201738fd1498Szrj }
201838fd1498Szrj
201938fd1498Szrj eliminate_using_constants (opcode, ops);
202038fd1498Szrj oelast = NULL;
202138fd1498Szrj
202238fd1498Szrj for (i = 0; ops->iterate (i, &oe);)
202338fd1498Szrj {
202438fd1498Szrj bool done = false;
202538fd1498Szrj
202638fd1498Szrj if (eliminate_not_pairs (opcode, ops, i, oe))
202738fd1498Szrj return;
202838fd1498Szrj if (eliminate_duplicate_pair (opcode, ops, &done, i, oe, oelast)
202938fd1498Szrj || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe))
203038fd1498Szrj || (!done && eliminate_redundant_comparison (opcode, ops, i, oe)))
203138fd1498Szrj {
203238fd1498Szrj if (done)
203338fd1498Szrj return;
203438fd1498Szrj iterate = true;
203538fd1498Szrj oelast = NULL;
203638fd1498Szrj continue;
203738fd1498Szrj }
203838fd1498Szrj oelast = oe;
203938fd1498Szrj i++;
204038fd1498Szrj }
204138fd1498Szrj
204238fd1498Szrj length = ops->length ();
204338fd1498Szrj oelast = ops->last ();
204438fd1498Szrj
204538fd1498Szrj if (iterate)
204638fd1498Szrj optimize_ops_list (opcode, ops);
204738fd1498Szrj }
204838fd1498Szrj
204938fd1498Szrj /* The following functions are subroutines to optimize_range_tests and allow
205038fd1498Szrj it to try to change a logical combination of comparisons into a range
205138fd1498Szrj test.
205238fd1498Szrj
205338fd1498Szrj For example, both
205438fd1498Szrj X == 2 || X == 5 || X == 3 || X == 4
205538fd1498Szrj and
205638fd1498Szrj X >= 2 && X <= 5
205738fd1498Szrj are converted to
205838fd1498Szrj (unsigned) (X - 2) <= 3
205938fd1498Szrj
206038fd1498Szrj For more information see comments above fold_test_range in fold-const.c,
206138fd1498Szrj this implementation is for GIMPLE. */
206238fd1498Szrj
206338fd1498Szrj struct range_entry
206438fd1498Szrj {
206538fd1498Szrj tree exp;
206638fd1498Szrj tree low;
206738fd1498Szrj tree high;
206838fd1498Szrj bool in_p;
206938fd1498Szrj bool strict_overflow_p;
207038fd1498Szrj unsigned int idx, next;
207138fd1498Szrj };
207238fd1498Szrj
207338fd1498Szrj /* This is similar to make_range in fold-const.c, but on top of
207438fd1498Szrj GIMPLE instead of trees. If EXP is non-NULL, it should be
207538fd1498Szrj an SSA_NAME and STMT argument is ignored, otherwise STMT
207638fd1498Szrj argument should be a GIMPLE_COND. */
207738fd1498Szrj
207838fd1498Szrj static void
init_range_entry(struct range_entry * r,tree exp,gimple * stmt)207938fd1498Szrj init_range_entry (struct range_entry *r, tree exp, gimple *stmt)
208038fd1498Szrj {
208138fd1498Szrj int in_p;
208238fd1498Szrj tree low, high;
208338fd1498Szrj bool is_bool, strict_overflow_p;
208438fd1498Szrj
208538fd1498Szrj r->exp = NULL_TREE;
208638fd1498Szrj r->in_p = false;
208738fd1498Szrj r->strict_overflow_p = false;
208838fd1498Szrj r->low = NULL_TREE;
208938fd1498Szrj r->high = NULL_TREE;
209038fd1498Szrj if (exp != NULL_TREE
209138fd1498Szrj && (TREE_CODE (exp) != SSA_NAME || !INTEGRAL_TYPE_P (TREE_TYPE (exp))))
209238fd1498Szrj return;
209338fd1498Szrj
209438fd1498Szrj /* Start with simply saying "EXP != 0" and then look at the code of EXP
209538fd1498Szrj and see if we can refine the range. Some of the cases below may not
209638fd1498Szrj happen, but it doesn't seem worth worrying about this. We "continue"
209738fd1498Szrj the outer loop when we've changed something; otherwise we "break"
209838fd1498Szrj the switch, which will "break" the while. */
209938fd1498Szrj low = exp ? build_int_cst (TREE_TYPE (exp), 0) : boolean_false_node;
210038fd1498Szrj high = low;
210138fd1498Szrj in_p = 0;
210238fd1498Szrj strict_overflow_p = false;
210338fd1498Szrj is_bool = false;
210438fd1498Szrj if (exp == NULL_TREE)
210538fd1498Szrj is_bool = true;
210638fd1498Szrj else if (TYPE_PRECISION (TREE_TYPE (exp)) == 1)
210738fd1498Szrj {
210838fd1498Szrj if (TYPE_UNSIGNED (TREE_TYPE (exp)))
210938fd1498Szrj is_bool = true;
211038fd1498Szrj else
211138fd1498Szrj return;
211238fd1498Szrj }
211338fd1498Szrj else if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE)
211438fd1498Szrj is_bool = true;
211538fd1498Szrj
211638fd1498Szrj while (1)
211738fd1498Szrj {
211838fd1498Szrj enum tree_code code;
211938fd1498Szrj tree arg0, arg1, exp_type;
212038fd1498Szrj tree nexp;
212138fd1498Szrj location_t loc;
212238fd1498Szrj
212338fd1498Szrj if (exp != NULL_TREE)
212438fd1498Szrj {
212538fd1498Szrj if (TREE_CODE (exp) != SSA_NAME
212638fd1498Szrj || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
212738fd1498Szrj break;
212838fd1498Szrj
212938fd1498Szrj stmt = SSA_NAME_DEF_STMT (exp);
213038fd1498Szrj if (!is_gimple_assign (stmt))
213138fd1498Szrj break;
213238fd1498Szrj
213338fd1498Szrj code = gimple_assign_rhs_code (stmt);
213438fd1498Szrj arg0 = gimple_assign_rhs1 (stmt);
213538fd1498Szrj arg1 = gimple_assign_rhs2 (stmt);
213638fd1498Szrj exp_type = TREE_TYPE (exp);
213738fd1498Szrj }
213838fd1498Szrj else
213938fd1498Szrj {
214038fd1498Szrj code = gimple_cond_code (stmt);
214138fd1498Szrj arg0 = gimple_cond_lhs (stmt);
214238fd1498Szrj arg1 = gimple_cond_rhs (stmt);
214338fd1498Szrj exp_type = boolean_type_node;
214438fd1498Szrj }
214538fd1498Szrj
214638fd1498Szrj if (TREE_CODE (arg0) != SSA_NAME)
214738fd1498Szrj break;
214838fd1498Szrj loc = gimple_location (stmt);
214938fd1498Szrj switch (code)
215038fd1498Szrj {
215138fd1498Szrj case BIT_NOT_EXPR:
215238fd1498Szrj if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE
215338fd1498Szrj /* Ensure the range is either +[-,0], +[0,0],
215438fd1498Szrj -[-,0], -[0,0] or +[1,-], +[1,1], -[1,-] or
215538fd1498Szrj -[1,1]. If it is e.g. +[-,-] or -[-,-]
215638fd1498Szrj or similar expression of unconditional true or
215738fd1498Szrj false, it should not be negated. */
215838fd1498Szrj && ((high && integer_zerop (high))
215938fd1498Szrj || (low && integer_onep (low))))
216038fd1498Szrj {
216138fd1498Szrj in_p = !in_p;
216238fd1498Szrj exp = arg0;
216338fd1498Szrj continue;
216438fd1498Szrj }
216538fd1498Szrj break;
216638fd1498Szrj case SSA_NAME:
216738fd1498Szrj exp = arg0;
216838fd1498Szrj continue;
216938fd1498Szrj CASE_CONVERT:
217038fd1498Szrj if (is_bool)
2171*58e805e6Szrj {
2172*58e805e6Szrj if ((TYPE_PRECISION (exp_type) == 1
2173*58e805e6Szrj || TREE_CODE (exp_type) == BOOLEAN_TYPE)
2174*58e805e6Szrj && TYPE_PRECISION (TREE_TYPE (arg0)) > 1)
2175*58e805e6Szrj return;
2176*58e805e6Szrj }
2177*58e805e6Szrj else if (TYPE_PRECISION (TREE_TYPE (arg0)) == 1)
217838fd1498Szrj {
217938fd1498Szrj if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
218038fd1498Szrj is_bool = true;
218138fd1498Szrj else
218238fd1498Szrj return;
218338fd1498Szrj }
218438fd1498Szrj else if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE)
218538fd1498Szrj is_bool = true;
218638fd1498Szrj goto do_default;
218738fd1498Szrj case EQ_EXPR:
218838fd1498Szrj case NE_EXPR:
218938fd1498Szrj case LT_EXPR:
219038fd1498Szrj case LE_EXPR:
219138fd1498Szrj case GE_EXPR:
219238fd1498Szrj case GT_EXPR:
219338fd1498Szrj is_bool = true;
219438fd1498Szrj /* FALLTHRU */
219538fd1498Szrj default:
219638fd1498Szrj if (!is_bool)
219738fd1498Szrj return;
219838fd1498Szrj do_default:
219938fd1498Szrj nexp = make_range_step (loc, code, arg0, arg1, exp_type,
220038fd1498Szrj &low, &high, &in_p,
220138fd1498Szrj &strict_overflow_p);
220238fd1498Szrj if (nexp != NULL_TREE)
220338fd1498Szrj {
220438fd1498Szrj exp = nexp;
220538fd1498Szrj gcc_assert (TREE_CODE (exp) == SSA_NAME);
220638fd1498Szrj continue;
220738fd1498Szrj }
220838fd1498Szrj break;
220938fd1498Szrj }
221038fd1498Szrj break;
221138fd1498Szrj }
221238fd1498Szrj if (is_bool)
221338fd1498Szrj {
221438fd1498Szrj r->exp = exp;
221538fd1498Szrj r->in_p = in_p;
221638fd1498Szrj r->low = low;
221738fd1498Szrj r->high = high;
221838fd1498Szrj r->strict_overflow_p = strict_overflow_p;
221938fd1498Szrj }
222038fd1498Szrj }
222138fd1498Szrj
222238fd1498Szrj /* Comparison function for qsort. Sort entries
222338fd1498Szrj without SSA_NAME exp first, then with SSA_NAMEs sorted
222438fd1498Szrj by increasing SSA_NAME_VERSION, and for the same SSA_NAMEs
222538fd1498Szrj by increasing ->low and if ->low is the same, by increasing
222638fd1498Szrj ->high. ->low == NULL_TREE means minimum, ->high == NULL_TREE
222738fd1498Szrj maximum. */
222838fd1498Szrj
222938fd1498Szrj static int
range_entry_cmp(const void * a,const void * b)223038fd1498Szrj range_entry_cmp (const void *a, const void *b)
223138fd1498Szrj {
223238fd1498Szrj const struct range_entry *p = (const struct range_entry *) a;
223338fd1498Szrj const struct range_entry *q = (const struct range_entry *) b;
223438fd1498Szrj
223538fd1498Szrj if (p->exp != NULL_TREE && TREE_CODE (p->exp) == SSA_NAME)
223638fd1498Szrj {
223738fd1498Szrj if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME)
223838fd1498Szrj {
223938fd1498Szrj /* Group range_entries for the same SSA_NAME together. */
224038fd1498Szrj if (SSA_NAME_VERSION (p->exp) < SSA_NAME_VERSION (q->exp))
224138fd1498Szrj return -1;
224238fd1498Szrj else if (SSA_NAME_VERSION (p->exp) > SSA_NAME_VERSION (q->exp))
224338fd1498Szrj return 1;
224438fd1498Szrj /* If ->low is different, NULL low goes first, then by
224538fd1498Szrj ascending low. */
224638fd1498Szrj if (p->low != NULL_TREE)
224738fd1498Szrj {
224838fd1498Szrj if (q->low != NULL_TREE)
224938fd1498Szrj {
225038fd1498Szrj tree tem = fold_binary (LT_EXPR, boolean_type_node,
225138fd1498Szrj p->low, q->low);
225238fd1498Szrj if (tem && integer_onep (tem))
225338fd1498Szrj return -1;
225438fd1498Szrj tem = fold_binary (GT_EXPR, boolean_type_node,
225538fd1498Szrj p->low, q->low);
225638fd1498Szrj if (tem && integer_onep (tem))
225738fd1498Szrj return 1;
225838fd1498Szrj }
225938fd1498Szrj else
226038fd1498Szrj return 1;
226138fd1498Szrj }
226238fd1498Szrj else if (q->low != NULL_TREE)
226338fd1498Szrj return -1;
226438fd1498Szrj /* If ->high is different, NULL high goes last, before that by
226538fd1498Szrj ascending high. */
226638fd1498Szrj if (p->high != NULL_TREE)
226738fd1498Szrj {
226838fd1498Szrj if (q->high != NULL_TREE)
226938fd1498Szrj {
227038fd1498Szrj tree tem = fold_binary (LT_EXPR, boolean_type_node,
227138fd1498Szrj p->high, q->high);
227238fd1498Szrj if (tem && integer_onep (tem))
227338fd1498Szrj return -1;
227438fd1498Szrj tem = fold_binary (GT_EXPR, boolean_type_node,
227538fd1498Szrj p->high, q->high);
227638fd1498Szrj if (tem && integer_onep (tem))
227738fd1498Szrj return 1;
227838fd1498Szrj }
227938fd1498Szrj else
228038fd1498Szrj return -1;
228138fd1498Szrj }
228238fd1498Szrj else if (q->high != NULL_TREE)
228338fd1498Szrj return 1;
228438fd1498Szrj /* If both ranges are the same, sort below by ascending idx. */
228538fd1498Szrj }
228638fd1498Szrj else
228738fd1498Szrj return 1;
228838fd1498Szrj }
228938fd1498Szrj else if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME)
229038fd1498Szrj return -1;
229138fd1498Szrj
229238fd1498Szrj if (p->idx < q->idx)
229338fd1498Szrj return -1;
229438fd1498Szrj else
229538fd1498Szrj {
229638fd1498Szrj gcc_checking_assert (p->idx > q->idx);
229738fd1498Szrj return 1;
229838fd1498Szrj }
229938fd1498Szrj }
230038fd1498Szrj
230138fd1498Szrj /* Helper function for update_range_test. Force EXPR into an SSA_NAME,
230238fd1498Szrj insert needed statements BEFORE or after GSI. */
230338fd1498Szrj
230438fd1498Szrj static tree
force_into_ssa_name(gimple_stmt_iterator * gsi,tree expr,bool before)230538fd1498Szrj force_into_ssa_name (gimple_stmt_iterator *gsi, tree expr, bool before)
230638fd1498Szrj {
230738fd1498Szrj enum gsi_iterator_update m = before ? GSI_SAME_STMT : GSI_CONTINUE_LINKING;
230838fd1498Szrj tree ret = force_gimple_operand_gsi (gsi, expr, true, NULL_TREE, before, m);
230938fd1498Szrj if (TREE_CODE (ret) != SSA_NAME)
231038fd1498Szrj {
231138fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (ret)), ret);
231238fd1498Szrj if (before)
231338fd1498Szrj gsi_insert_before (gsi, g, GSI_SAME_STMT);
231438fd1498Szrj else
231538fd1498Szrj gsi_insert_after (gsi, g, GSI_CONTINUE_LINKING);
231638fd1498Szrj ret = gimple_assign_lhs (g);
231738fd1498Szrj }
231838fd1498Szrj return ret;
231938fd1498Szrj }
232038fd1498Szrj
232138fd1498Szrj /* Helper routine of optimize_range_test.
232238fd1498Szrj [EXP, IN_P, LOW, HIGH, STRICT_OVERFLOW_P] is a merged range for
232338fd1498Szrj RANGE and OTHERRANGE through OTHERRANGE + COUNT - 1 ranges,
232438fd1498Szrj OPCODE and OPS are arguments of optimize_range_tests. If OTHERRANGE
232538fd1498Szrj is NULL, OTHERRANGEP should not be and then OTHERRANGEP points to
232638fd1498Szrj an array of COUNT pointers to other ranges. Return
232738fd1498Szrj true if the range merge has been successful.
232838fd1498Szrj If OPCODE is ERROR_MARK, this is called from within
232938fd1498Szrj maybe_optimize_range_tests and is performing inter-bb range optimization.
233038fd1498Szrj In that case, whether an op is BIT_AND_EXPR or BIT_IOR_EXPR is found in
233138fd1498Szrj oe->rank. */
233238fd1498Szrj
233338fd1498Szrj static bool
update_range_test(struct range_entry * range,struct range_entry * otherrange,struct range_entry ** otherrangep,unsigned int count,enum tree_code opcode,vec<operand_entry * > * ops,tree exp,gimple_seq seq,bool in_p,tree low,tree high,bool strict_overflow_p)233438fd1498Szrj update_range_test (struct range_entry *range, struct range_entry *otherrange,
233538fd1498Szrj struct range_entry **otherrangep,
233638fd1498Szrj unsigned int count, enum tree_code opcode,
233738fd1498Szrj vec<operand_entry *> *ops, tree exp, gimple_seq seq,
233838fd1498Szrj bool in_p, tree low, tree high, bool strict_overflow_p)
233938fd1498Szrj {
234038fd1498Szrj operand_entry *oe = (*ops)[range->idx];
234138fd1498Szrj tree op = oe->op;
234238fd1498Szrj gimple *stmt = op ? SSA_NAME_DEF_STMT (op)
234338fd1498Szrj : last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id));
234438fd1498Szrj location_t loc = gimple_location (stmt);
234538fd1498Szrj tree optype = op ? TREE_TYPE (op) : boolean_type_node;
234638fd1498Szrj tree tem = build_range_check (loc, optype, unshare_expr (exp),
234738fd1498Szrj in_p, low, high);
234838fd1498Szrj enum warn_strict_overflow_code wc = WARN_STRICT_OVERFLOW_COMPARISON;
234938fd1498Szrj gimple_stmt_iterator gsi;
235038fd1498Szrj unsigned int i, uid;
235138fd1498Szrj
235238fd1498Szrj if (tem == NULL_TREE)
235338fd1498Szrj return false;
235438fd1498Szrj
235538fd1498Szrj /* If op is default def SSA_NAME, there is no place to insert the
235638fd1498Szrj new comparison. Give up, unless we can use OP itself as the
235738fd1498Szrj range test. */
235838fd1498Szrj if (op && SSA_NAME_IS_DEFAULT_DEF (op))
235938fd1498Szrj {
236038fd1498Szrj if (op == range->exp
236138fd1498Szrj && ((TYPE_PRECISION (optype) == 1 && TYPE_UNSIGNED (optype))
236238fd1498Szrj || TREE_CODE (optype) == BOOLEAN_TYPE)
236338fd1498Szrj && (op == tem
236438fd1498Szrj || (TREE_CODE (tem) == EQ_EXPR
236538fd1498Szrj && TREE_OPERAND (tem, 0) == op
236638fd1498Szrj && integer_onep (TREE_OPERAND (tem, 1))))
236738fd1498Szrj && opcode != BIT_IOR_EXPR
236838fd1498Szrj && (opcode != ERROR_MARK || oe->rank != BIT_IOR_EXPR))
236938fd1498Szrj {
237038fd1498Szrj stmt = NULL;
237138fd1498Szrj tem = op;
237238fd1498Szrj }
237338fd1498Szrj else
237438fd1498Szrj return false;
237538fd1498Szrj }
237638fd1498Szrj
237738fd1498Szrj if (strict_overflow_p && issue_strict_overflow_warning (wc))
237838fd1498Szrj warning_at (loc, OPT_Wstrict_overflow,
237938fd1498Szrj "assuming signed overflow does not occur "
238038fd1498Szrj "when simplifying range test");
238138fd1498Szrj
238238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
238338fd1498Szrj {
238438fd1498Szrj struct range_entry *r;
238538fd1498Szrj fprintf (dump_file, "Optimizing range tests ");
238638fd1498Szrj print_generic_expr (dump_file, range->exp);
238738fd1498Szrj fprintf (dump_file, " %c[", range->in_p ? '+' : '-');
238838fd1498Szrj print_generic_expr (dump_file, range->low);
238938fd1498Szrj fprintf (dump_file, ", ");
239038fd1498Szrj print_generic_expr (dump_file, range->high);
239138fd1498Szrj fprintf (dump_file, "]");
239238fd1498Szrj for (i = 0; i < count; i++)
239338fd1498Szrj {
239438fd1498Szrj if (otherrange)
239538fd1498Szrj r = otherrange + i;
239638fd1498Szrj else
239738fd1498Szrj r = otherrangep[i];
239838fd1498Szrj if (r->exp
239938fd1498Szrj && r->exp != range->exp
240038fd1498Szrj && TREE_CODE (r->exp) == SSA_NAME)
240138fd1498Szrj {
240238fd1498Szrj fprintf (dump_file, " and ");
240338fd1498Szrj print_generic_expr (dump_file, r->exp);
240438fd1498Szrj }
240538fd1498Szrj else
240638fd1498Szrj fprintf (dump_file, " and");
240738fd1498Szrj fprintf (dump_file, " %c[", r->in_p ? '+' : '-');
240838fd1498Szrj print_generic_expr (dump_file, r->low);
240938fd1498Szrj fprintf (dump_file, ", ");
241038fd1498Szrj print_generic_expr (dump_file, r->high);
241138fd1498Szrj fprintf (dump_file, "]");
241238fd1498Szrj }
241338fd1498Szrj fprintf (dump_file, "\n into ");
241438fd1498Szrj print_generic_expr (dump_file, tem);
241538fd1498Szrj fprintf (dump_file, "\n");
241638fd1498Szrj }
241738fd1498Szrj
241838fd1498Szrj if (opcode == BIT_IOR_EXPR
241938fd1498Szrj || (opcode == ERROR_MARK && oe->rank == BIT_IOR_EXPR))
242038fd1498Szrj tem = invert_truthvalue_loc (loc, tem);
242138fd1498Szrj
242238fd1498Szrj tem = fold_convert_loc (loc, optype, tem);
242338fd1498Szrj if (stmt)
242438fd1498Szrj {
242538fd1498Szrj gsi = gsi_for_stmt (stmt);
242638fd1498Szrj uid = gimple_uid (stmt);
242738fd1498Szrj }
242838fd1498Szrj else
242938fd1498Szrj {
243038fd1498Szrj gsi = gsi_none ();
243138fd1498Szrj uid = 0;
243238fd1498Szrj }
243338fd1498Szrj if (stmt == NULL)
243438fd1498Szrj gcc_checking_assert (tem == op);
243538fd1498Szrj /* In rare cases range->exp can be equal to lhs of stmt.
243638fd1498Szrj In that case we have to insert after the stmt rather then before
243738fd1498Szrj it. If stmt is a PHI, insert it at the start of the basic block. */
243838fd1498Szrj else if (op != range->exp)
243938fd1498Szrj {
244038fd1498Szrj gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
244138fd1498Szrj tem = force_into_ssa_name (&gsi, tem, true);
244238fd1498Szrj gsi_prev (&gsi);
244338fd1498Szrj }
244438fd1498Szrj else if (gimple_code (stmt) != GIMPLE_PHI)
244538fd1498Szrj {
244638fd1498Szrj gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
244738fd1498Szrj tem = force_into_ssa_name (&gsi, tem, false);
244838fd1498Szrj }
244938fd1498Szrj else
245038fd1498Szrj {
245138fd1498Szrj gsi = gsi_after_labels (gimple_bb (stmt));
245238fd1498Szrj if (!gsi_end_p (gsi))
245338fd1498Szrj uid = gimple_uid (gsi_stmt (gsi));
245438fd1498Szrj else
245538fd1498Szrj {
245638fd1498Szrj gsi = gsi_start_bb (gimple_bb (stmt));
245738fd1498Szrj uid = 1;
245838fd1498Szrj while (!gsi_end_p (gsi))
245938fd1498Szrj {
246038fd1498Szrj uid = gimple_uid (gsi_stmt (gsi));
246138fd1498Szrj gsi_next (&gsi);
246238fd1498Szrj }
246338fd1498Szrj }
246438fd1498Szrj gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
246538fd1498Szrj tem = force_into_ssa_name (&gsi, tem, true);
246638fd1498Szrj if (gsi_end_p (gsi))
246738fd1498Szrj gsi = gsi_last_bb (gimple_bb (stmt));
246838fd1498Szrj else
246938fd1498Szrj gsi_prev (&gsi);
247038fd1498Szrj }
247138fd1498Szrj for (; !gsi_end_p (gsi); gsi_prev (&gsi))
247238fd1498Szrj if (gimple_uid (gsi_stmt (gsi)))
247338fd1498Szrj break;
247438fd1498Szrj else
247538fd1498Szrj gimple_set_uid (gsi_stmt (gsi), uid);
247638fd1498Szrj
247738fd1498Szrj oe->op = tem;
247838fd1498Szrj range->exp = exp;
247938fd1498Szrj range->low = low;
248038fd1498Szrj range->high = high;
248138fd1498Szrj range->in_p = in_p;
248238fd1498Szrj range->strict_overflow_p = false;
248338fd1498Szrj
248438fd1498Szrj for (i = 0; i < count; i++)
248538fd1498Szrj {
248638fd1498Szrj if (otherrange)
248738fd1498Szrj range = otherrange + i;
248838fd1498Szrj else
248938fd1498Szrj range = otherrangep[i];
249038fd1498Szrj oe = (*ops)[range->idx];
249138fd1498Szrj /* Now change all the other range test immediate uses, so that
249238fd1498Szrj those tests will be optimized away. */
249338fd1498Szrj if (opcode == ERROR_MARK)
249438fd1498Szrj {
249538fd1498Szrj if (oe->op)
249638fd1498Szrj oe->op = build_int_cst (TREE_TYPE (oe->op),
249738fd1498Szrj oe->rank == BIT_IOR_EXPR ? 0 : 1);
249838fd1498Szrj else
249938fd1498Szrj oe->op = (oe->rank == BIT_IOR_EXPR
250038fd1498Szrj ? boolean_false_node : boolean_true_node);
250138fd1498Szrj }
250238fd1498Szrj else
250338fd1498Szrj oe->op = error_mark_node;
250438fd1498Szrj range->exp = NULL_TREE;
250538fd1498Szrj range->low = NULL_TREE;
250638fd1498Szrj range->high = NULL_TREE;
250738fd1498Szrj }
250838fd1498Szrj return true;
250938fd1498Szrj }
251038fd1498Szrj
251138fd1498Szrj /* Optimize X == CST1 || X == CST2
251238fd1498Szrj if popcount (CST1 ^ CST2) == 1 into
251338fd1498Szrj (X & ~(CST1 ^ CST2)) == (CST1 & ~(CST1 ^ CST2)).
251438fd1498Szrj Similarly for ranges. E.g.
251538fd1498Szrj X != 2 && X != 3 && X != 10 && X != 11
251638fd1498Szrj will be transformed by the previous optimization into
251738fd1498Szrj !((X - 2U) <= 1U || (X - 10U) <= 1U)
251838fd1498Szrj and this loop can transform that into
251938fd1498Szrj !(((X & ~8) - 2U) <= 1U). */
252038fd1498Szrj
252138fd1498Szrj static bool
optimize_range_tests_xor(enum tree_code opcode,tree type,tree lowi,tree lowj,tree highi,tree highj,vec<operand_entry * > * ops,struct range_entry * rangei,struct range_entry * rangej)252238fd1498Szrj optimize_range_tests_xor (enum tree_code opcode, tree type,
252338fd1498Szrj tree lowi, tree lowj, tree highi, tree highj,
252438fd1498Szrj vec<operand_entry *> *ops,
252538fd1498Szrj struct range_entry *rangei,
252638fd1498Szrj struct range_entry *rangej)
252738fd1498Szrj {
252838fd1498Szrj tree lowxor, highxor, tem, exp;
252938fd1498Szrj /* Check lowi ^ lowj == highi ^ highj and
253038fd1498Szrj popcount (lowi ^ lowj) == 1. */
253138fd1498Szrj lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj);
253238fd1498Szrj if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST)
253338fd1498Szrj return false;
253438fd1498Szrj if (!integer_pow2p (lowxor))
253538fd1498Szrj return false;
253638fd1498Szrj highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj);
253738fd1498Szrj if (!tree_int_cst_equal (lowxor, highxor))
253838fd1498Szrj return false;
253938fd1498Szrj
254038fd1498Szrj tem = fold_build1 (BIT_NOT_EXPR, type, lowxor);
254138fd1498Szrj exp = fold_build2 (BIT_AND_EXPR, type, rangei->exp, tem);
254238fd1498Szrj lowj = fold_build2 (BIT_AND_EXPR, type, lowi, tem);
254338fd1498Szrj highj = fold_build2 (BIT_AND_EXPR, type, highi, tem);
254438fd1498Szrj if (update_range_test (rangei, rangej, NULL, 1, opcode, ops, exp,
254538fd1498Szrj NULL, rangei->in_p, lowj, highj,
254638fd1498Szrj rangei->strict_overflow_p
254738fd1498Szrj || rangej->strict_overflow_p))
254838fd1498Szrj return true;
254938fd1498Szrj return false;
255038fd1498Szrj }
255138fd1498Szrj
255238fd1498Szrj /* Optimize X == CST1 || X == CST2
255338fd1498Szrj if popcount (CST2 - CST1) == 1 into
255438fd1498Szrj ((X - CST1) & ~(CST2 - CST1)) == 0.
255538fd1498Szrj Similarly for ranges. E.g.
255638fd1498Szrj X == 43 || X == 76 || X == 44 || X == 78 || X == 77 || X == 46
255738fd1498Szrj || X == 75 || X == 45
255838fd1498Szrj will be transformed by the previous optimization into
255938fd1498Szrj (X - 43U) <= 3U || (X - 75U) <= 3U
256038fd1498Szrj and this loop can transform that into
256138fd1498Szrj ((X - 43U) & ~(75U - 43U)) <= 3U. */
256238fd1498Szrj static bool
optimize_range_tests_diff(enum tree_code opcode,tree type,tree lowi,tree lowj,tree highi,tree highj,vec<operand_entry * > * ops,struct range_entry * rangei,struct range_entry * rangej)256338fd1498Szrj optimize_range_tests_diff (enum tree_code opcode, tree type,
256438fd1498Szrj tree lowi, tree lowj, tree highi, tree highj,
256538fd1498Szrj vec<operand_entry *> *ops,
256638fd1498Szrj struct range_entry *rangei,
256738fd1498Szrj struct range_entry *rangej)
256838fd1498Szrj {
256938fd1498Szrj tree tem1, tem2, mask;
257038fd1498Szrj /* Check highi - lowi == highj - lowj. */
257138fd1498Szrj tem1 = fold_binary (MINUS_EXPR, type, highi, lowi);
257238fd1498Szrj if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
257338fd1498Szrj return false;
257438fd1498Szrj tem2 = fold_binary (MINUS_EXPR, type, highj, lowj);
257538fd1498Szrj if (!tree_int_cst_equal (tem1, tem2))
257638fd1498Szrj return false;
257738fd1498Szrj /* Check popcount (lowj - lowi) == 1. */
257838fd1498Szrj tem1 = fold_binary (MINUS_EXPR, type, lowj, lowi);
257938fd1498Szrj if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
258038fd1498Szrj return false;
258138fd1498Szrj if (!integer_pow2p (tem1))
258238fd1498Szrj return false;
258338fd1498Szrj
258438fd1498Szrj type = unsigned_type_for (type);
258538fd1498Szrj tem1 = fold_convert (type, tem1);
258638fd1498Szrj tem2 = fold_convert (type, tem2);
258738fd1498Szrj lowi = fold_convert (type, lowi);
258838fd1498Szrj mask = fold_build1 (BIT_NOT_EXPR, type, tem1);
258938fd1498Szrj tem1 = fold_build2 (MINUS_EXPR, type,
259038fd1498Szrj fold_convert (type, rangei->exp), lowi);
259138fd1498Szrj tem1 = fold_build2 (BIT_AND_EXPR, type, tem1, mask);
259238fd1498Szrj lowj = build_int_cst (type, 0);
259338fd1498Szrj if (update_range_test (rangei, rangej, NULL, 1, opcode, ops, tem1,
259438fd1498Szrj NULL, rangei->in_p, lowj, tem2,
259538fd1498Szrj rangei->strict_overflow_p
259638fd1498Szrj || rangej->strict_overflow_p))
259738fd1498Szrj return true;
259838fd1498Szrj return false;
259938fd1498Szrj }
260038fd1498Szrj
260138fd1498Szrj /* It does some common checks for function optimize_range_tests_xor and
260238fd1498Szrj optimize_range_tests_diff.
260338fd1498Szrj If OPTIMIZE_XOR is TRUE, it calls optimize_range_tests_xor.
260438fd1498Szrj Else it calls optimize_range_tests_diff. */
260538fd1498Szrj
260638fd1498Szrj static bool
optimize_range_tests_1(enum tree_code opcode,int first,int length,bool optimize_xor,vec<operand_entry * > * ops,struct range_entry * ranges)260738fd1498Szrj optimize_range_tests_1 (enum tree_code opcode, int first, int length,
260838fd1498Szrj bool optimize_xor, vec<operand_entry *> *ops,
260938fd1498Szrj struct range_entry *ranges)
261038fd1498Szrj {
261138fd1498Szrj int i, j;
261238fd1498Szrj bool any_changes = false;
261338fd1498Szrj for (i = first; i < length; i++)
261438fd1498Szrj {
261538fd1498Szrj tree lowi, highi, lowj, highj, type, tem;
261638fd1498Szrj
261738fd1498Szrj if (ranges[i].exp == NULL_TREE || ranges[i].in_p)
261838fd1498Szrj continue;
261938fd1498Szrj type = TREE_TYPE (ranges[i].exp);
262038fd1498Szrj if (!INTEGRAL_TYPE_P (type))
262138fd1498Szrj continue;
262238fd1498Szrj lowi = ranges[i].low;
262338fd1498Szrj if (lowi == NULL_TREE)
262438fd1498Szrj lowi = TYPE_MIN_VALUE (type);
262538fd1498Szrj highi = ranges[i].high;
262638fd1498Szrj if (highi == NULL_TREE)
262738fd1498Szrj continue;
262838fd1498Szrj for (j = i + 1; j < length && j < i + 64; j++)
262938fd1498Szrj {
263038fd1498Szrj bool changes;
263138fd1498Szrj if (ranges[i].exp != ranges[j].exp || ranges[j].in_p)
263238fd1498Szrj continue;
263338fd1498Szrj lowj = ranges[j].low;
263438fd1498Szrj if (lowj == NULL_TREE)
263538fd1498Szrj continue;
263638fd1498Szrj highj = ranges[j].high;
263738fd1498Szrj if (highj == NULL_TREE)
263838fd1498Szrj highj = TYPE_MAX_VALUE (type);
263938fd1498Szrj /* Check lowj > highi. */
264038fd1498Szrj tem = fold_binary (GT_EXPR, boolean_type_node,
264138fd1498Szrj lowj, highi);
264238fd1498Szrj if (tem == NULL_TREE || !integer_onep (tem))
264338fd1498Szrj continue;
264438fd1498Szrj if (optimize_xor)
264538fd1498Szrj changes = optimize_range_tests_xor (opcode, type, lowi, lowj,
264638fd1498Szrj highi, highj, ops,
264738fd1498Szrj ranges + i, ranges + j);
264838fd1498Szrj else
264938fd1498Szrj changes = optimize_range_tests_diff (opcode, type, lowi, lowj,
265038fd1498Szrj highi, highj, ops,
265138fd1498Szrj ranges + i, ranges + j);
265238fd1498Szrj if (changes)
265338fd1498Szrj {
265438fd1498Szrj any_changes = true;
265538fd1498Szrj break;
265638fd1498Szrj }
265738fd1498Szrj }
265838fd1498Szrj }
265938fd1498Szrj return any_changes;
266038fd1498Szrj }
266138fd1498Szrj
266238fd1498Szrj /* Helper function of optimize_range_tests_to_bit_test. Handle a single
266338fd1498Szrj range, EXP, LOW, HIGH, compute bit mask of bits to test and return
266438fd1498Szrj EXP on success, NULL otherwise. */
266538fd1498Szrj
266638fd1498Szrj static tree
extract_bit_test_mask(tree exp,int prec,tree totallow,tree low,tree high,wide_int * mask,tree * totallowp)266738fd1498Szrj extract_bit_test_mask (tree exp, int prec, tree totallow, tree low, tree high,
266838fd1498Szrj wide_int *mask, tree *totallowp)
266938fd1498Szrj {
267038fd1498Szrj tree tem = int_const_binop (MINUS_EXPR, high, low);
267138fd1498Szrj if (tem == NULL_TREE
267238fd1498Szrj || TREE_CODE (tem) != INTEGER_CST
267338fd1498Szrj || TREE_OVERFLOW (tem)
267438fd1498Szrj || tree_int_cst_sgn (tem) == -1
267538fd1498Szrj || compare_tree_int (tem, prec) != -1)
267638fd1498Szrj return NULL_TREE;
267738fd1498Szrj
267838fd1498Szrj unsigned HOST_WIDE_INT max = tree_to_uhwi (tem) + 1;
267938fd1498Szrj *mask = wi::shifted_mask (0, max, false, prec);
268038fd1498Szrj if (TREE_CODE (exp) == BIT_AND_EXPR
268138fd1498Szrj && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
268238fd1498Szrj {
268338fd1498Szrj widest_int msk = wi::to_widest (TREE_OPERAND (exp, 1));
268438fd1498Szrj msk = wi::zext (~msk, TYPE_PRECISION (TREE_TYPE (exp)));
268538fd1498Szrj if (wi::popcount (msk) == 1
268638fd1498Szrj && wi::ltu_p (msk, prec - max))
268738fd1498Szrj {
268838fd1498Szrj *mask |= wi::shifted_mask (msk.to_uhwi (), max, false, prec);
268938fd1498Szrj max += msk.to_uhwi ();
269038fd1498Szrj exp = TREE_OPERAND (exp, 0);
269138fd1498Szrj if (integer_zerop (low)
269238fd1498Szrj && TREE_CODE (exp) == PLUS_EXPR
269338fd1498Szrj && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
269438fd1498Szrj {
269538fd1498Szrj tree ret = TREE_OPERAND (exp, 0);
269638fd1498Szrj STRIP_NOPS (ret);
269738fd1498Szrj widest_int bias
269838fd1498Szrj = wi::neg (wi::sext (wi::to_widest (TREE_OPERAND (exp, 1)),
269938fd1498Szrj TYPE_PRECISION (TREE_TYPE (low))));
270038fd1498Szrj tree tbias = wide_int_to_tree (TREE_TYPE (ret), bias);
270138fd1498Szrj if (totallowp)
270238fd1498Szrj {
270338fd1498Szrj *totallowp = tbias;
270438fd1498Szrj return ret;
270538fd1498Szrj }
270638fd1498Szrj else if (!tree_int_cst_lt (totallow, tbias))
270738fd1498Szrj return NULL_TREE;
270838fd1498Szrj bias = wi::to_widest (tbias);
270938fd1498Szrj bias -= wi::to_widest (totallow);
271038fd1498Szrj if (bias >= 0 && bias < prec - max)
271138fd1498Szrj {
271238fd1498Szrj *mask = wi::lshift (*mask, bias);
271338fd1498Szrj return ret;
271438fd1498Szrj }
271538fd1498Szrj }
271638fd1498Szrj }
271738fd1498Szrj }
271838fd1498Szrj if (totallowp)
271938fd1498Szrj return exp;
272038fd1498Szrj if (!tree_int_cst_lt (totallow, low))
272138fd1498Szrj return exp;
272238fd1498Szrj tem = int_const_binop (MINUS_EXPR, low, totallow);
272338fd1498Szrj if (tem == NULL_TREE
272438fd1498Szrj || TREE_CODE (tem) != INTEGER_CST
272538fd1498Szrj || TREE_OVERFLOW (tem)
272638fd1498Szrj || compare_tree_int (tem, prec - max) == 1)
272738fd1498Szrj return NULL_TREE;
272838fd1498Szrj
272938fd1498Szrj *mask = wi::lshift (*mask, wi::to_widest (tem));
273038fd1498Szrj return exp;
273138fd1498Szrj }
273238fd1498Szrj
273338fd1498Szrj /* Attempt to optimize small range tests using bit test.
273438fd1498Szrj E.g.
273538fd1498Szrj X != 43 && X != 76 && X != 44 && X != 78 && X != 49
273638fd1498Szrj && X != 77 && X != 46 && X != 75 && X != 45 && X != 82
273738fd1498Szrj has been by earlier optimizations optimized into:
273838fd1498Szrj ((X - 43U) & ~32U) > 3U && X != 49 && X != 82
273938fd1498Szrj As all the 43 through 82 range is less than 64 numbers,
274038fd1498Szrj for 64-bit word targets optimize that into:
274138fd1498Szrj (X - 43U) > 40U && ((1 << (X - 43U)) & 0x8F0000004FULL) == 0 */
274238fd1498Szrj
274338fd1498Szrj static bool
optimize_range_tests_to_bit_test(enum tree_code opcode,int first,int length,vec<operand_entry * > * ops,struct range_entry * ranges)274438fd1498Szrj optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
274538fd1498Szrj vec<operand_entry *> *ops,
274638fd1498Szrj struct range_entry *ranges)
274738fd1498Szrj {
274838fd1498Szrj int i, j;
274938fd1498Szrj bool any_changes = false;
275038fd1498Szrj int prec = GET_MODE_BITSIZE (word_mode);
275138fd1498Szrj auto_vec<struct range_entry *, 64> candidates;
275238fd1498Szrj
275338fd1498Szrj for (i = first; i < length - 2; i++)
275438fd1498Szrj {
275538fd1498Szrj tree lowi, highi, lowj, highj, type;
275638fd1498Szrj
275738fd1498Szrj if (ranges[i].exp == NULL_TREE || ranges[i].in_p)
275838fd1498Szrj continue;
275938fd1498Szrj type = TREE_TYPE (ranges[i].exp);
276038fd1498Szrj if (!INTEGRAL_TYPE_P (type))
276138fd1498Szrj continue;
276238fd1498Szrj lowi = ranges[i].low;
276338fd1498Szrj if (lowi == NULL_TREE)
276438fd1498Szrj lowi = TYPE_MIN_VALUE (type);
276538fd1498Szrj highi = ranges[i].high;
276638fd1498Szrj if (highi == NULL_TREE)
276738fd1498Szrj continue;
276838fd1498Szrj wide_int mask;
276938fd1498Szrj tree exp = extract_bit_test_mask (ranges[i].exp, prec, lowi, lowi,
277038fd1498Szrj highi, &mask, &lowi);
277138fd1498Szrj if (exp == NULL_TREE)
277238fd1498Szrj continue;
277338fd1498Szrj bool strict_overflow_p = ranges[i].strict_overflow_p;
277438fd1498Szrj candidates.truncate (0);
277538fd1498Szrj int end = MIN (i + 64, length);
277638fd1498Szrj for (j = i + 1; j < end; j++)
277738fd1498Szrj {
277838fd1498Szrj tree exp2;
277938fd1498Szrj if (ranges[j].exp == NULL_TREE || ranges[j].in_p)
278038fd1498Szrj continue;
278138fd1498Szrj if (ranges[j].exp == exp)
278238fd1498Szrj ;
278338fd1498Szrj else if (TREE_CODE (ranges[j].exp) == BIT_AND_EXPR)
278438fd1498Szrj {
278538fd1498Szrj exp2 = TREE_OPERAND (ranges[j].exp, 0);
278638fd1498Szrj if (exp2 == exp)
278738fd1498Szrj ;
278838fd1498Szrj else if (TREE_CODE (exp2) == PLUS_EXPR)
278938fd1498Szrj {
279038fd1498Szrj exp2 = TREE_OPERAND (exp2, 0);
279138fd1498Szrj STRIP_NOPS (exp2);
279238fd1498Szrj if (exp2 != exp)
279338fd1498Szrj continue;
279438fd1498Szrj }
279538fd1498Szrj else
279638fd1498Szrj continue;
279738fd1498Szrj }
279838fd1498Szrj else
279938fd1498Szrj continue;
280038fd1498Szrj lowj = ranges[j].low;
280138fd1498Szrj if (lowj == NULL_TREE)
280238fd1498Szrj continue;
280338fd1498Szrj highj = ranges[j].high;
280438fd1498Szrj if (highj == NULL_TREE)
280538fd1498Szrj highj = TYPE_MAX_VALUE (type);
280638fd1498Szrj wide_int mask2;
280738fd1498Szrj exp2 = extract_bit_test_mask (ranges[j].exp, prec, lowi, lowj,
280838fd1498Szrj highj, &mask2, NULL);
280938fd1498Szrj if (exp2 != exp)
281038fd1498Szrj continue;
281138fd1498Szrj mask |= mask2;
281238fd1498Szrj strict_overflow_p |= ranges[j].strict_overflow_p;
281338fd1498Szrj candidates.safe_push (&ranges[j]);
281438fd1498Szrj }
281538fd1498Szrj
281638fd1498Szrj /* If we need otherwise 3 or more comparisons, use a bit test. */
281738fd1498Szrj if (candidates.length () >= 2)
281838fd1498Szrj {
281938fd1498Szrj tree high = wide_int_to_tree (TREE_TYPE (lowi),
282038fd1498Szrj wi::to_widest (lowi)
282138fd1498Szrj + prec - 1 - wi::clz (mask));
282238fd1498Szrj operand_entry *oe = (*ops)[ranges[i].idx];
282338fd1498Szrj tree op = oe->op;
282438fd1498Szrj gimple *stmt = op ? SSA_NAME_DEF_STMT (op)
282538fd1498Szrj : last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id));
282638fd1498Szrj location_t loc = gimple_location (stmt);
282738fd1498Szrj tree optype = op ? TREE_TYPE (op) : boolean_type_node;
282838fd1498Szrj
282938fd1498Szrj /* See if it isn't cheaper to pretend the minimum value of the
283038fd1498Szrj range is 0, if maximum value is small enough.
283138fd1498Szrj We can avoid then subtraction of the minimum value, but the
283238fd1498Szrj mask constant could be perhaps more expensive. */
283338fd1498Szrj if (compare_tree_int (lowi, 0) > 0
283438fd1498Szrj && compare_tree_int (high, prec) < 0)
283538fd1498Szrj {
283638fd1498Szrj int cost_diff;
283738fd1498Szrj HOST_WIDE_INT m = tree_to_uhwi (lowi);
283838fd1498Szrj rtx reg = gen_raw_REG (word_mode, 10000);
283938fd1498Szrj bool speed_p = optimize_bb_for_speed_p (gimple_bb (stmt));
284038fd1498Szrj cost_diff = set_rtx_cost (gen_rtx_PLUS (word_mode, reg,
284138fd1498Szrj GEN_INT (-m)), speed_p);
284238fd1498Szrj rtx r = immed_wide_int_const (mask, word_mode);
284338fd1498Szrj cost_diff += set_src_cost (gen_rtx_AND (word_mode, reg, r),
284438fd1498Szrj word_mode, speed_p);
284538fd1498Szrj r = immed_wide_int_const (wi::lshift (mask, m), word_mode);
284638fd1498Szrj cost_diff -= set_src_cost (gen_rtx_AND (word_mode, reg, r),
284738fd1498Szrj word_mode, speed_p);
284838fd1498Szrj if (cost_diff > 0)
284938fd1498Szrj {
285038fd1498Szrj mask = wi::lshift (mask, m);
285138fd1498Szrj lowi = build_zero_cst (TREE_TYPE (lowi));
285238fd1498Szrj }
285338fd1498Szrj }
285438fd1498Szrj
285538fd1498Szrj tree tem = build_range_check (loc, optype, unshare_expr (exp),
285638fd1498Szrj false, lowi, high);
285738fd1498Szrj if (tem == NULL_TREE || is_gimple_val (tem))
285838fd1498Szrj continue;
285938fd1498Szrj tree etype = unsigned_type_for (TREE_TYPE (exp));
286038fd1498Szrj exp = fold_build2_loc (loc, MINUS_EXPR, etype,
286138fd1498Szrj fold_convert_loc (loc, etype, exp),
286238fd1498Szrj fold_convert_loc (loc, etype, lowi));
286338fd1498Szrj exp = fold_convert_loc (loc, integer_type_node, exp);
286438fd1498Szrj tree word_type = lang_hooks.types.type_for_mode (word_mode, 1);
286538fd1498Szrj exp = fold_build2_loc (loc, LSHIFT_EXPR, word_type,
286638fd1498Szrj build_int_cst (word_type, 1), exp);
286738fd1498Szrj exp = fold_build2_loc (loc, BIT_AND_EXPR, word_type, exp,
286838fd1498Szrj wide_int_to_tree (word_type, mask));
286938fd1498Szrj exp = fold_build2_loc (loc, EQ_EXPR, optype, exp,
287038fd1498Szrj build_zero_cst (word_type));
287138fd1498Szrj if (is_gimple_val (exp))
287238fd1498Szrj continue;
287338fd1498Szrj
287438fd1498Szrj /* The shift might have undefined behavior if TEM is true,
287538fd1498Szrj but reassociate_bb isn't prepared to have basic blocks
287638fd1498Szrj split when it is running. So, temporarily emit a code
287738fd1498Szrj with BIT_IOR_EXPR instead of &&, and fix it up in
287838fd1498Szrj branch_fixup. */
287938fd1498Szrj gimple_seq seq;
288038fd1498Szrj tem = force_gimple_operand (tem, &seq, true, NULL_TREE);
288138fd1498Szrj gcc_assert (TREE_CODE (tem) == SSA_NAME);
288238fd1498Szrj gimple_set_visited (SSA_NAME_DEF_STMT (tem), true);
288338fd1498Szrj gimple_seq seq2;
288438fd1498Szrj exp = force_gimple_operand (exp, &seq2, true, NULL_TREE);
288538fd1498Szrj gimple_seq_add_seq_without_update (&seq, seq2);
288638fd1498Szrj gcc_assert (TREE_CODE (exp) == SSA_NAME);
288738fd1498Szrj gimple_set_visited (SSA_NAME_DEF_STMT (exp), true);
288838fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (optype),
288938fd1498Szrj BIT_IOR_EXPR, tem, exp);
289038fd1498Szrj gimple_set_location (g, loc);
289138fd1498Szrj gimple_seq_add_stmt_without_update (&seq, g);
289238fd1498Szrj exp = gimple_assign_lhs (g);
289338fd1498Szrj tree val = build_zero_cst (optype);
289438fd1498Szrj if (update_range_test (&ranges[i], NULL, candidates.address (),
289538fd1498Szrj candidates.length (), opcode, ops, exp,
289638fd1498Szrj seq, false, val, val, strict_overflow_p))
289738fd1498Szrj {
289838fd1498Szrj any_changes = true;
289938fd1498Szrj reassoc_branch_fixups.safe_push (tem);
290038fd1498Szrj }
290138fd1498Szrj else
290238fd1498Szrj gimple_seq_discard (seq);
290338fd1498Szrj }
290438fd1498Szrj }
290538fd1498Szrj return any_changes;
290638fd1498Szrj }
290738fd1498Szrj
290838fd1498Szrj /* Optimize x != 0 && y != 0 && z != 0 into (x | y | z) != 0
290938fd1498Szrj and similarly x != -1 && y != -1 && y != -1 into (x & y & z) != -1. */
291038fd1498Szrj
291138fd1498Szrj static bool
optimize_range_tests_cmp_bitwise(enum tree_code opcode,int first,int length,vec<operand_entry * > * ops,struct range_entry * ranges)291238fd1498Szrj optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length,
291338fd1498Szrj vec<operand_entry *> *ops,
291438fd1498Szrj struct range_entry *ranges)
291538fd1498Szrj {
291638fd1498Szrj int i;
291738fd1498Szrj unsigned int b;
291838fd1498Szrj bool any_changes = false;
291938fd1498Szrj auto_vec<int, 128> buckets;
292038fd1498Szrj auto_vec<int, 32> chains;
292138fd1498Szrj auto_vec<struct range_entry *, 32> candidates;
292238fd1498Szrj
292338fd1498Szrj for (i = first; i < length; i++)
292438fd1498Szrj {
292538fd1498Szrj if (ranges[i].exp == NULL_TREE
292638fd1498Szrj || TREE_CODE (ranges[i].exp) != SSA_NAME
292738fd1498Szrj || !ranges[i].in_p
292838fd1498Szrj || TYPE_PRECISION (TREE_TYPE (ranges[i].exp)) <= 1
292938fd1498Szrj || TREE_CODE (TREE_TYPE (ranges[i].exp)) == BOOLEAN_TYPE
293038fd1498Szrj || ranges[i].low == NULL_TREE
293138fd1498Szrj || ranges[i].low != ranges[i].high)
293238fd1498Szrj continue;
293338fd1498Szrj
293438fd1498Szrj bool zero_p = integer_zerop (ranges[i].low);
293538fd1498Szrj if (!zero_p && !integer_all_onesp (ranges[i].low))
293638fd1498Szrj continue;
293738fd1498Szrj
293838fd1498Szrj b = TYPE_PRECISION (TREE_TYPE (ranges[i].exp)) * 2 + !zero_p;
293938fd1498Szrj if (buckets.length () <= b)
294038fd1498Szrj buckets.safe_grow_cleared (b + 1);
294138fd1498Szrj if (chains.length () <= (unsigned) i)
294238fd1498Szrj chains.safe_grow (i + 1);
294338fd1498Szrj chains[i] = buckets[b];
294438fd1498Szrj buckets[b] = i + 1;
294538fd1498Szrj }
294638fd1498Szrj
294738fd1498Szrj FOR_EACH_VEC_ELT (buckets, b, i)
294838fd1498Szrj if (i && chains[i - 1])
294938fd1498Szrj {
295038fd1498Szrj int j, k = i;
295138fd1498Szrj for (j = chains[i - 1]; j; j = chains[j - 1])
295238fd1498Szrj {
295338fd1498Szrj gimple *gk = SSA_NAME_DEF_STMT (ranges[k - 1].exp);
295438fd1498Szrj gimple *gj = SSA_NAME_DEF_STMT (ranges[j - 1].exp);
295538fd1498Szrj if (reassoc_stmt_dominates_stmt_p (gk, gj))
295638fd1498Szrj k = j;
295738fd1498Szrj }
295838fd1498Szrj tree type1 = TREE_TYPE (ranges[k - 1].exp);
295938fd1498Szrj tree type2 = NULL_TREE;
296038fd1498Szrj bool strict_overflow_p = false;
296138fd1498Szrj candidates.truncate (0);
296238fd1498Szrj for (j = i; j; j = chains[j - 1])
296338fd1498Szrj {
296438fd1498Szrj tree type = TREE_TYPE (ranges[j - 1].exp);
296538fd1498Szrj strict_overflow_p |= ranges[j - 1].strict_overflow_p;
296638fd1498Szrj if (j == k
296738fd1498Szrj || useless_type_conversion_p (type1, type))
296838fd1498Szrj ;
296938fd1498Szrj else if (type2 == NULL_TREE
297038fd1498Szrj || useless_type_conversion_p (type2, type))
297138fd1498Szrj {
297238fd1498Szrj if (type2 == NULL_TREE)
297338fd1498Szrj type2 = type;
297438fd1498Szrj candidates.safe_push (&ranges[j - 1]);
297538fd1498Szrj }
297638fd1498Szrj }
297738fd1498Szrj unsigned l = candidates.length ();
297838fd1498Szrj for (j = i; j; j = chains[j - 1])
297938fd1498Szrj {
298038fd1498Szrj tree type = TREE_TYPE (ranges[j - 1].exp);
298138fd1498Szrj if (j == k)
298238fd1498Szrj continue;
298338fd1498Szrj if (useless_type_conversion_p (type1, type))
298438fd1498Szrj ;
298538fd1498Szrj else if (type2 == NULL_TREE
298638fd1498Szrj || useless_type_conversion_p (type2, type))
298738fd1498Szrj continue;
298838fd1498Szrj candidates.safe_push (&ranges[j - 1]);
298938fd1498Szrj }
299038fd1498Szrj gimple_seq seq = NULL;
299138fd1498Szrj tree op = NULL_TREE;
299238fd1498Szrj unsigned int id;
299338fd1498Szrj struct range_entry *r;
299438fd1498Szrj candidates.safe_push (&ranges[k - 1]);
299538fd1498Szrj FOR_EACH_VEC_ELT (candidates, id, r)
299638fd1498Szrj {
299738fd1498Szrj gimple *g;
299838fd1498Szrj if (id == 0)
299938fd1498Szrj {
300038fd1498Szrj op = r->exp;
300138fd1498Szrj continue;
300238fd1498Szrj }
300338fd1498Szrj if (id == l)
300438fd1498Szrj {
300538fd1498Szrj g = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, op);
300638fd1498Szrj gimple_seq_add_stmt_without_update (&seq, g);
300738fd1498Szrj op = gimple_assign_lhs (g);
300838fd1498Szrj }
300938fd1498Szrj tree type = TREE_TYPE (r->exp);
301038fd1498Szrj tree exp = r->exp;
301138fd1498Szrj if (id >= l && !useless_type_conversion_p (type1, type))
301238fd1498Szrj {
301338fd1498Szrj g = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, exp);
301438fd1498Szrj gimple_seq_add_stmt_without_update (&seq, g);
301538fd1498Szrj exp = gimple_assign_lhs (g);
301638fd1498Szrj }
301738fd1498Szrj g = gimple_build_assign (make_ssa_name (id >= l ? type1 : type2),
301838fd1498Szrj (b & 1) ? BIT_AND_EXPR : BIT_IOR_EXPR,
301938fd1498Szrj op, exp);
302038fd1498Szrj gimple_seq_add_stmt_without_update (&seq, g);
302138fd1498Szrj op = gimple_assign_lhs (g);
302238fd1498Szrj }
302338fd1498Szrj candidates.pop ();
302438fd1498Szrj if (update_range_test (&ranges[k - 1], NULL, candidates.address (),
302538fd1498Szrj candidates.length (), opcode, ops, op,
302638fd1498Szrj seq, true, ranges[k - 1].low,
302738fd1498Szrj ranges[k - 1].low, strict_overflow_p))
302838fd1498Szrj any_changes = true;
302938fd1498Szrj else
303038fd1498Szrj gimple_seq_discard (seq);
303138fd1498Szrj }
303238fd1498Szrj
303338fd1498Szrj return any_changes;
303438fd1498Szrj }
303538fd1498Szrj
303638fd1498Szrj /* Attempt to optimize for signed a and b where b is known to be >= 0:
303738fd1498Szrj a >= 0 && a < b into (unsigned) a < (unsigned) b
303838fd1498Szrj a >= 0 && a <= b into (unsigned) a <= (unsigned) b */
303938fd1498Szrj
304038fd1498Szrj static bool
optimize_range_tests_var_bound(enum tree_code opcode,int first,int length,vec<operand_entry * > * ops,struct range_entry * ranges,basic_block first_bb)304138fd1498Szrj optimize_range_tests_var_bound (enum tree_code opcode, int first, int length,
304238fd1498Szrj vec<operand_entry *> *ops,
304338fd1498Szrj struct range_entry *ranges,
304438fd1498Szrj basic_block first_bb)
304538fd1498Szrj {
304638fd1498Szrj int i;
304738fd1498Szrj bool any_changes = false;
304838fd1498Szrj hash_map<tree, int> *map = NULL;
304938fd1498Szrj
305038fd1498Szrj for (i = first; i < length; i++)
305138fd1498Szrj {
305238fd1498Szrj if (ranges[i].exp == NULL_TREE
305338fd1498Szrj || TREE_CODE (ranges[i].exp) != SSA_NAME
305438fd1498Szrj || !ranges[i].in_p)
305538fd1498Szrj continue;
305638fd1498Szrj
305738fd1498Szrj tree type = TREE_TYPE (ranges[i].exp);
305838fd1498Szrj if (!INTEGRAL_TYPE_P (type)
305938fd1498Szrj || TYPE_UNSIGNED (type)
306038fd1498Szrj || ranges[i].low == NULL_TREE
306138fd1498Szrj || !integer_zerop (ranges[i].low)
306238fd1498Szrj || ranges[i].high != NULL_TREE)
306338fd1498Szrj continue;
306438fd1498Szrj /* EXP >= 0 here. */
306538fd1498Szrj if (map == NULL)
306638fd1498Szrj map = new hash_map <tree, int>;
306738fd1498Szrj map->put (ranges[i].exp, i);
306838fd1498Szrj }
306938fd1498Szrj
307038fd1498Szrj if (map == NULL)
307138fd1498Szrj return false;
307238fd1498Szrj
307338fd1498Szrj for (i = 0; i < length; i++)
307438fd1498Szrj {
307538fd1498Szrj bool in_p = ranges[i].in_p;
307638fd1498Szrj if (ranges[i].low == NULL_TREE
307738fd1498Szrj || ranges[i].high == NULL_TREE)
307838fd1498Szrj continue;
307938fd1498Szrj if (!integer_zerop (ranges[i].low)
308038fd1498Szrj || !integer_zerop (ranges[i].high))
308138fd1498Szrj {
308238fd1498Szrj if (ranges[i].exp
308338fd1498Szrj && TYPE_PRECISION (TREE_TYPE (ranges[i].exp)) == 1
308438fd1498Szrj && TYPE_UNSIGNED (TREE_TYPE (ranges[i].exp))
308538fd1498Szrj && integer_onep (ranges[i].low)
308638fd1498Szrj && integer_onep (ranges[i].high))
308738fd1498Szrj in_p = !in_p;
308838fd1498Szrj else
308938fd1498Szrj continue;
309038fd1498Szrj }
309138fd1498Szrj
309238fd1498Szrj gimple *stmt;
309338fd1498Szrj tree_code ccode;
309438fd1498Szrj tree rhs1, rhs2;
309538fd1498Szrj if (ranges[i].exp)
309638fd1498Szrj {
309738fd1498Szrj if (TREE_CODE (ranges[i].exp) != SSA_NAME)
309838fd1498Szrj continue;
309938fd1498Szrj stmt = SSA_NAME_DEF_STMT (ranges[i].exp);
310038fd1498Szrj if (!is_gimple_assign (stmt))
310138fd1498Szrj continue;
310238fd1498Szrj ccode = gimple_assign_rhs_code (stmt);
310338fd1498Szrj rhs1 = gimple_assign_rhs1 (stmt);
310438fd1498Szrj rhs2 = gimple_assign_rhs2 (stmt);
310538fd1498Szrj }
310638fd1498Szrj else
310738fd1498Szrj {
310838fd1498Szrj operand_entry *oe = (*ops)[ranges[i].idx];
310938fd1498Szrj stmt = last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id));
311038fd1498Szrj if (gimple_code (stmt) != GIMPLE_COND)
311138fd1498Szrj continue;
311238fd1498Szrj ccode = gimple_cond_code (stmt);
311338fd1498Szrj rhs1 = gimple_cond_lhs (stmt);
311438fd1498Szrj rhs2 = gimple_cond_rhs (stmt);
311538fd1498Szrj }
311638fd1498Szrj
311738fd1498Szrj if (TREE_CODE (rhs1) != SSA_NAME
311838fd1498Szrj || rhs2 == NULL_TREE
311938fd1498Szrj || TREE_CODE (rhs2) != SSA_NAME)
312038fd1498Szrj continue;
312138fd1498Szrj
312238fd1498Szrj switch (ccode)
312338fd1498Szrj {
312438fd1498Szrj case GT_EXPR:
312538fd1498Szrj case GE_EXPR:
312638fd1498Szrj case LT_EXPR:
312738fd1498Szrj case LE_EXPR:
312838fd1498Szrj break;
312938fd1498Szrj default:
313038fd1498Szrj continue;
313138fd1498Szrj }
313238fd1498Szrj if (in_p)
313338fd1498Szrj ccode = invert_tree_comparison (ccode, false);
313438fd1498Szrj switch (ccode)
313538fd1498Szrj {
313638fd1498Szrj case GT_EXPR:
313738fd1498Szrj case GE_EXPR:
313838fd1498Szrj std::swap (rhs1, rhs2);
313938fd1498Szrj ccode = swap_tree_comparison (ccode);
314038fd1498Szrj break;
314138fd1498Szrj case LT_EXPR:
314238fd1498Szrj case LE_EXPR:
314338fd1498Szrj break;
314438fd1498Szrj default:
314538fd1498Szrj gcc_unreachable ();
314638fd1498Szrj }
314738fd1498Szrj
314838fd1498Szrj int *idx = map->get (rhs1);
314938fd1498Szrj if (idx == NULL)
315038fd1498Szrj continue;
315138fd1498Szrj
315238fd1498Szrj /* maybe_optimize_range_tests allows statements without side-effects
315338fd1498Szrj in the basic blocks as long as they are consumed in the same bb.
315438fd1498Szrj Make sure rhs2's def stmt is not among them, otherwise we can't
315538fd1498Szrj use safely get_nonzero_bits on it. E.g. in:
315638fd1498Szrj # RANGE [-83, 1] NONZERO 173
315738fd1498Szrj # k_32 = PHI <k_47(13), k_12(9)>
315838fd1498Szrj ...
315938fd1498Szrj if (k_32 >= 0)
316038fd1498Szrj goto <bb 5>; [26.46%]
316138fd1498Szrj else
316238fd1498Szrj goto <bb 9>; [73.54%]
316338fd1498Szrj
316438fd1498Szrj <bb 5> [local count: 140323371]:
316538fd1498Szrj # RANGE [0, 1] NONZERO 1
316638fd1498Szrj _5 = (int) k_32;
316738fd1498Szrj # RANGE [0, 4] NONZERO 4
316838fd1498Szrj _21 = _5 << 2;
316938fd1498Szrj # RANGE [0, 4] NONZERO 4
317038fd1498Szrj iftmp.0_44 = (char) _21;
317138fd1498Szrj if (k_32 < iftmp.0_44)
317238fd1498Szrj goto <bb 6>; [84.48%]
317338fd1498Szrj else
317438fd1498Szrj goto <bb 9>; [15.52%]
317538fd1498Szrj the ranges on _5/_21/iftmp.0_44 are flow sensitive, assume that
317638fd1498Szrj k_32 >= 0. If we'd optimize k_32 >= 0 to true and k_32 < iftmp.0_44
317738fd1498Szrj to (unsigned) k_32 < (unsigned) iftmp.0_44, then we would execute
317838fd1498Szrj those stmts even for negative k_32 and the value ranges would be no
317938fd1498Szrj longer guaranteed and so the optimization would be invalid. */
318038fd1498Szrj if (opcode == ERROR_MARK)
318138fd1498Szrj {
318238fd1498Szrj gimple *g = SSA_NAME_DEF_STMT (rhs2);
318338fd1498Szrj basic_block bb2 = gimple_bb (g);
318438fd1498Szrj if (bb2
318538fd1498Szrj && bb2 != first_bb
318638fd1498Szrj && dominated_by_p (CDI_DOMINATORS, bb2, first_bb))
318738fd1498Szrj {
318838fd1498Szrj /* As an exception, handle a few common cases. */
318938fd1498Szrj if (gimple_assign_cast_p (g)
319038fd1498Szrj && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (g)))
319138fd1498Szrj && TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)))
319238fd1498Szrj && (TYPE_PRECISION (TREE_TYPE (rhs2))
319338fd1498Szrj > TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (g)))))
319438fd1498Szrj /* Zero-extension is always ok. */ ;
319538fd1498Szrj else if (is_gimple_assign (g)
319638fd1498Szrj && gimple_assign_rhs_code (g) == BIT_AND_EXPR
319738fd1498Szrj && TREE_CODE (gimple_assign_rhs2 (g)) == INTEGER_CST
319838fd1498Szrj && !wi::neg_p (wi::to_wide (gimple_assign_rhs2 (g))))
319938fd1498Szrj /* Masking with INTEGER_CST with MSB clear is always ok
320038fd1498Szrj too. */ ;
320138fd1498Szrj else
320238fd1498Szrj continue;
320338fd1498Szrj }
320438fd1498Szrj }
320538fd1498Szrj
320638fd1498Szrj wide_int nz = get_nonzero_bits (rhs2);
320738fd1498Szrj if (wi::neg_p (nz))
320838fd1498Szrj continue;
320938fd1498Szrj
321038fd1498Szrj /* We have EXP < RHS2 or EXP <= RHS2 where EXP >= 0
321138fd1498Szrj and RHS2 is known to be RHS2 >= 0. */
321238fd1498Szrj tree utype = unsigned_type_for (TREE_TYPE (rhs1));
321338fd1498Szrj
321438fd1498Szrj enum warn_strict_overflow_code wc = WARN_STRICT_OVERFLOW_COMPARISON;
321538fd1498Szrj if ((ranges[*idx].strict_overflow_p
321638fd1498Szrj || ranges[i].strict_overflow_p)
321738fd1498Szrj && issue_strict_overflow_warning (wc))
321838fd1498Szrj warning_at (gimple_location (stmt), OPT_Wstrict_overflow,
321938fd1498Szrj "assuming signed overflow does not occur "
322038fd1498Szrj "when simplifying range test");
322138fd1498Szrj
322238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
322338fd1498Szrj {
322438fd1498Szrj struct range_entry *r = &ranges[*idx];
322538fd1498Szrj fprintf (dump_file, "Optimizing range test ");
322638fd1498Szrj print_generic_expr (dump_file, r->exp);
322738fd1498Szrj fprintf (dump_file, " +[");
322838fd1498Szrj print_generic_expr (dump_file, r->low);
322938fd1498Szrj fprintf (dump_file, ", ");
323038fd1498Szrj print_generic_expr (dump_file, r->high);
323138fd1498Szrj fprintf (dump_file, "] and comparison ");
323238fd1498Szrj print_generic_expr (dump_file, rhs1);
323338fd1498Szrj fprintf (dump_file, " %s ", op_symbol_code (ccode));
323438fd1498Szrj print_generic_expr (dump_file, rhs2);
323538fd1498Szrj fprintf (dump_file, "\n into (");
323638fd1498Szrj print_generic_expr (dump_file, utype);
323738fd1498Szrj fprintf (dump_file, ") ");
323838fd1498Szrj print_generic_expr (dump_file, rhs1);
323938fd1498Szrj fprintf (dump_file, " %s (", op_symbol_code (ccode));
324038fd1498Szrj print_generic_expr (dump_file, utype);
324138fd1498Szrj fprintf (dump_file, ") ");
324238fd1498Szrj print_generic_expr (dump_file, rhs2);
324338fd1498Szrj fprintf (dump_file, "\n");
324438fd1498Szrj }
324538fd1498Szrj
324638fd1498Szrj operand_entry *oe = (*ops)[ranges[i].idx];
324738fd1498Szrj ranges[i].in_p = 0;
324838fd1498Szrj if (opcode == BIT_IOR_EXPR
324938fd1498Szrj || (opcode == ERROR_MARK && oe->rank == BIT_IOR_EXPR))
325038fd1498Szrj {
325138fd1498Szrj ranges[i].in_p = 1;
325238fd1498Szrj ccode = invert_tree_comparison (ccode, false);
325338fd1498Szrj }
325438fd1498Szrj
325538fd1498Szrj unsigned int uid = gimple_uid (stmt);
325638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
325738fd1498Szrj gimple *g = gimple_build_assign (make_ssa_name (utype), NOP_EXPR, rhs1);
325838fd1498Szrj gimple_set_uid (g, uid);
325938fd1498Szrj rhs1 = gimple_assign_lhs (g);
326038fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
326138fd1498Szrj g = gimple_build_assign (make_ssa_name (utype), NOP_EXPR, rhs2);
326238fd1498Szrj gimple_set_uid (g, uid);
326338fd1498Szrj rhs2 = gimple_assign_lhs (g);
326438fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
326538fd1498Szrj if (tree_swap_operands_p (rhs1, rhs2))
326638fd1498Szrj {
326738fd1498Szrj std::swap (rhs1, rhs2);
326838fd1498Szrj ccode = swap_tree_comparison (ccode);
326938fd1498Szrj }
327038fd1498Szrj if (gimple_code (stmt) == GIMPLE_COND)
327138fd1498Szrj {
327238fd1498Szrj gcond *c = as_a <gcond *> (stmt);
327338fd1498Szrj gimple_cond_set_code (c, ccode);
327438fd1498Szrj gimple_cond_set_lhs (c, rhs1);
327538fd1498Szrj gimple_cond_set_rhs (c, rhs2);
327638fd1498Szrj update_stmt (stmt);
327738fd1498Szrj }
327838fd1498Szrj else
327938fd1498Szrj {
328038fd1498Szrj tree ctype = oe->op ? TREE_TYPE (oe->op) : boolean_type_node;
328138fd1498Szrj if (!INTEGRAL_TYPE_P (ctype)
328238fd1498Szrj || (TREE_CODE (ctype) != BOOLEAN_TYPE
328338fd1498Szrj && TYPE_PRECISION (ctype) != 1))
328438fd1498Szrj ctype = boolean_type_node;
328538fd1498Szrj g = gimple_build_assign (make_ssa_name (ctype), ccode, rhs1, rhs2);
328638fd1498Szrj gimple_set_uid (g, uid);
328738fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
328838fd1498Szrj if (oe->op && ctype != TREE_TYPE (oe->op))
328938fd1498Szrj {
329038fd1498Szrj g = gimple_build_assign (make_ssa_name (TREE_TYPE (oe->op)),
329138fd1498Szrj NOP_EXPR, gimple_assign_lhs (g));
329238fd1498Szrj gimple_set_uid (g, uid);
329338fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
329438fd1498Szrj }
329538fd1498Szrj ranges[i].exp = gimple_assign_lhs (g);
329638fd1498Szrj oe->op = ranges[i].exp;
329738fd1498Szrj ranges[i].low = build_zero_cst (TREE_TYPE (ranges[i].exp));
329838fd1498Szrj ranges[i].high = ranges[i].low;
329938fd1498Szrj }
330038fd1498Szrj ranges[i].strict_overflow_p = false;
330138fd1498Szrj oe = (*ops)[ranges[*idx].idx];
330238fd1498Szrj /* Now change all the other range test immediate uses, so that
330338fd1498Szrj those tests will be optimized away. */
330438fd1498Szrj if (opcode == ERROR_MARK)
330538fd1498Szrj {
330638fd1498Szrj if (oe->op)
330738fd1498Szrj oe->op = build_int_cst (TREE_TYPE (oe->op),
330838fd1498Szrj oe->rank == BIT_IOR_EXPR ? 0 : 1);
330938fd1498Szrj else
331038fd1498Szrj oe->op = (oe->rank == BIT_IOR_EXPR
331138fd1498Szrj ? boolean_false_node : boolean_true_node);
331238fd1498Szrj }
331338fd1498Szrj else
331438fd1498Szrj oe->op = error_mark_node;
331538fd1498Szrj ranges[*idx].exp = NULL_TREE;
331638fd1498Szrj ranges[*idx].low = NULL_TREE;
331738fd1498Szrj ranges[*idx].high = NULL_TREE;
331838fd1498Szrj any_changes = true;
331938fd1498Szrj }
332038fd1498Szrj
332138fd1498Szrj delete map;
332238fd1498Szrj return any_changes;
332338fd1498Szrj }
332438fd1498Szrj
332538fd1498Szrj /* Optimize range tests, similarly how fold_range_test optimizes
332638fd1498Szrj it on trees. The tree code for the binary
332738fd1498Szrj operation between all the operands is OPCODE.
332838fd1498Szrj If OPCODE is ERROR_MARK, optimize_range_tests is called from within
332938fd1498Szrj maybe_optimize_range_tests for inter-bb range optimization.
333038fd1498Szrj In that case if oe->op is NULL, oe->id is bb->index whose
333138fd1498Szrj GIMPLE_COND is && or ||ed into the test, and oe->rank says
333238fd1498Szrj the actual opcode.
333338fd1498Szrj FIRST_BB is the first basic block if OPCODE is ERROR_MARK. */
333438fd1498Szrj
333538fd1498Szrj static bool
optimize_range_tests(enum tree_code opcode,vec<operand_entry * > * ops,basic_block first_bb)333638fd1498Szrj optimize_range_tests (enum tree_code opcode,
333738fd1498Szrj vec<operand_entry *> *ops, basic_block first_bb)
333838fd1498Szrj {
333938fd1498Szrj unsigned int length = ops->length (), i, j, first;
334038fd1498Szrj operand_entry *oe;
334138fd1498Szrj struct range_entry *ranges;
334238fd1498Szrj bool any_changes = false;
334338fd1498Szrj
334438fd1498Szrj if (length == 1)
334538fd1498Szrj return false;
334638fd1498Szrj
334738fd1498Szrj ranges = XNEWVEC (struct range_entry, length);
334838fd1498Szrj for (i = 0; i < length; i++)
334938fd1498Szrj {
335038fd1498Szrj oe = (*ops)[i];
335138fd1498Szrj ranges[i].idx = i;
335238fd1498Szrj init_range_entry (ranges + i, oe->op,
335338fd1498Szrj oe->op
335438fd1498Szrj ? NULL
335538fd1498Szrj : last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id)));
335638fd1498Szrj /* For | invert it now, we will invert it again before emitting
335738fd1498Szrj the optimized expression. */
335838fd1498Szrj if (opcode == BIT_IOR_EXPR
335938fd1498Szrj || (opcode == ERROR_MARK && oe->rank == BIT_IOR_EXPR))
336038fd1498Szrj ranges[i].in_p = !ranges[i].in_p;
336138fd1498Szrj }
336238fd1498Szrj
336338fd1498Szrj qsort (ranges, length, sizeof (*ranges), range_entry_cmp);
336438fd1498Szrj for (i = 0; i < length; i++)
336538fd1498Szrj if (ranges[i].exp != NULL_TREE && TREE_CODE (ranges[i].exp) == SSA_NAME)
336638fd1498Szrj break;
336738fd1498Szrj
336838fd1498Szrj /* Try to merge ranges. */
336938fd1498Szrj for (first = i; i < length; i++)
337038fd1498Szrj {
337138fd1498Szrj tree low = ranges[i].low;
337238fd1498Szrj tree high = ranges[i].high;
337338fd1498Szrj int in_p = ranges[i].in_p;
337438fd1498Szrj bool strict_overflow_p = ranges[i].strict_overflow_p;
337538fd1498Szrj int update_fail_count = 0;
337638fd1498Szrj
337738fd1498Szrj for (j = i + 1; j < length; j++)
337838fd1498Szrj {
337938fd1498Szrj if (ranges[i].exp != ranges[j].exp)
338038fd1498Szrj break;
338138fd1498Szrj if (!merge_ranges (&in_p, &low, &high, in_p, low, high,
338238fd1498Szrj ranges[j].in_p, ranges[j].low, ranges[j].high))
338338fd1498Szrj break;
338438fd1498Szrj strict_overflow_p |= ranges[j].strict_overflow_p;
338538fd1498Szrj }
338638fd1498Szrj
338738fd1498Szrj if (j == i + 1)
338838fd1498Szrj continue;
338938fd1498Szrj
339038fd1498Szrj if (update_range_test (ranges + i, ranges + i + 1, NULL, j - i - 1,
339138fd1498Szrj opcode, ops, ranges[i].exp, NULL, in_p,
339238fd1498Szrj low, high, strict_overflow_p))
339338fd1498Szrj {
339438fd1498Szrj i = j - 1;
339538fd1498Szrj any_changes = true;
339638fd1498Szrj }
339738fd1498Szrj /* Avoid quadratic complexity if all merge_ranges calls would succeed,
339838fd1498Szrj while update_range_test would fail. */
339938fd1498Szrj else if (update_fail_count == 64)
340038fd1498Szrj i = j - 1;
340138fd1498Szrj else
340238fd1498Szrj ++update_fail_count;
340338fd1498Szrj }
340438fd1498Szrj
340538fd1498Szrj any_changes |= optimize_range_tests_1 (opcode, first, length, true,
340638fd1498Szrj ops, ranges);
340738fd1498Szrj
340838fd1498Szrj if (BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2)
340938fd1498Szrj any_changes |= optimize_range_tests_1 (opcode, first, length, false,
341038fd1498Szrj ops, ranges);
341138fd1498Szrj if (lshift_cheap_p (optimize_function_for_speed_p (cfun)))
341238fd1498Szrj any_changes |= optimize_range_tests_to_bit_test (opcode, first, length,
341338fd1498Szrj ops, ranges);
341438fd1498Szrj any_changes |= optimize_range_tests_cmp_bitwise (opcode, first, length,
341538fd1498Szrj ops, ranges);
341638fd1498Szrj any_changes |= optimize_range_tests_var_bound (opcode, first, length, ops,
341738fd1498Szrj ranges, first_bb);
341838fd1498Szrj
341938fd1498Szrj if (any_changes && opcode != ERROR_MARK)
342038fd1498Szrj {
342138fd1498Szrj j = 0;
342238fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe)
342338fd1498Szrj {
342438fd1498Szrj if (oe->op == error_mark_node)
342538fd1498Szrj continue;
342638fd1498Szrj else if (i != j)
342738fd1498Szrj (*ops)[j] = oe;
342838fd1498Szrj j++;
342938fd1498Szrj }
343038fd1498Szrj ops->truncate (j);
343138fd1498Szrj }
343238fd1498Szrj
343338fd1498Szrj XDELETEVEC (ranges);
343438fd1498Szrj return any_changes;
343538fd1498Szrj }
343638fd1498Szrj
343738fd1498Szrj /* A subroutine of optimize_vec_cond_expr to extract and canonicalize
343838fd1498Szrj the operands of the VEC_COND_EXPR. Returns ERROR_MARK on failure,
343938fd1498Szrj otherwise the comparison code. */
344038fd1498Szrj
344138fd1498Szrj static tree_code
ovce_extract_ops(tree var,gassign ** rets,bool * reti)344238fd1498Szrj ovce_extract_ops (tree var, gassign **rets, bool *reti)
344338fd1498Szrj {
344438fd1498Szrj if (TREE_CODE (var) != SSA_NAME)
344538fd1498Szrj return ERROR_MARK;
344638fd1498Szrj
344738fd1498Szrj gassign *stmt = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (var));
344838fd1498Szrj if (stmt == NULL)
344938fd1498Szrj return ERROR_MARK;
345038fd1498Szrj
345138fd1498Szrj /* ??? If we start creating more COND_EXPR, we could perform
345238fd1498Szrj this same optimization with them. For now, simplify. */
345338fd1498Szrj if (gimple_assign_rhs_code (stmt) != VEC_COND_EXPR)
345438fd1498Szrj return ERROR_MARK;
345538fd1498Szrj
345638fd1498Szrj tree cond = gimple_assign_rhs1 (stmt);
345738fd1498Szrj tree_code cmp = TREE_CODE (cond);
345838fd1498Szrj if (TREE_CODE_CLASS (cmp) != tcc_comparison)
345938fd1498Szrj return ERROR_MARK;
346038fd1498Szrj
346138fd1498Szrj /* ??? For now, allow only canonical true and false result vectors.
346238fd1498Szrj We could expand this to other constants should the need arise,
346338fd1498Szrj but at the moment we don't create them. */
346438fd1498Szrj tree t = gimple_assign_rhs2 (stmt);
346538fd1498Szrj tree f = gimple_assign_rhs3 (stmt);
346638fd1498Szrj bool inv;
346738fd1498Szrj if (integer_all_onesp (t))
346838fd1498Szrj inv = false;
346938fd1498Szrj else if (integer_all_onesp (f))
347038fd1498Szrj {
347138fd1498Szrj cmp = invert_tree_comparison (cmp, false);
347238fd1498Szrj inv = true;
347338fd1498Szrj }
347438fd1498Szrj else
347538fd1498Szrj return ERROR_MARK;
347638fd1498Szrj if (!integer_zerop (f))
347738fd1498Szrj return ERROR_MARK;
347838fd1498Szrj
347938fd1498Szrj /* Success! */
348038fd1498Szrj if (rets)
348138fd1498Szrj *rets = stmt;
348238fd1498Szrj if (reti)
348338fd1498Szrj *reti = inv;
348438fd1498Szrj return cmp;
348538fd1498Szrj }
348638fd1498Szrj
348738fd1498Szrj /* Optimize the condition of VEC_COND_EXPRs which have been combined
348838fd1498Szrj with OPCODE (either BIT_AND_EXPR or BIT_IOR_EXPR). */
348938fd1498Szrj
349038fd1498Szrj static bool
optimize_vec_cond_expr(tree_code opcode,vec<operand_entry * > * ops)349138fd1498Szrj optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
349238fd1498Szrj {
349338fd1498Szrj unsigned int length = ops->length (), i, j;
349438fd1498Szrj bool any_changes = false;
349538fd1498Szrj
349638fd1498Szrj if (length == 1)
349738fd1498Szrj return false;
349838fd1498Szrj
349938fd1498Szrj for (i = 0; i < length; ++i)
350038fd1498Szrj {
350138fd1498Szrj tree elt0 = (*ops)[i]->op;
350238fd1498Szrj
350338fd1498Szrj gassign *stmt0;
350438fd1498Szrj bool invert;
350538fd1498Szrj tree_code cmp0 = ovce_extract_ops (elt0, &stmt0, &invert);
350638fd1498Szrj if (cmp0 == ERROR_MARK)
350738fd1498Szrj continue;
350838fd1498Szrj
350938fd1498Szrj for (j = i + 1; j < length; ++j)
351038fd1498Szrj {
351138fd1498Szrj tree &elt1 = (*ops)[j]->op;
351238fd1498Szrj
351338fd1498Szrj gassign *stmt1;
351438fd1498Szrj tree_code cmp1 = ovce_extract_ops (elt1, &stmt1, NULL);
351538fd1498Szrj if (cmp1 == ERROR_MARK)
351638fd1498Szrj continue;
351738fd1498Szrj
351838fd1498Szrj tree cond0 = gimple_assign_rhs1 (stmt0);
351938fd1498Szrj tree x0 = TREE_OPERAND (cond0, 0);
352038fd1498Szrj tree y0 = TREE_OPERAND (cond0, 1);
352138fd1498Szrj
352238fd1498Szrj tree cond1 = gimple_assign_rhs1 (stmt1);
352338fd1498Szrj tree x1 = TREE_OPERAND (cond1, 0);
352438fd1498Szrj tree y1 = TREE_OPERAND (cond1, 1);
352538fd1498Szrj
352638fd1498Szrj tree comb;
352738fd1498Szrj if (opcode == BIT_AND_EXPR)
352838fd1498Szrj comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
352938fd1498Szrj else if (opcode == BIT_IOR_EXPR)
353038fd1498Szrj comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
353138fd1498Szrj else
353238fd1498Szrj gcc_unreachable ();
353338fd1498Szrj if (comb == NULL)
353438fd1498Szrj continue;
353538fd1498Szrj
353638fd1498Szrj /* Success! */
353738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
353838fd1498Szrj {
353938fd1498Szrj fprintf (dump_file, "Transforming ");
354038fd1498Szrj print_generic_expr (dump_file, cond0);
354138fd1498Szrj fprintf (dump_file, " %c ", opcode == BIT_AND_EXPR ? '&' : '|');
354238fd1498Szrj print_generic_expr (dump_file, cond1);
354338fd1498Szrj fprintf (dump_file, " into ");
354438fd1498Szrj print_generic_expr (dump_file, comb);
354538fd1498Szrj fputc ('\n', dump_file);
354638fd1498Szrj }
354738fd1498Szrj
354838fd1498Szrj gimple_assign_set_rhs1 (stmt0, comb);
354938fd1498Szrj if (invert)
355038fd1498Szrj std::swap (*gimple_assign_rhs2_ptr (stmt0),
355138fd1498Szrj *gimple_assign_rhs3_ptr (stmt0));
355238fd1498Szrj update_stmt (stmt0);
355338fd1498Szrj
355438fd1498Szrj elt1 = error_mark_node;
355538fd1498Szrj any_changes = true;
355638fd1498Szrj }
355738fd1498Szrj }
355838fd1498Szrj
355938fd1498Szrj if (any_changes)
356038fd1498Szrj {
356138fd1498Szrj operand_entry *oe;
356238fd1498Szrj j = 0;
356338fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe)
356438fd1498Szrj {
356538fd1498Szrj if (oe->op == error_mark_node)
356638fd1498Szrj continue;
356738fd1498Szrj else if (i != j)
356838fd1498Szrj (*ops)[j] = oe;
356938fd1498Szrj j++;
357038fd1498Szrj }
357138fd1498Szrj ops->truncate (j);
357238fd1498Szrj }
357338fd1498Szrj
357438fd1498Szrj return any_changes;
357538fd1498Szrj }
357638fd1498Szrj
357738fd1498Szrj /* Return true if STMT is a cast like:
357838fd1498Szrj <bb N>:
357938fd1498Szrj ...
358038fd1498Szrj _123 = (int) _234;
358138fd1498Szrj
358238fd1498Szrj <bb M>:
358338fd1498Szrj # _345 = PHI <_123(N), 1(...), 1(...)>
358438fd1498Szrj where _234 has bool type, _123 has single use and
358538fd1498Szrj bb N has a single successor M. This is commonly used in
358638fd1498Szrj the last block of a range test.
358738fd1498Szrj
358838fd1498Szrj Also Return true if STMT is tcc_compare like:
358938fd1498Szrj <bb N>:
359038fd1498Szrj ...
359138fd1498Szrj _234 = a_2(D) == 2;
359238fd1498Szrj
359338fd1498Szrj <bb M>:
359438fd1498Szrj # _345 = PHI <_234(N), 1(...), 1(...)>
359538fd1498Szrj _346 = (int) _345;
359638fd1498Szrj where _234 has booltype, single use and
359738fd1498Szrj bb N has a single successor M. This is commonly used in
359838fd1498Szrj the last block of a range test. */
359938fd1498Szrj
360038fd1498Szrj static bool
final_range_test_p(gimple * stmt)360138fd1498Szrj final_range_test_p (gimple *stmt)
360238fd1498Szrj {
360338fd1498Szrj basic_block bb, rhs_bb, lhs_bb;
360438fd1498Szrj edge e;
360538fd1498Szrj tree lhs, rhs;
360638fd1498Szrj use_operand_p use_p;
360738fd1498Szrj gimple *use_stmt;
360838fd1498Szrj
360938fd1498Szrj if (!gimple_assign_cast_p (stmt)
361038fd1498Szrj && (!is_gimple_assign (stmt)
361138fd1498Szrj || (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
361238fd1498Szrj != tcc_comparison)))
361338fd1498Szrj return false;
361438fd1498Szrj bb = gimple_bb (stmt);
361538fd1498Szrj if (!single_succ_p (bb))
361638fd1498Szrj return false;
361738fd1498Szrj e = single_succ_edge (bb);
361838fd1498Szrj if (e->flags & EDGE_COMPLEX)
361938fd1498Szrj return false;
362038fd1498Szrj
362138fd1498Szrj lhs = gimple_assign_lhs (stmt);
362238fd1498Szrj rhs = gimple_assign_rhs1 (stmt);
362338fd1498Szrj if (gimple_assign_cast_p (stmt)
362438fd1498Szrj && (!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
362538fd1498Szrj || TREE_CODE (rhs) != SSA_NAME
362638fd1498Szrj || TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE))
362738fd1498Szrj return false;
362838fd1498Szrj
362938fd1498Szrj if (!gimple_assign_cast_p (stmt)
363038fd1498Szrj && (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE))
363138fd1498Szrj return false;
363238fd1498Szrj
363338fd1498Szrj /* Test whether lhs is consumed only by a PHI in the only successor bb. */
363438fd1498Szrj if (!single_imm_use (lhs, &use_p, &use_stmt))
363538fd1498Szrj return false;
363638fd1498Szrj
363738fd1498Szrj if (gimple_code (use_stmt) != GIMPLE_PHI
363838fd1498Szrj || gimple_bb (use_stmt) != e->dest)
363938fd1498Szrj return false;
364038fd1498Szrj
364138fd1498Szrj /* And that the rhs is defined in the same loop. */
364238fd1498Szrj if (gimple_assign_cast_p (stmt))
364338fd1498Szrj {
364438fd1498Szrj if (TREE_CODE (rhs) != SSA_NAME
364538fd1498Szrj || !(rhs_bb = gimple_bb (SSA_NAME_DEF_STMT (rhs)))
364638fd1498Szrj || !flow_bb_inside_loop_p (loop_containing_stmt (stmt), rhs_bb))
364738fd1498Szrj return false;
364838fd1498Szrj }
364938fd1498Szrj else
365038fd1498Szrj {
365138fd1498Szrj if (TREE_CODE (lhs) != SSA_NAME
365238fd1498Szrj || !(lhs_bb = gimple_bb (SSA_NAME_DEF_STMT (lhs)))
365338fd1498Szrj || !flow_bb_inside_loop_p (loop_containing_stmt (stmt), lhs_bb))
365438fd1498Szrj return false;
365538fd1498Szrj }
365638fd1498Szrj
365738fd1498Szrj return true;
365838fd1498Szrj }
365938fd1498Szrj
366038fd1498Szrj /* Return true if BB is suitable basic block for inter-bb range test
366138fd1498Szrj optimization. If BACKWARD is true, BB should be the only predecessor
366238fd1498Szrj of TEST_BB, and *OTHER_BB is either NULL and filled by the routine,
366338fd1498Szrj or compared with to find a common basic block to which all conditions
366438fd1498Szrj branch to if true resp. false. If BACKWARD is false, TEST_BB should
366538fd1498Szrj be the only predecessor of BB. */
366638fd1498Szrj
366738fd1498Szrj static bool
suitable_cond_bb(basic_block bb,basic_block test_bb,basic_block * other_bb,bool backward)366838fd1498Szrj suitable_cond_bb (basic_block bb, basic_block test_bb, basic_block *other_bb,
366938fd1498Szrj bool backward)
367038fd1498Szrj {
367138fd1498Szrj edge_iterator ei, ei2;
367238fd1498Szrj edge e, e2;
367338fd1498Szrj gimple *stmt;
367438fd1498Szrj gphi_iterator gsi;
367538fd1498Szrj bool other_edge_seen = false;
367638fd1498Szrj bool is_cond;
367738fd1498Szrj
367838fd1498Szrj if (test_bb == bb)
367938fd1498Szrj return false;
368038fd1498Szrj /* Check last stmt first. */
368138fd1498Szrj stmt = last_stmt (bb);
368238fd1498Szrj if (stmt == NULL
368338fd1498Szrj || (gimple_code (stmt) != GIMPLE_COND
368438fd1498Szrj && (backward || !final_range_test_p (stmt)))
368538fd1498Szrj || gimple_visited_p (stmt)
368638fd1498Szrj || stmt_could_throw_p (stmt)
368738fd1498Szrj || *other_bb == bb)
368838fd1498Szrj return false;
368938fd1498Szrj is_cond = gimple_code (stmt) == GIMPLE_COND;
369038fd1498Szrj if (is_cond)
369138fd1498Szrj {
369238fd1498Szrj /* If last stmt is GIMPLE_COND, verify that one of the succ edges
369338fd1498Szrj goes to the next bb (if BACKWARD, it is TEST_BB), and the other
369438fd1498Szrj to *OTHER_BB (if not set yet, try to find it out). */
369538fd1498Szrj if (EDGE_COUNT (bb->succs) != 2)
369638fd1498Szrj return false;
369738fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
369838fd1498Szrj {
369938fd1498Szrj if (!(e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
370038fd1498Szrj return false;
370138fd1498Szrj if (e->dest == test_bb)
370238fd1498Szrj {
370338fd1498Szrj if (backward)
370438fd1498Szrj continue;
370538fd1498Szrj else
370638fd1498Szrj return false;
370738fd1498Szrj }
370838fd1498Szrj if (e->dest == bb)
370938fd1498Szrj return false;
371038fd1498Szrj if (*other_bb == NULL)
371138fd1498Szrj {
371238fd1498Szrj FOR_EACH_EDGE (e2, ei2, test_bb->succs)
371338fd1498Szrj if (!(e2->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
371438fd1498Szrj return false;
371538fd1498Szrj else if (e->dest == e2->dest)
371638fd1498Szrj *other_bb = e->dest;
371738fd1498Szrj if (*other_bb == NULL)
371838fd1498Szrj return false;
371938fd1498Szrj }
372038fd1498Szrj if (e->dest == *other_bb)
372138fd1498Szrj other_edge_seen = true;
372238fd1498Szrj else if (backward)
372338fd1498Szrj return false;
372438fd1498Szrj }
372538fd1498Szrj if (*other_bb == NULL || !other_edge_seen)
372638fd1498Szrj return false;
372738fd1498Szrj }
372838fd1498Szrj else if (single_succ (bb) != *other_bb)
372938fd1498Szrj return false;
373038fd1498Szrj
373138fd1498Szrj /* Now check all PHIs of *OTHER_BB. */
373238fd1498Szrj e = find_edge (bb, *other_bb);
373338fd1498Szrj e2 = find_edge (test_bb, *other_bb);
373438fd1498Szrj for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
373538fd1498Szrj {
373638fd1498Szrj gphi *phi = gsi.phi ();
373738fd1498Szrj /* If both BB and TEST_BB end with GIMPLE_COND, all PHI arguments
373838fd1498Szrj corresponding to BB and TEST_BB predecessor must be the same. */
373938fd1498Szrj if (!operand_equal_p (gimple_phi_arg_def (phi, e->dest_idx),
374038fd1498Szrj gimple_phi_arg_def (phi, e2->dest_idx), 0))
374138fd1498Szrj {
374238fd1498Szrj /* Otherwise, if one of the blocks doesn't end with GIMPLE_COND,
374338fd1498Szrj one of the PHIs should have the lhs of the last stmt in
374438fd1498Szrj that block as PHI arg and that PHI should have 0 or 1
374538fd1498Szrj corresponding to it in all other range test basic blocks
374638fd1498Szrj considered. */
374738fd1498Szrj if (!is_cond)
374838fd1498Szrj {
374938fd1498Szrj if (gimple_phi_arg_def (phi, e->dest_idx)
375038fd1498Szrj == gimple_assign_lhs (stmt)
375138fd1498Szrj && (integer_zerop (gimple_phi_arg_def (phi, e2->dest_idx))
375238fd1498Szrj || integer_onep (gimple_phi_arg_def (phi,
375338fd1498Szrj e2->dest_idx))))
375438fd1498Szrj continue;
375538fd1498Szrj }
375638fd1498Szrj else
375738fd1498Szrj {
375838fd1498Szrj gimple *test_last = last_stmt (test_bb);
375938fd1498Szrj if (gimple_code (test_last) != GIMPLE_COND
376038fd1498Szrj && gimple_phi_arg_def (phi, e2->dest_idx)
376138fd1498Szrj == gimple_assign_lhs (test_last)
376238fd1498Szrj && (integer_zerop (gimple_phi_arg_def (phi, e->dest_idx))
376338fd1498Szrj || integer_onep (gimple_phi_arg_def (phi, e->dest_idx))))
376438fd1498Szrj continue;
376538fd1498Szrj }
376638fd1498Szrj
376738fd1498Szrj return false;
376838fd1498Szrj }
376938fd1498Szrj }
377038fd1498Szrj return true;
377138fd1498Szrj }
377238fd1498Szrj
377338fd1498Szrj /* Return true if BB doesn't have side-effects that would disallow
377438fd1498Szrj range test optimization, all SSA_NAMEs set in the bb are consumed
377538fd1498Szrj in the bb and there are no PHIs. */
377638fd1498Szrj
377738fd1498Szrj static bool
no_side_effect_bb(basic_block bb)377838fd1498Szrj no_side_effect_bb (basic_block bb)
377938fd1498Szrj {
378038fd1498Szrj gimple_stmt_iterator gsi;
378138fd1498Szrj gimple *last;
378238fd1498Szrj
378338fd1498Szrj if (!gimple_seq_empty_p (phi_nodes (bb)))
378438fd1498Szrj return false;
378538fd1498Szrj last = last_stmt (bb);
378638fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
378738fd1498Szrj {
378838fd1498Szrj gimple *stmt = gsi_stmt (gsi);
378938fd1498Szrj tree lhs;
379038fd1498Szrj imm_use_iterator imm_iter;
379138fd1498Szrj use_operand_p use_p;
379238fd1498Szrj
379338fd1498Szrj if (is_gimple_debug (stmt))
379438fd1498Szrj continue;
379538fd1498Szrj if (gimple_has_side_effects (stmt))
379638fd1498Szrj return false;
379738fd1498Szrj if (stmt == last)
379838fd1498Szrj return true;
379938fd1498Szrj if (!is_gimple_assign (stmt))
380038fd1498Szrj return false;
380138fd1498Szrj lhs = gimple_assign_lhs (stmt);
380238fd1498Szrj if (TREE_CODE (lhs) != SSA_NAME)
380338fd1498Szrj return false;
380438fd1498Szrj if (gimple_assign_rhs_could_trap_p (stmt))
380538fd1498Szrj return false;
380638fd1498Szrj FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
380738fd1498Szrj {
380838fd1498Szrj gimple *use_stmt = USE_STMT (use_p);
380938fd1498Szrj if (is_gimple_debug (use_stmt))
381038fd1498Szrj continue;
381138fd1498Szrj if (gimple_bb (use_stmt) != bb)
381238fd1498Szrj return false;
381338fd1498Szrj }
381438fd1498Szrj }
381538fd1498Szrj return false;
381638fd1498Szrj }
381738fd1498Szrj
381838fd1498Szrj /* If VAR is set by CODE (BIT_{AND,IOR}_EXPR) which is reassociable,
381938fd1498Szrj return true and fill in *OPS recursively. */
382038fd1498Szrj
382138fd1498Szrj static bool
get_ops(tree var,enum tree_code code,vec<operand_entry * > * ops,struct loop * loop)382238fd1498Szrj get_ops (tree var, enum tree_code code, vec<operand_entry *> *ops,
382338fd1498Szrj struct loop *loop)
382438fd1498Szrj {
382538fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (var);
382638fd1498Szrj tree rhs[2];
382738fd1498Szrj int i;
382838fd1498Szrj
382938fd1498Szrj if (!is_reassociable_op (stmt, code, loop))
383038fd1498Szrj return false;
383138fd1498Szrj
383238fd1498Szrj rhs[0] = gimple_assign_rhs1 (stmt);
383338fd1498Szrj rhs[1] = gimple_assign_rhs2 (stmt);
383438fd1498Szrj gimple_set_visited (stmt, true);
383538fd1498Szrj for (i = 0; i < 2; i++)
383638fd1498Szrj if (TREE_CODE (rhs[i]) == SSA_NAME
383738fd1498Szrj && !get_ops (rhs[i], code, ops, loop)
383838fd1498Szrj && has_single_use (rhs[i]))
383938fd1498Szrj {
384038fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
384138fd1498Szrj
384238fd1498Szrj oe->op = rhs[i];
384338fd1498Szrj oe->rank = code;
384438fd1498Szrj oe->id = 0;
384538fd1498Szrj oe->count = 1;
384638fd1498Szrj oe->stmt_to_insert = NULL;
384738fd1498Szrj ops->safe_push (oe);
384838fd1498Szrj }
384938fd1498Szrj return true;
385038fd1498Szrj }
385138fd1498Szrj
385238fd1498Szrj /* Find the ops that were added by get_ops starting from VAR, see if
385338fd1498Szrj they were changed during update_range_test and if yes, create new
385438fd1498Szrj stmts. */
385538fd1498Szrj
385638fd1498Szrj static tree
update_ops(tree var,enum tree_code code,vec<operand_entry * > ops,unsigned int * pidx,struct loop * loop)385738fd1498Szrj update_ops (tree var, enum tree_code code, vec<operand_entry *> ops,
385838fd1498Szrj unsigned int *pidx, struct loop *loop)
385938fd1498Szrj {
386038fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (var);
386138fd1498Szrj tree rhs[4];
386238fd1498Szrj int i;
386338fd1498Szrj
386438fd1498Szrj if (!is_reassociable_op (stmt, code, loop))
386538fd1498Szrj return NULL;
386638fd1498Szrj
386738fd1498Szrj rhs[0] = gimple_assign_rhs1 (stmt);
386838fd1498Szrj rhs[1] = gimple_assign_rhs2 (stmt);
386938fd1498Szrj rhs[2] = rhs[0];
387038fd1498Szrj rhs[3] = rhs[1];
387138fd1498Szrj for (i = 0; i < 2; i++)
387238fd1498Szrj if (TREE_CODE (rhs[i]) == SSA_NAME)
387338fd1498Szrj {
387438fd1498Szrj rhs[2 + i] = update_ops (rhs[i], code, ops, pidx, loop);
387538fd1498Szrj if (rhs[2 + i] == NULL_TREE)
387638fd1498Szrj {
387738fd1498Szrj if (has_single_use (rhs[i]))
387838fd1498Szrj rhs[2 + i] = ops[(*pidx)++]->op;
387938fd1498Szrj else
388038fd1498Szrj rhs[2 + i] = rhs[i];
388138fd1498Szrj }
388238fd1498Szrj }
388338fd1498Szrj if ((rhs[2] != rhs[0] || rhs[3] != rhs[1])
388438fd1498Szrj && (rhs[2] != rhs[1] || rhs[3] != rhs[0]))
388538fd1498Szrj {
388638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
388738fd1498Szrj var = make_ssa_name (TREE_TYPE (var));
388838fd1498Szrj gassign *g = gimple_build_assign (var, gimple_assign_rhs_code (stmt),
388938fd1498Szrj rhs[2], rhs[3]);
389038fd1498Szrj gimple_set_uid (g, gimple_uid (stmt));
389138fd1498Szrj gimple_set_visited (g, true);
389238fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
389338fd1498Szrj }
389438fd1498Szrj return var;
389538fd1498Szrj }
389638fd1498Szrj
389738fd1498Szrj /* Structure to track the initial value passed to get_ops and
389838fd1498Szrj the range in the ops vector for each basic block. */
389938fd1498Szrj
390038fd1498Szrj struct inter_bb_range_test_entry
390138fd1498Szrj {
390238fd1498Szrj tree op;
390338fd1498Szrj unsigned int first_idx, last_idx;
390438fd1498Szrj };
390538fd1498Szrj
390638fd1498Szrj /* Inter-bb range test optimization.
390738fd1498Szrj
390838fd1498Szrj Returns TRUE if a gimple conditional is optimized to a true/false,
390938fd1498Szrj otherwise return FALSE.
391038fd1498Szrj
391138fd1498Szrj This indicates to the caller that it should run a CFG cleanup pass
391238fd1498Szrj once reassociation is completed. */
391338fd1498Szrj
391438fd1498Szrj static bool
maybe_optimize_range_tests(gimple * stmt)391538fd1498Szrj maybe_optimize_range_tests (gimple *stmt)
391638fd1498Szrj {
391738fd1498Szrj basic_block first_bb = gimple_bb (stmt);
391838fd1498Szrj basic_block last_bb = first_bb;
391938fd1498Szrj basic_block other_bb = NULL;
392038fd1498Szrj basic_block bb;
392138fd1498Szrj edge_iterator ei;
392238fd1498Szrj edge e;
392338fd1498Szrj auto_vec<operand_entry *> ops;
392438fd1498Szrj auto_vec<inter_bb_range_test_entry> bbinfo;
392538fd1498Szrj bool any_changes = false;
392638fd1498Szrj bool cfg_cleanup_needed = false;
392738fd1498Szrj
392838fd1498Szrj /* Consider only basic blocks that end with GIMPLE_COND or
392938fd1498Szrj a cast statement satisfying final_range_test_p. All
393038fd1498Szrj but the last bb in the first_bb .. last_bb range
393138fd1498Szrj should end with GIMPLE_COND. */
393238fd1498Szrj if (gimple_code (stmt) == GIMPLE_COND)
393338fd1498Szrj {
393438fd1498Szrj if (EDGE_COUNT (first_bb->succs) != 2)
393538fd1498Szrj return cfg_cleanup_needed;
393638fd1498Szrj }
393738fd1498Szrj else if (final_range_test_p (stmt))
393838fd1498Szrj other_bb = single_succ (first_bb);
393938fd1498Szrj else
394038fd1498Szrj return cfg_cleanup_needed;
394138fd1498Szrj
394238fd1498Szrj if (stmt_could_throw_p (stmt))
394338fd1498Szrj return cfg_cleanup_needed;
394438fd1498Szrj
394538fd1498Szrj /* As relative ordering of post-dominator sons isn't fixed,
394638fd1498Szrj maybe_optimize_range_tests can be called first on any
394738fd1498Szrj bb in the range we want to optimize. So, start searching
394838fd1498Szrj backwards, if first_bb can be set to a predecessor. */
394938fd1498Szrj while (single_pred_p (first_bb))
395038fd1498Szrj {
395138fd1498Szrj basic_block pred_bb = single_pred (first_bb);
395238fd1498Szrj if (!suitable_cond_bb (pred_bb, first_bb, &other_bb, true))
395338fd1498Szrj break;
395438fd1498Szrj if (!no_side_effect_bb (first_bb))
395538fd1498Szrj break;
395638fd1498Szrj first_bb = pred_bb;
395738fd1498Szrj }
395838fd1498Szrj /* If first_bb is last_bb, other_bb hasn't been computed yet.
395938fd1498Szrj Before starting forward search in last_bb successors, find
396038fd1498Szrj out the other_bb. */
396138fd1498Szrj if (first_bb == last_bb)
396238fd1498Szrj {
396338fd1498Szrj other_bb = NULL;
396438fd1498Szrj /* As non-GIMPLE_COND last stmt always terminates the range,
396538fd1498Szrj if forward search didn't discover anything, just give up. */
396638fd1498Szrj if (gimple_code (stmt) != GIMPLE_COND)
396738fd1498Szrj return cfg_cleanup_needed;
396838fd1498Szrj /* Look at both successors. Either it ends with a GIMPLE_COND
396938fd1498Szrj and satisfies suitable_cond_bb, or ends with a cast and
397038fd1498Szrj other_bb is that cast's successor. */
397138fd1498Szrj FOR_EACH_EDGE (e, ei, first_bb->succs)
397238fd1498Szrj if (!(e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
397338fd1498Szrj || e->dest == first_bb)
397438fd1498Szrj return cfg_cleanup_needed;
397538fd1498Szrj else if (single_pred_p (e->dest))
397638fd1498Szrj {
397738fd1498Szrj stmt = last_stmt (e->dest);
397838fd1498Szrj if (stmt
397938fd1498Szrj && gimple_code (stmt) == GIMPLE_COND
398038fd1498Szrj && EDGE_COUNT (e->dest->succs) == 2)
398138fd1498Szrj {
398238fd1498Szrj if (suitable_cond_bb (first_bb, e->dest, &other_bb, true))
398338fd1498Szrj break;
398438fd1498Szrj else
398538fd1498Szrj other_bb = NULL;
398638fd1498Szrj }
398738fd1498Szrj else if (stmt
398838fd1498Szrj && final_range_test_p (stmt)
398938fd1498Szrj && find_edge (first_bb, single_succ (e->dest)))
399038fd1498Szrj {
399138fd1498Szrj other_bb = single_succ (e->dest);
399238fd1498Szrj if (other_bb == first_bb)
399338fd1498Szrj other_bb = NULL;
399438fd1498Szrj }
399538fd1498Szrj }
399638fd1498Szrj if (other_bb == NULL)
399738fd1498Szrj return cfg_cleanup_needed;
399838fd1498Szrj }
399938fd1498Szrj /* Now do the forward search, moving last_bb to successor bbs
400038fd1498Szrj that aren't other_bb. */
400138fd1498Szrj while (EDGE_COUNT (last_bb->succs) == 2)
400238fd1498Szrj {
400338fd1498Szrj FOR_EACH_EDGE (e, ei, last_bb->succs)
400438fd1498Szrj if (e->dest != other_bb)
400538fd1498Szrj break;
400638fd1498Szrj if (e == NULL)
400738fd1498Szrj break;
400838fd1498Szrj if (!single_pred_p (e->dest))
400938fd1498Szrj break;
401038fd1498Szrj if (!suitable_cond_bb (e->dest, last_bb, &other_bb, false))
401138fd1498Szrj break;
401238fd1498Szrj if (!no_side_effect_bb (e->dest))
401338fd1498Szrj break;
401438fd1498Szrj last_bb = e->dest;
401538fd1498Szrj }
401638fd1498Szrj if (first_bb == last_bb)
401738fd1498Szrj return cfg_cleanup_needed;
401838fd1498Szrj /* Here basic blocks first_bb through last_bb's predecessor
401938fd1498Szrj end with GIMPLE_COND, all of them have one of the edges to
402038fd1498Szrj other_bb and another to another block in the range,
402138fd1498Szrj all blocks except first_bb don't have side-effects and
402238fd1498Szrj last_bb ends with either GIMPLE_COND, or cast satisfying
402338fd1498Szrj final_range_test_p. */
402438fd1498Szrj for (bb = last_bb; ; bb = single_pred (bb))
402538fd1498Szrj {
402638fd1498Szrj enum tree_code code;
402738fd1498Szrj tree lhs, rhs;
402838fd1498Szrj inter_bb_range_test_entry bb_ent;
402938fd1498Szrj
403038fd1498Szrj bb_ent.op = NULL_TREE;
403138fd1498Szrj bb_ent.first_idx = ops.length ();
403238fd1498Szrj bb_ent.last_idx = bb_ent.first_idx;
403338fd1498Szrj e = find_edge (bb, other_bb);
403438fd1498Szrj stmt = last_stmt (bb);
403538fd1498Szrj gimple_set_visited (stmt, true);
403638fd1498Szrj if (gimple_code (stmt) != GIMPLE_COND)
403738fd1498Szrj {
403838fd1498Szrj use_operand_p use_p;
403938fd1498Szrj gimple *phi;
404038fd1498Szrj edge e2;
404138fd1498Szrj unsigned int d;
404238fd1498Szrj
404338fd1498Szrj lhs = gimple_assign_lhs (stmt);
404438fd1498Szrj rhs = gimple_assign_rhs1 (stmt);
404538fd1498Szrj gcc_assert (bb == last_bb);
404638fd1498Szrj
404738fd1498Szrj /* stmt is
404838fd1498Szrj _123 = (int) _234;
404938fd1498Szrj OR
405038fd1498Szrj _234 = a_2(D) == 2;
405138fd1498Szrj
405238fd1498Szrj followed by:
405338fd1498Szrj <bb M>:
405438fd1498Szrj # _345 = PHI <_123(N), 1(...), 1(...)>
405538fd1498Szrj
405638fd1498Szrj or 0 instead of 1. If it is 0, the _234
405738fd1498Szrj range test is anded together with all the
405838fd1498Szrj other range tests, if it is 1, it is ored with
405938fd1498Szrj them. */
406038fd1498Szrj single_imm_use (lhs, &use_p, &phi);
406138fd1498Szrj gcc_assert (gimple_code (phi) == GIMPLE_PHI);
406238fd1498Szrj e2 = find_edge (first_bb, other_bb);
406338fd1498Szrj d = e2->dest_idx;
406438fd1498Szrj gcc_assert (gimple_phi_arg_def (phi, e->dest_idx) == lhs);
406538fd1498Szrj if (integer_zerop (gimple_phi_arg_def (phi, d)))
406638fd1498Szrj code = BIT_AND_EXPR;
406738fd1498Szrj else
406838fd1498Szrj {
406938fd1498Szrj gcc_checking_assert (integer_onep (gimple_phi_arg_def (phi, d)));
407038fd1498Szrj code = BIT_IOR_EXPR;
407138fd1498Szrj }
407238fd1498Szrj
407338fd1498Szrj /* If _234 SSA_NAME_DEF_STMT is
407438fd1498Szrj _234 = _567 | _789;
407538fd1498Szrj (or &, corresponding to 1/0 in the phi arguments,
407638fd1498Szrj push into ops the individual range test arguments
407738fd1498Szrj of the bitwise or resp. and, recursively. */
407838fd1498Szrj if (TREE_CODE (rhs) == SSA_NAME
407938fd1498Szrj && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
408038fd1498Szrj != tcc_comparison)
408138fd1498Szrj && !get_ops (rhs, code, &ops,
408238fd1498Szrj loop_containing_stmt (stmt))
408338fd1498Szrj && has_single_use (rhs))
408438fd1498Szrj {
408538fd1498Szrj /* Otherwise, push the _234 range test itself. */
408638fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
408738fd1498Szrj
408838fd1498Szrj oe->op = rhs;
408938fd1498Szrj oe->rank = code;
409038fd1498Szrj oe->id = 0;
409138fd1498Szrj oe->count = 1;
409238fd1498Szrj oe->stmt_to_insert = NULL;
409338fd1498Szrj ops.safe_push (oe);
409438fd1498Szrj bb_ent.last_idx++;
409538fd1498Szrj bb_ent.op = rhs;
409638fd1498Szrj }
409738fd1498Szrj else if (is_gimple_assign (stmt)
409838fd1498Szrj && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
409938fd1498Szrj == tcc_comparison)
410038fd1498Szrj && !get_ops (lhs, code, &ops,
410138fd1498Szrj loop_containing_stmt (stmt))
410238fd1498Szrj && has_single_use (lhs))
410338fd1498Szrj {
410438fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
410538fd1498Szrj oe->op = lhs;
410638fd1498Szrj oe->rank = code;
410738fd1498Szrj oe->id = 0;
410838fd1498Szrj oe->count = 1;
410938fd1498Szrj ops.safe_push (oe);
411038fd1498Szrj bb_ent.last_idx++;
411138fd1498Szrj bb_ent.op = lhs;
411238fd1498Szrj }
411338fd1498Szrj else
411438fd1498Szrj {
411538fd1498Szrj bb_ent.last_idx = ops.length ();
411638fd1498Szrj bb_ent.op = rhs;
411738fd1498Szrj }
411838fd1498Szrj bbinfo.safe_push (bb_ent);
411938fd1498Szrj continue;
412038fd1498Szrj }
412138fd1498Szrj /* Otherwise stmt is GIMPLE_COND. */
412238fd1498Szrj code = gimple_cond_code (stmt);
412338fd1498Szrj lhs = gimple_cond_lhs (stmt);
412438fd1498Szrj rhs = gimple_cond_rhs (stmt);
412538fd1498Szrj if (TREE_CODE (lhs) == SSA_NAME
412638fd1498Szrj && INTEGRAL_TYPE_P (TREE_TYPE (lhs))
412738fd1498Szrj && ((code != EQ_EXPR && code != NE_EXPR)
412838fd1498Szrj || rhs != boolean_false_node
412938fd1498Szrj /* Either push into ops the individual bitwise
413038fd1498Szrj or resp. and operands, depending on which
413138fd1498Szrj edge is other_bb. */
413238fd1498Szrj || !get_ops (lhs, (((e->flags & EDGE_TRUE_VALUE) == 0)
413338fd1498Szrj ^ (code == EQ_EXPR))
413438fd1498Szrj ? BIT_AND_EXPR : BIT_IOR_EXPR, &ops,
413538fd1498Szrj loop_containing_stmt (stmt))))
413638fd1498Szrj {
413738fd1498Szrj /* Or push the GIMPLE_COND stmt itself. */
413838fd1498Szrj operand_entry *oe = operand_entry_pool.allocate ();
413938fd1498Szrj
414038fd1498Szrj oe->op = NULL;
414138fd1498Szrj oe->rank = (e->flags & EDGE_TRUE_VALUE)
414238fd1498Szrj ? BIT_IOR_EXPR : BIT_AND_EXPR;
414338fd1498Szrj /* oe->op = NULL signs that there is no SSA_NAME
414438fd1498Szrj for the range test, and oe->id instead is the
414538fd1498Szrj basic block number, at which's end the GIMPLE_COND
414638fd1498Szrj is. */
414738fd1498Szrj oe->id = bb->index;
414838fd1498Szrj oe->count = 1;
414938fd1498Szrj oe->stmt_to_insert = NULL;
415038fd1498Szrj ops.safe_push (oe);
415138fd1498Szrj bb_ent.op = NULL;
415238fd1498Szrj bb_ent.last_idx++;
415338fd1498Szrj }
415438fd1498Szrj else if (ops.length () > bb_ent.first_idx)
415538fd1498Szrj {
415638fd1498Szrj bb_ent.op = lhs;
415738fd1498Szrj bb_ent.last_idx = ops.length ();
415838fd1498Szrj }
415938fd1498Szrj bbinfo.safe_push (bb_ent);
416038fd1498Szrj if (bb == first_bb)
416138fd1498Szrj break;
416238fd1498Szrj }
416338fd1498Szrj if (ops.length () > 1)
416438fd1498Szrj any_changes = optimize_range_tests (ERROR_MARK, &ops, first_bb);
416538fd1498Szrj if (any_changes)
416638fd1498Szrj {
416738fd1498Szrj unsigned int idx, max_idx = 0;
416838fd1498Szrj /* update_ops relies on has_single_use predicates returning the
416938fd1498Szrj same values as it did during get_ops earlier. Additionally it
417038fd1498Szrj never removes statements, only adds new ones and it should walk
417138fd1498Szrj from the single imm use and check the predicate already before
417238fd1498Szrj making those changes.
417338fd1498Szrj On the other side, the handling of GIMPLE_COND directly can turn
417438fd1498Szrj previously multiply used SSA_NAMEs into single use SSA_NAMEs, so
417538fd1498Szrj it needs to be done in a separate loop afterwards. */
417638fd1498Szrj for (bb = last_bb, idx = 0; ; bb = single_pred (bb), idx++)
417738fd1498Szrj {
417838fd1498Szrj if (bbinfo[idx].first_idx < bbinfo[idx].last_idx
417938fd1498Szrj && bbinfo[idx].op != NULL_TREE)
418038fd1498Szrj {
418138fd1498Szrj tree new_op;
418238fd1498Szrj
418338fd1498Szrj max_idx = idx;
418438fd1498Szrj stmt = last_stmt (bb);
418538fd1498Szrj new_op = update_ops (bbinfo[idx].op,
418638fd1498Szrj (enum tree_code)
418738fd1498Szrj ops[bbinfo[idx].first_idx]->rank,
418838fd1498Szrj ops, &bbinfo[idx].first_idx,
418938fd1498Szrj loop_containing_stmt (stmt));
419038fd1498Szrj if (new_op == NULL_TREE)
419138fd1498Szrj {
419238fd1498Szrj gcc_assert (bb == last_bb);
419338fd1498Szrj new_op = ops[bbinfo[idx].first_idx++]->op;
419438fd1498Szrj }
419538fd1498Szrj if (bbinfo[idx].op != new_op)
419638fd1498Szrj {
419738fd1498Szrj imm_use_iterator iter;
419838fd1498Szrj use_operand_p use_p;
419938fd1498Szrj gimple *use_stmt, *cast_or_tcc_cmp_stmt = NULL;
420038fd1498Szrj
420138fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, iter, bbinfo[idx].op)
420238fd1498Szrj if (is_gimple_debug (use_stmt))
420338fd1498Szrj continue;
420438fd1498Szrj else if (gimple_code (use_stmt) == GIMPLE_COND
420538fd1498Szrj || gimple_code (use_stmt) == GIMPLE_PHI)
420638fd1498Szrj FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
420738fd1498Szrj SET_USE (use_p, new_op);
420838fd1498Szrj else if ((is_gimple_assign (use_stmt)
420938fd1498Szrj && (TREE_CODE_CLASS
421038fd1498Szrj (gimple_assign_rhs_code (use_stmt))
421138fd1498Szrj == tcc_comparison)))
421238fd1498Szrj cast_or_tcc_cmp_stmt = use_stmt;
421338fd1498Szrj else if (gimple_assign_cast_p (use_stmt))
421438fd1498Szrj cast_or_tcc_cmp_stmt = use_stmt;
421538fd1498Szrj else
421638fd1498Szrj gcc_unreachable ();
421738fd1498Szrj
421838fd1498Szrj if (cast_or_tcc_cmp_stmt)
421938fd1498Szrj {
422038fd1498Szrj gcc_assert (bb == last_bb);
422138fd1498Szrj tree lhs = gimple_assign_lhs (cast_or_tcc_cmp_stmt);
422238fd1498Szrj tree new_lhs = make_ssa_name (TREE_TYPE (lhs));
422338fd1498Szrj enum tree_code rhs_code
422438fd1498Szrj = gimple_assign_cast_p (cast_or_tcc_cmp_stmt)
422538fd1498Szrj ? gimple_assign_rhs_code (cast_or_tcc_cmp_stmt)
422638fd1498Szrj : CONVERT_EXPR;
422738fd1498Szrj gassign *g;
422838fd1498Szrj if (is_gimple_min_invariant (new_op))
422938fd1498Szrj {
423038fd1498Szrj new_op = fold_convert (TREE_TYPE (lhs), new_op);
423138fd1498Szrj g = gimple_build_assign (new_lhs, new_op);
423238fd1498Szrj }
423338fd1498Szrj else
423438fd1498Szrj g = gimple_build_assign (new_lhs, rhs_code, new_op);
423538fd1498Szrj gimple_stmt_iterator gsi
423638fd1498Szrj = gsi_for_stmt (cast_or_tcc_cmp_stmt);
423738fd1498Szrj gimple_set_uid (g, gimple_uid (cast_or_tcc_cmp_stmt));
423838fd1498Szrj gimple_set_visited (g, true);
423938fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
424038fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
424138fd1498Szrj if (is_gimple_debug (use_stmt))
424238fd1498Szrj continue;
424338fd1498Szrj else if (gimple_code (use_stmt) == GIMPLE_COND
424438fd1498Szrj || gimple_code (use_stmt) == GIMPLE_PHI)
424538fd1498Szrj FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
424638fd1498Szrj SET_USE (use_p, new_lhs);
424738fd1498Szrj else
424838fd1498Szrj gcc_unreachable ();
424938fd1498Szrj }
425038fd1498Szrj }
425138fd1498Szrj }
425238fd1498Szrj if (bb == first_bb)
425338fd1498Szrj break;
425438fd1498Szrj }
425538fd1498Szrj for (bb = last_bb, idx = 0; ; bb = single_pred (bb), idx++)
425638fd1498Szrj {
425738fd1498Szrj if (bbinfo[idx].first_idx < bbinfo[idx].last_idx
425838fd1498Szrj && bbinfo[idx].op == NULL_TREE
425938fd1498Szrj && ops[bbinfo[idx].first_idx]->op != NULL_TREE)
426038fd1498Szrj {
426138fd1498Szrj gcond *cond_stmt = as_a <gcond *> (last_stmt (bb));
426238fd1498Szrj
426338fd1498Szrj if (idx > max_idx)
426438fd1498Szrj max_idx = idx;
426538fd1498Szrj
426638fd1498Szrj /* If we collapse the conditional to a true/false
426738fd1498Szrj condition, then bubble that knowledge up to our caller. */
426838fd1498Szrj if (integer_zerop (ops[bbinfo[idx].first_idx]->op))
426938fd1498Szrj {
427038fd1498Szrj gimple_cond_make_false (cond_stmt);
427138fd1498Szrj cfg_cleanup_needed = true;
427238fd1498Szrj }
427338fd1498Szrj else if (integer_onep (ops[bbinfo[idx].first_idx]->op))
427438fd1498Szrj {
427538fd1498Szrj gimple_cond_make_true (cond_stmt);
427638fd1498Szrj cfg_cleanup_needed = true;
427738fd1498Szrj }
427838fd1498Szrj else
427938fd1498Szrj {
428038fd1498Szrj gimple_cond_set_code (cond_stmt, NE_EXPR);
428138fd1498Szrj gimple_cond_set_lhs (cond_stmt,
428238fd1498Szrj ops[bbinfo[idx].first_idx]->op);
428338fd1498Szrj gimple_cond_set_rhs (cond_stmt, boolean_false_node);
428438fd1498Szrj }
428538fd1498Szrj update_stmt (cond_stmt);
428638fd1498Szrj }
428738fd1498Szrj if (bb == first_bb)
428838fd1498Szrj break;
428938fd1498Szrj }
429038fd1498Szrj
429138fd1498Szrj /* The above changes could result in basic blocks after the first
429238fd1498Szrj modified one, up to and including last_bb, to be executed even if
429338fd1498Szrj they would not be in the original program. If the value ranges of
429438fd1498Szrj assignment lhs' in those bbs were dependent on the conditions
429538fd1498Szrj guarding those basic blocks which now can change, the VRs might
429638fd1498Szrj be incorrect. As no_side_effect_bb should ensure those SSA_NAMEs
429738fd1498Szrj are only used within the same bb, it should be not a big deal if
429838fd1498Szrj we just reset all the VRs in those bbs. See PR68671. */
429938fd1498Szrj for (bb = last_bb, idx = 0; idx < max_idx; bb = single_pred (bb), idx++)
430038fd1498Szrj reset_flow_sensitive_info_in_bb (bb);
430138fd1498Szrj }
430238fd1498Szrj return cfg_cleanup_needed;
430338fd1498Szrj }
430438fd1498Szrj
430538fd1498Szrj /* Return true if OPERAND is defined by a PHI node which uses the LHS
430638fd1498Szrj of STMT in it's operands. This is also known as a "destructive
430738fd1498Szrj update" operation. */
430838fd1498Szrj
430938fd1498Szrj static bool
is_phi_for_stmt(gimple * stmt,tree operand)431038fd1498Szrj is_phi_for_stmt (gimple *stmt, tree operand)
431138fd1498Szrj {
431238fd1498Szrj gimple *def_stmt;
431338fd1498Szrj gphi *def_phi;
431438fd1498Szrj tree lhs;
431538fd1498Szrj use_operand_p arg_p;
431638fd1498Szrj ssa_op_iter i;
431738fd1498Szrj
431838fd1498Szrj if (TREE_CODE (operand) != SSA_NAME)
431938fd1498Szrj return false;
432038fd1498Szrj
432138fd1498Szrj lhs = gimple_assign_lhs (stmt);
432238fd1498Szrj
432338fd1498Szrj def_stmt = SSA_NAME_DEF_STMT (operand);
432438fd1498Szrj def_phi = dyn_cast <gphi *> (def_stmt);
432538fd1498Szrj if (!def_phi)
432638fd1498Szrj return false;
432738fd1498Szrj
432838fd1498Szrj FOR_EACH_PHI_ARG (arg_p, def_phi, i, SSA_OP_USE)
432938fd1498Szrj if (lhs == USE_FROM_PTR (arg_p))
433038fd1498Szrj return true;
433138fd1498Szrj return false;
433238fd1498Szrj }
433338fd1498Szrj
433438fd1498Szrj /* Remove def stmt of VAR if VAR has zero uses and recurse
433538fd1498Szrj on rhs1 operand if so. */
433638fd1498Szrj
433738fd1498Szrj static void
remove_visited_stmt_chain(tree var)433838fd1498Szrj remove_visited_stmt_chain (tree var)
433938fd1498Szrj {
434038fd1498Szrj gimple *stmt;
434138fd1498Szrj gimple_stmt_iterator gsi;
434238fd1498Szrj
434338fd1498Szrj while (1)
434438fd1498Szrj {
434538fd1498Szrj if (TREE_CODE (var) != SSA_NAME || !has_zero_uses (var))
434638fd1498Szrj return;
434738fd1498Szrj stmt = SSA_NAME_DEF_STMT (var);
434838fd1498Szrj if (is_gimple_assign (stmt) && gimple_visited_p (stmt))
434938fd1498Szrj {
435038fd1498Szrj var = gimple_assign_rhs1 (stmt);
435138fd1498Szrj gsi = gsi_for_stmt (stmt);
435238fd1498Szrj reassoc_remove_stmt (&gsi);
435338fd1498Szrj release_defs (stmt);
435438fd1498Szrj }
435538fd1498Szrj else
435638fd1498Szrj return;
435738fd1498Szrj }
435838fd1498Szrj }
435938fd1498Szrj
436038fd1498Szrj /* This function checks three consequtive operands in
436138fd1498Szrj passed operands vector OPS starting from OPINDEX and
436238fd1498Szrj swaps two operands if it is profitable for binary operation
436338fd1498Szrj consuming OPINDEX + 1 abnd OPINDEX + 2 operands.
436438fd1498Szrj
436538fd1498Szrj We pair ops with the same rank if possible.
436638fd1498Szrj
436738fd1498Szrj The alternative we try is to see if STMT is a destructive
436838fd1498Szrj update style statement, which is like:
436938fd1498Szrj b = phi (a, ...)
437038fd1498Szrj a = c + b;
437138fd1498Szrj In that case, we want to use the destructive update form to
437238fd1498Szrj expose the possible vectorizer sum reduction opportunity.
437338fd1498Szrj In that case, the third operand will be the phi node. This
437438fd1498Szrj check is not performed if STMT is null.
437538fd1498Szrj
437638fd1498Szrj We could, of course, try to be better as noted above, and do a
437738fd1498Szrj lot of work to try to find these opportunities in >3 operand
437838fd1498Szrj cases, but it is unlikely to be worth it. */
437938fd1498Szrj
438038fd1498Szrj static void
swap_ops_for_binary_stmt(vec<operand_entry * > ops,unsigned int opindex,gimple * stmt)438138fd1498Szrj swap_ops_for_binary_stmt (vec<operand_entry *> ops,
438238fd1498Szrj unsigned int opindex, gimple *stmt)
438338fd1498Szrj {
438438fd1498Szrj operand_entry *oe1, *oe2, *oe3;
438538fd1498Szrj
438638fd1498Szrj oe1 = ops[opindex];
438738fd1498Szrj oe2 = ops[opindex + 1];
438838fd1498Szrj oe3 = ops[opindex + 2];
438938fd1498Szrj
439038fd1498Szrj if ((oe1->rank == oe2->rank
439138fd1498Szrj && oe2->rank != oe3->rank)
439238fd1498Szrj || (stmt && is_phi_for_stmt (stmt, oe3->op)
439338fd1498Szrj && !is_phi_for_stmt (stmt, oe1->op)
439438fd1498Szrj && !is_phi_for_stmt (stmt, oe2->op)))
439538fd1498Szrj std::swap (*oe1, *oe3);
439638fd1498Szrj else if ((oe1->rank == oe3->rank
439738fd1498Szrj && oe2->rank != oe3->rank)
439838fd1498Szrj || (stmt && is_phi_for_stmt (stmt, oe2->op)
439938fd1498Szrj && !is_phi_for_stmt (stmt, oe1->op)
440038fd1498Szrj && !is_phi_for_stmt (stmt, oe3->op)))
440138fd1498Szrj std::swap (*oe1, *oe2);
440238fd1498Szrj }
440338fd1498Szrj
440438fd1498Szrj /* If definition of RHS1 or RHS2 dominates STMT, return the later of those
440538fd1498Szrj two definitions, otherwise return STMT. */
440638fd1498Szrj
440738fd1498Szrj static inline gimple *
find_insert_point(gimple * stmt,tree rhs1,tree rhs2)440838fd1498Szrj find_insert_point (gimple *stmt, tree rhs1, tree rhs2)
440938fd1498Szrj {
441038fd1498Szrj if (TREE_CODE (rhs1) == SSA_NAME
441138fd1498Szrj && reassoc_stmt_dominates_stmt_p (stmt, SSA_NAME_DEF_STMT (rhs1)))
441238fd1498Szrj stmt = SSA_NAME_DEF_STMT (rhs1);
441338fd1498Szrj if (TREE_CODE (rhs2) == SSA_NAME
441438fd1498Szrj && reassoc_stmt_dominates_stmt_p (stmt, SSA_NAME_DEF_STMT (rhs2)))
441538fd1498Szrj stmt = SSA_NAME_DEF_STMT (rhs2);
441638fd1498Szrj return stmt;
441738fd1498Szrj }
441838fd1498Szrj
441938fd1498Szrj /* If the stmt that defines operand has to be inserted, insert it
442038fd1498Szrj before the use. */
442138fd1498Szrj static void
insert_stmt_before_use(gimple * stmt,gimple * stmt_to_insert)442238fd1498Szrj insert_stmt_before_use (gimple *stmt, gimple *stmt_to_insert)
442338fd1498Szrj {
442438fd1498Szrj gcc_assert (is_gimple_assign (stmt_to_insert));
442538fd1498Szrj tree rhs1 = gimple_assign_rhs1 (stmt_to_insert);
442638fd1498Szrj tree rhs2 = gimple_assign_rhs2 (stmt_to_insert);
442738fd1498Szrj gimple *insert_point = find_insert_point (stmt, rhs1, rhs2);
442838fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (insert_point);
442938fd1498Szrj gimple_set_uid (stmt_to_insert, gimple_uid (insert_point));
443038fd1498Szrj
443138fd1498Szrj /* If the insert point is not stmt, then insert_point would be
443238fd1498Szrj the point where operand rhs1 or rhs2 is defined. In this case,
443338fd1498Szrj stmt_to_insert has to be inserted afterwards. This would
443438fd1498Szrj only happen when the stmt insertion point is flexible. */
443538fd1498Szrj if (stmt == insert_point)
443638fd1498Szrj gsi_insert_before (&gsi, stmt_to_insert, GSI_NEW_STMT);
443738fd1498Szrj else
443838fd1498Szrj insert_stmt_after (stmt_to_insert, insert_point);
443938fd1498Szrj }
444038fd1498Szrj
444138fd1498Szrj
444238fd1498Szrj /* Recursively rewrite our linearized statements so that the operators
444338fd1498Szrj match those in OPS[OPINDEX], putting the computation in rank
444438fd1498Szrj order. Return new lhs.
444538fd1498Szrj CHANGED is true if we shouldn't reuse the lhs SSA_NAME both in
444638fd1498Szrj the current stmt and during recursive invocations.
444738fd1498Szrj NEXT_CHANGED is true if we shouldn't reuse the lhs SSA_NAME in
444838fd1498Szrj recursive invocations. */
444938fd1498Szrj
445038fd1498Szrj static tree
rewrite_expr_tree(gimple * stmt,unsigned int opindex,vec<operand_entry * > ops,bool changed,bool next_changed)445138fd1498Szrj rewrite_expr_tree (gimple *stmt, unsigned int opindex,
445238fd1498Szrj vec<operand_entry *> ops, bool changed, bool next_changed)
445338fd1498Szrj {
445438fd1498Szrj tree rhs1 = gimple_assign_rhs1 (stmt);
445538fd1498Szrj tree rhs2 = gimple_assign_rhs2 (stmt);
445638fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
445738fd1498Szrj operand_entry *oe;
445838fd1498Szrj
445938fd1498Szrj /* The final recursion case for this function is that you have
446038fd1498Szrj exactly two operations left.
446138fd1498Szrj If we had exactly one op in the entire list to start with, we
446238fd1498Szrj would have never called this function, and the tail recursion
446338fd1498Szrj rewrites them one at a time. */
446438fd1498Szrj if (opindex + 2 == ops.length ())
446538fd1498Szrj {
446638fd1498Szrj operand_entry *oe1, *oe2;
446738fd1498Szrj
446838fd1498Szrj oe1 = ops[opindex];
446938fd1498Szrj oe2 = ops[opindex + 1];
447038fd1498Szrj
447138fd1498Szrj if (rhs1 != oe1->op || rhs2 != oe2->op)
447238fd1498Szrj {
447338fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
447438fd1498Szrj unsigned int uid = gimple_uid (stmt);
447538fd1498Szrj
447638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
447738fd1498Szrj {
447838fd1498Szrj fprintf (dump_file, "Transforming ");
447938fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
448038fd1498Szrj }
448138fd1498Szrj
448238fd1498Szrj /* If the stmt that defines operand has to be inserted, insert it
448338fd1498Szrj before the use. */
448438fd1498Szrj if (oe1->stmt_to_insert)
448538fd1498Szrj insert_stmt_before_use (stmt, oe1->stmt_to_insert);
448638fd1498Szrj if (oe2->stmt_to_insert)
448738fd1498Szrj insert_stmt_before_use (stmt, oe2->stmt_to_insert);
448838fd1498Szrj /* Even when changed is false, reassociation could have e.g. removed
448938fd1498Szrj some redundant operations, so unless we are just swapping the
449038fd1498Szrj arguments or unless there is no change at all (then we just
449138fd1498Szrj return lhs), force creation of a new SSA_NAME. */
449238fd1498Szrj if (changed || ((rhs1 != oe2->op || rhs2 != oe1->op) && opindex))
449338fd1498Szrj {
449438fd1498Szrj gimple *insert_point
449538fd1498Szrj = find_insert_point (stmt, oe1->op, oe2->op);
449638fd1498Szrj lhs = make_ssa_name (TREE_TYPE (lhs));
449738fd1498Szrj stmt
449838fd1498Szrj = gimple_build_assign (lhs, gimple_assign_rhs_code (stmt),
449938fd1498Szrj oe1->op, oe2->op);
450038fd1498Szrj gimple_set_uid (stmt, uid);
450138fd1498Szrj gimple_set_visited (stmt, true);
450238fd1498Szrj if (insert_point == gsi_stmt (gsi))
450338fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
450438fd1498Szrj else
450538fd1498Szrj insert_stmt_after (stmt, insert_point);
450638fd1498Szrj }
450738fd1498Szrj else
450838fd1498Szrj {
450938fd1498Szrj gcc_checking_assert (find_insert_point (stmt, oe1->op, oe2->op)
451038fd1498Szrj == stmt);
451138fd1498Szrj gimple_assign_set_rhs1 (stmt, oe1->op);
451238fd1498Szrj gimple_assign_set_rhs2 (stmt, oe2->op);
451338fd1498Szrj update_stmt (stmt);
451438fd1498Szrj }
451538fd1498Szrj
451638fd1498Szrj if (rhs1 != oe1->op && rhs1 != oe2->op)
451738fd1498Szrj remove_visited_stmt_chain (rhs1);
451838fd1498Szrj
451938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
452038fd1498Szrj {
452138fd1498Szrj fprintf (dump_file, " into ");
452238fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
452338fd1498Szrj }
452438fd1498Szrj }
452538fd1498Szrj return lhs;
452638fd1498Szrj }
452738fd1498Szrj
452838fd1498Szrj /* If we hit here, we should have 3 or more ops left. */
452938fd1498Szrj gcc_assert (opindex + 2 < ops.length ());
453038fd1498Szrj
453138fd1498Szrj /* Rewrite the next operator. */
453238fd1498Szrj oe = ops[opindex];
453338fd1498Szrj
453438fd1498Szrj /* If the stmt that defines operand has to be inserted, insert it
453538fd1498Szrj before the use. */
453638fd1498Szrj if (oe->stmt_to_insert)
453738fd1498Szrj insert_stmt_before_use (stmt, oe->stmt_to_insert);
453838fd1498Szrj
453938fd1498Szrj /* Recurse on the LHS of the binary operator, which is guaranteed to
454038fd1498Szrj be the non-leaf side. */
454138fd1498Szrj tree new_rhs1
454238fd1498Szrj = rewrite_expr_tree (SSA_NAME_DEF_STMT (rhs1), opindex + 1, ops,
454338fd1498Szrj changed || oe->op != rhs2 || next_changed,
454438fd1498Szrj false);
454538fd1498Szrj
454638fd1498Szrj if (oe->op != rhs2 || new_rhs1 != rhs1)
454738fd1498Szrj {
454838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
454938fd1498Szrj {
455038fd1498Szrj fprintf (dump_file, "Transforming ");
455138fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
455238fd1498Szrj }
455338fd1498Szrj
455438fd1498Szrj /* If changed is false, this is either opindex == 0
455538fd1498Szrj or all outer rhs2's were equal to corresponding oe->op,
455638fd1498Szrj and powi_result is NULL.
455738fd1498Szrj That means lhs is equivalent before and after reassociation.
455838fd1498Szrj Otherwise ensure the old lhs SSA_NAME is not reused and
455938fd1498Szrj create a new stmt as well, so that any debug stmts will be
456038fd1498Szrj properly adjusted. */
456138fd1498Szrj if (changed)
456238fd1498Szrj {
456338fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
456438fd1498Szrj unsigned int uid = gimple_uid (stmt);
456538fd1498Szrj gimple *insert_point = find_insert_point (stmt, new_rhs1, oe->op);
456638fd1498Szrj
456738fd1498Szrj lhs = make_ssa_name (TREE_TYPE (lhs));
456838fd1498Szrj stmt = gimple_build_assign (lhs, gimple_assign_rhs_code (stmt),
456938fd1498Szrj new_rhs1, oe->op);
457038fd1498Szrj gimple_set_uid (stmt, uid);
457138fd1498Szrj gimple_set_visited (stmt, true);
457238fd1498Szrj if (insert_point == gsi_stmt (gsi))
457338fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
457438fd1498Szrj else
457538fd1498Szrj insert_stmt_after (stmt, insert_point);
457638fd1498Szrj }
457738fd1498Szrj else
457838fd1498Szrj {
457938fd1498Szrj gcc_checking_assert (find_insert_point (stmt, new_rhs1, oe->op)
458038fd1498Szrj == stmt);
458138fd1498Szrj gimple_assign_set_rhs1 (stmt, new_rhs1);
458238fd1498Szrj gimple_assign_set_rhs2 (stmt, oe->op);
458338fd1498Szrj update_stmt (stmt);
458438fd1498Szrj }
458538fd1498Szrj
458638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
458738fd1498Szrj {
458838fd1498Szrj fprintf (dump_file, " into ");
458938fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
459038fd1498Szrj }
459138fd1498Szrj }
459238fd1498Szrj return lhs;
459338fd1498Szrj }
459438fd1498Szrj
459538fd1498Szrj /* Find out how many cycles we need to compute statements chain.
459638fd1498Szrj OPS_NUM holds number os statements in a chain. CPU_WIDTH is a
459738fd1498Szrj maximum number of independent statements we may execute per cycle. */
459838fd1498Szrj
459938fd1498Szrj static int
get_required_cycles(int ops_num,int cpu_width)460038fd1498Szrj get_required_cycles (int ops_num, int cpu_width)
460138fd1498Szrj {
460238fd1498Szrj int res;
460338fd1498Szrj int elog;
460438fd1498Szrj unsigned int rest;
460538fd1498Szrj
460638fd1498Szrj /* While we have more than 2 * cpu_width operands
460738fd1498Szrj we may reduce number of operands by cpu_width
460838fd1498Szrj per cycle. */
460938fd1498Szrj res = ops_num / (2 * cpu_width);
461038fd1498Szrj
461138fd1498Szrj /* Remained operands count may be reduced twice per cycle
461238fd1498Szrj until we have only one operand. */
461338fd1498Szrj rest = (unsigned)(ops_num - res * cpu_width);
461438fd1498Szrj elog = exact_log2 (rest);
461538fd1498Szrj if (elog >= 0)
461638fd1498Szrj res += elog;
461738fd1498Szrj else
461838fd1498Szrj res += floor_log2 (rest) + 1;
461938fd1498Szrj
462038fd1498Szrj return res;
462138fd1498Szrj }
462238fd1498Szrj
462338fd1498Szrj /* Returns an optimal number of registers to use for computation of
462438fd1498Szrj given statements. */
462538fd1498Szrj
462638fd1498Szrj static int
get_reassociation_width(int ops_num,enum tree_code opc,machine_mode mode)462738fd1498Szrj get_reassociation_width (int ops_num, enum tree_code opc,
462838fd1498Szrj machine_mode mode)
462938fd1498Szrj {
463038fd1498Szrj int param_width = PARAM_VALUE (PARAM_TREE_REASSOC_WIDTH);
463138fd1498Szrj int width;
463238fd1498Szrj int width_min;
463338fd1498Szrj int cycles_best;
463438fd1498Szrj
463538fd1498Szrj if (param_width > 0)
463638fd1498Szrj width = param_width;
463738fd1498Szrj else
463838fd1498Szrj width = targetm.sched.reassociation_width (opc, mode);
463938fd1498Szrj
464038fd1498Szrj if (width == 1)
464138fd1498Szrj return width;
464238fd1498Szrj
464338fd1498Szrj /* Get the minimal time required for sequence computation. */
464438fd1498Szrj cycles_best = get_required_cycles (ops_num, width);
464538fd1498Szrj
464638fd1498Szrj /* Check if we may use less width and still compute sequence for
464738fd1498Szrj the same time. It will allow us to reduce registers usage.
464838fd1498Szrj get_required_cycles is monotonically increasing with lower width
464938fd1498Szrj so we can perform a binary search for the minimal width that still
465038fd1498Szrj results in the optimal cycle count. */
465138fd1498Szrj width_min = 1;
465238fd1498Szrj while (width > width_min)
465338fd1498Szrj {
465438fd1498Szrj int width_mid = (width + width_min) / 2;
465538fd1498Szrj
465638fd1498Szrj if (get_required_cycles (ops_num, width_mid) == cycles_best)
465738fd1498Szrj width = width_mid;
465838fd1498Szrj else if (width_min < width_mid)
465938fd1498Szrj width_min = width_mid;
466038fd1498Szrj else
466138fd1498Szrj break;
466238fd1498Szrj }
466338fd1498Szrj
466438fd1498Szrj return width;
466538fd1498Szrj }
466638fd1498Szrj
466738fd1498Szrj /* Recursively rewrite our linearized statements so that the operators
466838fd1498Szrj match those in OPS[OPINDEX], putting the computation in rank
466938fd1498Szrj order and trying to allow operations to be executed in
467038fd1498Szrj parallel. */
467138fd1498Szrj
467238fd1498Szrj static void
rewrite_expr_tree_parallel(gassign * stmt,int width,vec<operand_entry * > ops)467338fd1498Szrj rewrite_expr_tree_parallel (gassign *stmt, int width,
467438fd1498Szrj vec<operand_entry *> ops)
467538fd1498Szrj {
467638fd1498Szrj enum tree_code opcode = gimple_assign_rhs_code (stmt);
467738fd1498Szrj int op_num = ops.length ();
467838fd1498Szrj gcc_assert (op_num > 0);
467938fd1498Szrj int stmt_num = op_num - 1;
468038fd1498Szrj gimple **stmts = XALLOCAVEC (gimple *, stmt_num);
468138fd1498Szrj int op_index = op_num - 1;
468238fd1498Szrj int stmt_index = 0;
468338fd1498Szrj int ready_stmts_end = 0;
468438fd1498Szrj int i = 0;
468538fd1498Szrj gimple *stmt1 = NULL, *stmt2 = NULL;
468638fd1498Szrj tree last_rhs1 = gimple_assign_rhs1 (stmt);
468738fd1498Szrj
468838fd1498Szrj /* We start expression rewriting from the top statements.
468938fd1498Szrj So, in this loop we create a full list of statements
469038fd1498Szrj we will work with. */
469138fd1498Szrj stmts[stmt_num - 1] = stmt;
469238fd1498Szrj for (i = stmt_num - 2; i >= 0; i--)
469338fd1498Szrj stmts[i] = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmts[i+1]));
469438fd1498Szrj
469538fd1498Szrj for (i = 0; i < stmt_num; i++)
469638fd1498Szrj {
469738fd1498Szrj tree op1, op2;
469838fd1498Szrj
469938fd1498Szrj /* Determine whether we should use results of
470038fd1498Szrj already handled statements or not. */
470138fd1498Szrj if (ready_stmts_end == 0
470238fd1498Szrj && (i - stmt_index >= width || op_index < 1))
470338fd1498Szrj ready_stmts_end = i;
470438fd1498Szrj
470538fd1498Szrj /* Now we choose operands for the next statement. Non zero
470638fd1498Szrj value in ready_stmts_end means here that we should use
470738fd1498Szrj the result of already generated statements as new operand. */
470838fd1498Szrj if (ready_stmts_end > 0)
470938fd1498Szrj {
471038fd1498Szrj op1 = gimple_assign_lhs (stmts[stmt_index++]);
471138fd1498Szrj if (ready_stmts_end > stmt_index)
471238fd1498Szrj op2 = gimple_assign_lhs (stmts[stmt_index++]);
471338fd1498Szrj else if (op_index >= 0)
471438fd1498Szrj {
471538fd1498Szrj operand_entry *oe = ops[op_index--];
471638fd1498Szrj stmt2 = oe->stmt_to_insert;
471738fd1498Szrj op2 = oe->op;
471838fd1498Szrj }
471938fd1498Szrj else
472038fd1498Szrj {
472138fd1498Szrj gcc_assert (stmt_index < i);
472238fd1498Szrj op2 = gimple_assign_lhs (stmts[stmt_index++]);
472338fd1498Szrj }
472438fd1498Szrj
472538fd1498Szrj if (stmt_index >= ready_stmts_end)
472638fd1498Szrj ready_stmts_end = 0;
472738fd1498Szrj }
472838fd1498Szrj else
472938fd1498Szrj {
473038fd1498Szrj if (op_index > 1)
473138fd1498Szrj swap_ops_for_binary_stmt (ops, op_index - 2, NULL);
473238fd1498Szrj operand_entry *oe2 = ops[op_index--];
473338fd1498Szrj operand_entry *oe1 = ops[op_index--];
473438fd1498Szrj op2 = oe2->op;
473538fd1498Szrj stmt2 = oe2->stmt_to_insert;
473638fd1498Szrj op1 = oe1->op;
473738fd1498Szrj stmt1 = oe1->stmt_to_insert;
473838fd1498Szrj }
473938fd1498Szrj
474038fd1498Szrj /* If we emit the last statement then we should put
474138fd1498Szrj operands into the last statement. It will also
474238fd1498Szrj break the loop. */
474338fd1498Szrj if (op_index < 0 && stmt_index == i)
474438fd1498Szrj i = stmt_num - 1;
474538fd1498Szrj
474638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
474738fd1498Szrj {
474838fd1498Szrj fprintf (dump_file, "Transforming ");
474938fd1498Szrj print_gimple_stmt (dump_file, stmts[i], 0);
475038fd1498Szrj }
475138fd1498Szrj
475238fd1498Szrj /* If the stmt that defines operand has to be inserted, insert it
475338fd1498Szrj before the use. */
475438fd1498Szrj if (stmt1)
475538fd1498Szrj insert_stmt_before_use (stmts[i], stmt1);
475638fd1498Szrj if (stmt2)
475738fd1498Szrj insert_stmt_before_use (stmts[i], stmt2);
475838fd1498Szrj stmt1 = stmt2 = NULL;
475938fd1498Szrj
476038fd1498Szrj /* We keep original statement only for the last one. All
476138fd1498Szrj others are recreated. */
476238fd1498Szrj if (i == stmt_num - 1)
476338fd1498Szrj {
476438fd1498Szrj gimple_assign_set_rhs1 (stmts[i], op1);
476538fd1498Szrj gimple_assign_set_rhs2 (stmts[i], op2);
476638fd1498Szrj update_stmt (stmts[i]);
476738fd1498Szrj }
476838fd1498Szrj else
476938fd1498Szrj {
477038fd1498Szrj stmts[i] = build_and_add_sum (TREE_TYPE (last_rhs1), op1, op2, opcode);
477138fd1498Szrj }
477238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
477338fd1498Szrj {
477438fd1498Szrj fprintf (dump_file, " into ");
477538fd1498Szrj print_gimple_stmt (dump_file, stmts[i], 0);
477638fd1498Szrj }
477738fd1498Szrj }
477838fd1498Szrj
477938fd1498Szrj remove_visited_stmt_chain (last_rhs1);
478038fd1498Szrj }
478138fd1498Szrj
478238fd1498Szrj /* Transform STMT, which is really (A +B) + (C + D) into the left
478338fd1498Szrj linear form, ((A+B)+C)+D.
478438fd1498Szrj Recurse on D if necessary. */
478538fd1498Szrj
478638fd1498Szrj static void
linearize_expr(gimple * stmt)478738fd1498Szrj linearize_expr (gimple *stmt)
478838fd1498Szrj {
478938fd1498Szrj gimple_stmt_iterator gsi;
479038fd1498Szrj gimple *binlhs = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
479138fd1498Szrj gimple *binrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
479238fd1498Szrj gimple *oldbinrhs = binrhs;
479338fd1498Szrj enum tree_code rhscode = gimple_assign_rhs_code (stmt);
479438fd1498Szrj gimple *newbinrhs = NULL;
479538fd1498Szrj struct loop *loop = loop_containing_stmt (stmt);
479638fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
479738fd1498Szrj
479838fd1498Szrj gcc_assert (is_reassociable_op (binlhs, rhscode, loop)
479938fd1498Szrj && is_reassociable_op (binrhs, rhscode, loop));
480038fd1498Szrj
480138fd1498Szrj gsi = gsi_for_stmt (stmt);
480238fd1498Szrj
480338fd1498Szrj gimple_assign_set_rhs2 (stmt, gimple_assign_rhs1 (binrhs));
480438fd1498Szrj binrhs = gimple_build_assign (make_ssa_name (TREE_TYPE (lhs)),
480538fd1498Szrj gimple_assign_rhs_code (binrhs),
480638fd1498Szrj gimple_assign_lhs (binlhs),
480738fd1498Szrj gimple_assign_rhs2 (binrhs));
480838fd1498Szrj gimple_assign_set_rhs1 (stmt, gimple_assign_lhs (binrhs));
480938fd1498Szrj gsi_insert_before (&gsi, binrhs, GSI_SAME_STMT);
481038fd1498Szrj gimple_set_uid (binrhs, gimple_uid (stmt));
481138fd1498Szrj
481238fd1498Szrj if (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME)
481338fd1498Szrj newbinrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
481438fd1498Szrj
481538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
481638fd1498Szrj {
481738fd1498Szrj fprintf (dump_file, "Linearized: ");
481838fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
481938fd1498Szrj }
482038fd1498Szrj
482138fd1498Szrj reassociate_stats.linearized++;
482238fd1498Szrj update_stmt (stmt);
482338fd1498Szrj
482438fd1498Szrj gsi = gsi_for_stmt (oldbinrhs);
482538fd1498Szrj reassoc_remove_stmt (&gsi);
482638fd1498Szrj release_defs (oldbinrhs);
482738fd1498Szrj
482838fd1498Szrj gimple_set_visited (stmt, true);
482938fd1498Szrj gimple_set_visited (binlhs, true);
483038fd1498Szrj gimple_set_visited (binrhs, true);
483138fd1498Szrj
483238fd1498Szrj /* Tail recurse on the new rhs if it still needs reassociation. */
483338fd1498Szrj if (newbinrhs && is_reassociable_op (newbinrhs, rhscode, loop))
483438fd1498Szrj /* ??? This should probably be linearize_expr (newbinrhs) but I don't
483538fd1498Szrj want to change the algorithm while converting to tuples. */
483638fd1498Szrj linearize_expr (stmt);
483738fd1498Szrj }
483838fd1498Szrj
483938fd1498Szrj /* If LHS has a single immediate use that is a GIMPLE_ASSIGN statement, return
484038fd1498Szrj it. Otherwise, return NULL. */
484138fd1498Szrj
484238fd1498Szrj static gimple *
get_single_immediate_use(tree lhs)484338fd1498Szrj get_single_immediate_use (tree lhs)
484438fd1498Szrj {
484538fd1498Szrj use_operand_p immuse;
484638fd1498Szrj gimple *immusestmt;
484738fd1498Szrj
484838fd1498Szrj if (TREE_CODE (lhs) == SSA_NAME
484938fd1498Szrj && single_imm_use (lhs, &immuse, &immusestmt)
485038fd1498Szrj && is_gimple_assign (immusestmt))
485138fd1498Szrj return immusestmt;
485238fd1498Szrj
485338fd1498Szrj return NULL;
485438fd1498Szrj }
485538fd1498Szrj
485638fd1498Szrj /* Recursively negate the value of TONEGATE, and return the SSA_NAME
485738fd1498Szrj representing the negated value. Insertions of any necessary
485838fd1498Szrj instructions go before GSI.
485938fd1498Szrj This function is recursive in that, if you hand it "a_5" as the
486038fd1498Szrj value to negate, and a_5 is defined by "a_5 = b_3 + b_4", it will
486138fd1498Szrj transform b_3 + b_4 into a_5 = -b_3 + -b_4. */
486238fd1498Szrj
486338fd1498Szrj static tree
negate_value(tree tonegate,gimple_stmt_iterator * gsip)486438fd1498Szrj negate_value (tree tonegate, gimple_stmt_iterator *gsip)
486538fd1498Szrj {
486638fd1498Szrj gimple *negatedefstmt = NULL;
486738fd1498Szrj tree resultofnegate;
486838fd1498Szrj gimple_stmt_iterator gsi;
486938fd1498Szrj unsigned int uid;
487038fd1498Szrj
487138fd1498Szrj /* If we are trying to negate a name, defined by an add, negate the
487238fd1498Szrj add operands instead. */
487338fd1498Szrj if (TREE_CODE (tonegate) == SSA_NAME)
487438fd1498Szrj negatedefstmt = SSA_NAME_DEF_STMT (tonegate);
487538fd1498Szrj if (TREE_CODE (tonegate) == SSA_NAME
487638fd1498Szrj && is_gimple_assign (negatedefstmt)
487738fd1498Szrj && TREE_CODE (gimple_assign_lhs (negatedefstmt)) == SSA_NAME
487838fd1498Szrj && has_single_use (gimple_assign_lhs (negatedefstmt))
487938fd1498Szrj && gimple_assign_rhs_code (negatedefstmt) == PLUS_EXPR)
488038fd1498Szrj {
488138fd1498Szrj tree rhs1 = gimple_assign_rhs1 (negatedefstmt);
488238fd1498Szrj tree rhs2 = gimple_assign_rhs2 (negatedefstmt);
488338fd1498Szrj tree lhs = gimple_assign_lhs (negatedefstmt);
488438fd1498Szrj gimple *g;
488538fd1498Szrj
488638fd1498Szrj gsi = gsi_for_stmt (negatedefstmt);
488738fd1498Szrj rhs1 = negate_value (rhs1, &gsi);
488838fd1498Szrj
488938fd1498Szrj gsi = gsi_for_stmt (negatedefstmt);
489038fd1498Szrj rhs2 = negate_value (rhs2, &gsi);
489138fd1498Szrj
489238fd1498Szrj gsi = gsi_for_stmt (negatedefstmt);
489338fd1498Szrj lhs = make_ssa_name (TREE_TYPE (lhs));
489438fd1498Szrj gimple_set_visited (negatedefstmt, true);
489538fd1498Szrj g = gimple_build_assign (lhs, PLUS_EXPR, rhs1, rhs2);
489638fd1498Szrj gimple_set_uid (g, gimple_uid (negatedefstmt));
489738fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
489838fd1498Szrj return lhs;
489938fd1498Szrj }
490038fd1498Szrj
490138fd1498Szrj tonegate = fold_build1 (NEGATE_EXPR, TREE_TYPE (tonegate), tonegate);
490238fd1498Szrj resultofnegate = force_gimple_operand_gsi (gsip, tonegate, true,
490338fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
490438fd1498Szrj gsi = *gsip;
490538fd1498Szrj uid = gimple_uid (gsi_stmt (gsi));
490638fd1498Szrj for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
490738fd1498Szrj {
490838fd1498Szrj gimple *stmt = gsi_stmt (gsi);
490938fd1498Szrj if (gimple_uid (stmt) != 0)
491038fd1498Szrj break;
491138fd1498Szrj gimple_set_uid (stmt, uid);
491238fd1498Szrj }
491338fd1498Szrj return resultofnegate;
491438fd1498Szrj }
491538fd1498Szrj
491638fd1498Szrj /* Return true if we should break up the subtract in STMT into an add
491738fd1498Szrj with negate. This is true when we the subtract operands are really
491838fd1498Szrj adds, or the subtract itself is used in an add expression. In
491938fd1498Szrj either case, breaking up the subtract into an add with negate
492038fd1498Szrj exposes the adds to reassociation. */
492138fd1498Szrj
492238fd1498Szrj static bool
should_break_up_subtract(gimple * stmt)492338fd1498Szrj should_break_up_subtract (gimple *stmt)
492438fd1498Szrj {
492538fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
492638fd1498Szrj tree binlhs = gimple_assign_rhs1 (stmt);
492738fd1498Szrj tree binrhs = gimple_assign_rhs2 (stmt);
492838fd1498Szrj gimple *immusestmt;
492938fd1498Szrj struct loop *loop = loop_containing_stmt (stmt);
493038fd1498Szrj
493138fd1498Szrj if (TREE_CODE (binlhs) == SSA_NAME
493238fd1498Szrj && is_reassociable_op (SSA_NAME_DEF_STMT (binlhs), PLUS_EXPR, loop))
493338fd1498Szrj return true;
493438fd1498Szrj
493538fd1498Szrj if (TREE_CODE (binrhs) == SSA_NAME
493638fd1498Szrj && is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), PLUS_EXPR, loop))
493738fd1498Szrj return true;
493838fd1498Szrj
493938fd1498Szrj if (TREE_CODE (lhs) == SSA_NAME
494038fd1498Szrj && (immusestmt = get_single_immediate_use (lhs))
494138fd1498Szrj && is_gimple_assign (immusestmt)
494238fd1498Szrj && (gimple_assign_rhs_code (immusestmt) == PLUS_EXPR
494338fd1498Szrj || (gimple_assign_rhs_code (immusestmt) == MINUS_EXPR
494438fd1498Szrj && gimple_assign_rhs1 (immusestmt) == lhs)
494538fd1498Szrj || gimple_assign_rhs_code (immusestmt) == MULT_EXPR))
494638fd1498Szrj return true;
494738fd1498Szrj return false;
494838fd1498Szrj }
494938fd1498Szrj
495038fd1498Szrj /* Transform STMT from A - B into A + -B. */
495138fd1498Szrj
495238fd1498Szrj static void
break_up_subtract(gimple * stmt,gimple_stmt_iterator * gsip)495338fd1498Szrj break_up_subtract (gimple *stmt, gimple_stmt_iterator *gsip)
495438fd1498Szrj {
495538fd1498Szrj tree rhs1 = gimple_assign_rhs1 (stmt);
495638fd1498Szrj tree rhs2 = gimple_assign_rhs2 (stmt);
495738fd1498Szrj
495838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
495938fd1498Szrj {
496038fd1498Szrj fprintf (dump_file, "Breaking up subtract ");
496138fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
496238fd1498Szrj }
496338fd1498Szrj
496438fd1498Szrj rhs2 = negate_value (rhs2, gsip);
496538fd1498Szrj gimple_assign_set_rhs_with_ops (gsip, PLUS_EXPR, rhs1, rhs2);
496638fd1498Szrj update_stmt (stmt);
496738fd1498Szrj }
496838fd1498Szrj
496938fd1498Szrj /* Determine whether STMT is a builtin call that raises an SSA name
497038fd1498Szrj to an integer power and has only one use. If so, and this is early
497138fd1498Szrj reassociation and unsafe math optimizations are permitted, place
497238fd1498Szrj the SSA name in *BASE and the exponent in *EXPONENT, and return TRUE.
497338fd1498Szrj If any of these conditions does not hold, return FALSE. */
497438fd1498Szrj
497538fd1498Szrj static bool
acceptable_pow_call(gcall * stmt,tree * base,HOST_WIDE_INT * exponent)497638fd1498Szrj acceptable_pow_call (gcall *stmt, tree *base, HOST_WIDE_INT *exponent)
497738fd1498Szrj {
497838fd1498Szrj tree arg1;
497938fd1498Szrj REAL_VALUE_TYPE c, cint;
498038fd1498Szrj
498138fd1498Szrj switch (gimple_call_combined_fn (stmt))
498238fd1498Szrj {
498338fd1498Szrj CASE_CFN_POW:
498438fd1498Szrj if (flag_errno_math)
498538fd1498Szrj return false;
498638fd1498Szrj
498738fd1498Szrj *base = gimple_call_arg (stmt, 0);
498838fd1498Szrj arg1 = gimple_call_arg (stmt, 1);
498938fd1498Szrj
499038fd1498Szrj if (TREE_CODE (arg1) != REAL_CST)
499138fd1498Szrj return false;
499238fd1498Szrj
499338fd1498Szrj c = TREE_REAL_CST (arg1);
499438fd1498Szrj
499538fd1498Szrj if (REAL_EXP (&c) > HOST_BITS_PER_WIDE_INT)
499638fd1498Szrj return false;
499738fd1498Szrj
499838fd1498Szrj *exponent = real_to_integer (&c);
499938fd1498Szrj real_from_integer (&cint, VOIDmode, *exponent, SIGNED);
500038fd1498Szrj if (!real_identical (&c, &cint))
500138fd1498Szrj return false;
500238fd1498Szrj
500338fd1498Szrj break;
500438fd1498Szrj
500538fd1498Szrj CASE_CFN_POWI:
500638fd1498Szrj *base = gimple_call_arg (stmt, 0);
500738fd1498Szrj arg1 = gimple_call_arg (stmt, 1);
500838fd1498Szrj
500938fd1498Szrj if (!tree_fits_shwi_p (arg1))
501038fd1498Szrj return false;
501138fd1498Szrj
501238fd1498Szrj *exponent = tree_to_shwi (arg1);
501338fd1498Szrj break;
501438fd1498Szrj
501538fd1498Szrj default:
501638fd1498Szrj return false;
501738fd1498Szrj }
501838fd1498Szrj
501938fd1498Szrj /* Expanding negative exponents is generally unproductive, so we don't
502038fd1498Szrj complicate matters with those. Exponents of zero and one should
502138fd1498Szrj have been handled by expression folding. */
502238fd1498Szrj if (*exponent < 2 || TREE_CODE (*base) != SSA_NAME)
502338fd1498Szrj return false;
502438fd1498Szrj
502538fd1498Szrj return true;
502638fd1498Szrj }
502738fd1498Szrj
502838fd1498Szrj /* Try to derive and add operand entry for OP to *OPS. Return false if
502938fd1498Szrj unsuccessful. */
503038fd1498Szrj
503138fd1498Szrj static bool
try_special_add_to_ops(vec<operand_entry * > * ops,enum tree_code code,tree op,gimple * def_stmt)503238fd1498Szrj try_special_add_to_ops (vec<operand_entry *> *ops,
503338fd1498Szrj enum tree_code code,
503438fd1498Szrj tree op, gimple* def_stmt)
503538fd1498Szrj {
503638fd1498Szrj tree base = NULL_TREE;
503738fd1498Szrj HOST_WIDE_INT exponent = 0;
503838fd1498Szrj
503938fd1498Szrj if (TREE_CODE (op) != SSA_NAME
504038fd1498Szrj || ! has_single_use (op))
504138fd1498Szrj return false;
504238fd1498Szrj
504338fd1498Szrj if (code == MULT_EXPR
504438fd1498Szrj && reassoc_insert_powi_p
504538fd1498Szrj && flag_unsafe_math_optimizations
504638fd1498Szrj && is_gimple_call (def_stmt)
504738fd1498Szrj && acceptable_pow_call (as_a <gcall *> (def_stmt), &base, &exponent))
504838fd1498Szrj {
504938fd1498Szrj add_repeat_to_ops_vec (ops, base, exponent);
505038fd1498Szrj gimple_set_visited (def_stmt, true);
505138fd1498Szrj return true;
505238fd1498Szrj }
505338fd1498Szrj else if (code == MULT_EXPR
505438fd1498Szrj && is_gimple_assign (def_stmt)
505538fd1498Szrj && gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR
505638fd1498Szrj && !HONOR_SNANS (TREE_TYPE (op))
505738fd1498Szrj && (!HONOR_SIGNED_ZEROS (TREE_TYPE (op))
505838fd1498Szrj || !COMPLEX_FLOAT_TYPE_P (TREE_TYPE (op))))
505938fd1498Szrj {
506038fd1498Szrj tree rhs1 = gimple_assign_rhs1 (def_stmt);
506138fd1498Szrj tree cst = build_minus_one_cst (TREE_TYPE (op));
506238fd1498Szrj add_to_ops_vec (ops, rhs1);
506338fd1498Szrj add_to_ops_vec (ops, cst);
506438fd1498Szrj gimple_set_visited (def_stmt, true);
506538fd1498Szrj return true;
506638fd1498Szrj }
506738fd1498Szrj
506838fd1498Szrj return false;
506938fd1498Szrj }
507038fd1498Szrj
507138fd1498Szrj /* Recursively linearize a binary expression that is the RHS of STMT.
507238fd1498Szrj Place the operands of the expression tree in the vector named OPS. */
507338fd1498Szrj
507438fd1498Szrj static void
linearize_expr_tree(vec<operand_entry * > * ops,gimple * stmt,bool is_associative,bool set_visited)507538fd1498Szrj linearize_expr_tree (vec<operand_entry *> *ops, gimple *stmt,
507638fd1498Szrj bool is_associative, bool set_visited)
507738fd1498Szrj {
507838fd1498Szrj tree binlhs = gimple_assign_rhs1 (stmt);
507938fd1498Szrj tree binrhs = gimple_assign_rhs2 (stmt);
508038fd1498Szrj gimple *binlhsdef = NULL, *binrhsdef = NULL;
508138fd1498Szrj bool binlhsisreassoc = false;
508238fd1498Szrj bool binrhsisreassoc = false;
508338fd1498Szrj enum tree_code rhscode = gimple_assign_rhs_code (stmt);
508438fd1498Szrj struct loop *loop = loop_containing_stmt (stmt);
508538fd1498Szrj
508638fd1498Szrj if (set_visited)
508738fd1498Szrj gimple_set_visited (stmt, true);
508838fd1498Szrj
508938fd1498Szrj if (TREE_CODE (binlhs) == SSA_NAME)
509038fd1498Szrj {
509138fd1498Szrj binlhsdef = SSA_NAME_DEF_STMT (binlhs);
509238fd1498Szrj binlhsisreassoc = (is_reassociable_op (binlhsdef, rhscode, loop)
509338fd1498Szrj && !stmt_could_throw_p (binlhsdef));
509438fd1498Szrj }
509538fd1498Szrj
509638fd1498Szrj if (TREE_CODE (binrhs) == SSA_NAME)
509738fd1498Szrj {
509838fd1498Szrj binrhsdef = SSA_NAME_DEF_STMT (binrhs);
509938fd1498Szrj binrhsisreassoc = (is_reassociable_op (binrhsdef, rhscode, loop)
510038fd1498Szrj && !stmt_could_throw_p (binrhsdef));
510138fd1498Szrj }
510238fd1498Szrj
510338fd1498Szrj /* If the LHS is not reassociable, but the RHS is, we need to swap
510438fd1498Szrj them. If neither is reassociable, there is nothing we can do, so
510538fd1498Szrj just put them in the ops vector. If the LHS is reassociable,
510638fd1498Szrj linearize it. If both are reassociable, then linearize the RHS
510738fd1498Szrj and the LHS. */
510838fd1498Szrj
510938fd1498Szrj if (!binlhsisreassoc)
511038fd1498Szrj {
511138fd1498Szrj /* If this is not a associative operation like division, give up. */
511238fd1498Szrj if (!is_associative)
511338fd1498Szrj {
511438fd1498Szrj add_to_ops_vec (ops, binrhs);
511538fd1498Szrj return;
511638fd1498Szrj }
511738fd1498Szrj
511838fd1498Szrj if (!binrhsisreassoc)
511938fd1498Szrj {
512038fd1498Szrj if (!try_special_add_to_ops (ops, rhscode, binrhs, binrhsdef))
512138fd1498Szrj add_to_ops_vec (ops, binrhs);
512238fd1498Szrj
512338fd1498Szrj if (!try_special_add_to_ops (ops, rhscode, binlhs, binlhsdef))
512438fd1498Szrj add_to_ops_vec (ops, binlhs);
512538fd1498Szrj
512638fd1498Szrj return;
512738fd1498Szrj }
512838fd1498Szrj
512938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
513038fd1498Szrj {
513138fd1498Szrj fprintf (dump_file, "swapping operands of ");
513238fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
513338fd1498Szrj }
513438fd1498Szrj
513538fd1498Szrj swap_ssa_operands (stmt,
513638fd1498Szrj gimple_assign_rhs1_ptr (stmt),
513738fd1498Szrj gimple_assign_rhs2_ptr (stmt));
513838fd1498Szrj update_stmt (stmt);
513938fd1498Szrj
514038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
514138fd1498Szrj {
514238fd1498Szrj fprintf (dump_file, " is now ");
514338fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
514438fd1498Szrj }
514538fd1498Szrj
514638fd1498Szrj /* We want to make it so the lhs is always the reassociative op,
514738fd1498Szrj so swap. */
514838fd1498Szrj std::swap (binlhs, binrhs);
514938fd1498Szrj }
515038fd1498Szrj else if (binrhsisreassoc)
515138fd1498Szrj {
515238fd1498Szrj linearize_expr (stmt);
515338fd1498Szrj binlhs = gimple_assign_rhs1 (stmt);
515438fd1498Szrj binrhs = gimple_assign_rhs2 (stmt);
515538fd1498Szrj }
515638fd1498Szrj
515738fd1498Szrj gcc_assert (TREE_CODE (binrhs) != SSA_NAME
515838fd1498Szrj || !is_reassociable_op (SSA_NAME_DEF_STMT (binrhs),
515938fd1498Szrj rhscode, loop));
516038fd1498Szrj linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs),
516138fd1498Szrj is_associative, set_visited);
516238fd1498Szrj
516338fd1498Szrj if (!try_special_add_to_ops (ops, rhscode, binrhs, binrhsdef))
516438fd1498Szrj add_to_ops_vec (ops, binrhs);
516538fd1498Szrj }
516638fd1498Szrj
516738fd1498Szrj /* Repropagate the negates back into subtracts, since no other pass
516838fd1498Szrj currently does it. */
516938fd1498Szrj
517038fd1498Szrj static void
repropagate_negates(void)517138fd1498Szrj repropagate_negates (void)
517238fd1498Szrj {
517338fd1498Szrj unsigned int i = 0;
517438fd1498Szrj tree negate;
517538fd1498Szrj
517638fd1498Szrj FOR_EACH_VEC_ELT (plus_negates, i, negate)
517738fd1498Szrj {
517838fd1498Szrj gimple *user = get_single_immediate_use (negate);
517938fd1498Szrj
518038fd1498Szrj if (!user || !is_gimple_assign (user))
518138fd1498Szrj continue;
518238fd1498Szrj
518338fd1498Szrj /* The negate operand can be either operand of a PLUS_EXPR
518438fd1498Szrj (it can be the LHS if the RHS is a constant for example).
518538fd1498Szrj
518638fd1498Szrj Force the negate operand to the RHS of the PLUS_EXPR, then
518738fd1498Szrj transform the PLUS_EXPR into a MINUS_EXPR. */
518838fd1498Szrj if (gimple_assign_rhs_code (user) == PLUS_EXPR)
518938fd1498Szrj {
519038fd1498Szrj /* If the negated operand appears on the LHS of the
519138fd1498Szrj PLUS_EXPR, exchange the operands of the PLUS_EXPR
519238fd1498Szrj to force the negated operand to the RHS of the PLUS_EXPR. */
519338fd1498Szrj if (gimple_assign_rhs1 (user) == negate)
519438fd1498Szrj {
519538fd1498Szrj swap_ssa_operands (user,
519638fd1498Szrj gimple_assign_rhs1_ptr (user),
519738fd1498Szrj gimple_assign_rhs2_ptr (user));
519838fd1498Szrj }
519938fd1498Szrj
520038fd1498Szrj /* Now transform the PLUS_EXPR into a MINUS_EXPR and replace
520138fd1498Szrj the RHS of the PLUS_EXPR with the operand of the NEGATE_EXPR. */
520238fd1498Szrj if (gimple_assign_rhs2 (user) == negate)
520338fd1498Szrj {
520438fd1498Szrj tree rhs1 = gimple_assign_rhs1 (user);
520538fd1498Szrj tree rhs2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (negate));
520638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (user);
520738fd1498Szrj gimple_assign_set_rhs_with_ops (&gsi, MINUS_EXPR, rhs1, rhs2);
520838fd1498Szrj update_stmt (user);
520938fd1498Szrj }
521038fd1498Szrj }
521138fd1498Szrj else if (gimple_assign_rhs_code (user) == MINUS_EXPR)
521238fd1498Szrj {
521338fd1498Szrj if (gimple_assign_rhs1 (user) == negate)
521438fd1498Szrj {
521538fd1498Szrj /* We have
521638fd1498Szrj x = -a
521738fd1498Szrj y = x - b
521838fd1498Szrj which we transform into
521938fd1498Szrj x = a + b
522038fd1498Szrj y = -x .
522138fd1498Szrj This pushes down the negate which we possibly can merge
522238fd1498Szrj into some other operation, hence insert it into the
522338fd1498Szrj plus_negates vector. */
522438fd1498Szrj gimple *feed = SSA_NAME_DEF_STMT (negate);
522538fd1498Szrj tree a = gimple_assign_rhs1 (feed);
522638fd1498Szrj tree b = gimple_assign_rhs2 (user);
522738fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (feed);
522838fd1498Szrj gimple_stmt_iterator gsi2 = gsi_for_stmt (user);
522938fd1498Szrj tree x = make_ssa_name (TREE_TYPE (gimple_assign_lhs (feed)));
523038fd1498Szrj gimple *g = gimple_build_assign (x, PLUS_EXPR, a, b);
523138fd1498Szrj gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
523238fd1498Szrj gimple_assign_set_rhs_with_ops (&gsi2, NEGATE_EXPR, x);
523338fd1498Szrj user = gsi_stmt (gsi2);
523438fd1498Szrj update_stmt (user);
523538fd1498Szrj reassoc_remove_stmt (&gsi);
523638fd1498Szrj release_defs (feed);
523738fd1498Szrj plus_negates.safe_push (gimple_assign_lhs (user));
523838fd1498Szrj }
523938fd1498Szrj else
524038fd1498Szrj {
524138fd1498Szrj /* Transform "x = -a; y = b - x" into "y = b + a", getting
524238fd1498Szrj rid of one operation. */
524338fd1498Szrj gimple *feed = SSA_NAME_DEF_STMT (negate);
524438fd1498Szrj tree a = gimple_assign_rhs1 (feed);
524538fd1498Szrj tree rhs1 = gimple_assign_rhs1 (user);
524638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (user);
524738fd1498Szrj gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, rhs1, a);
524838fd1498Szrj update_stmt (gsi_stmt (gsi));
524938fd1498Szrj }
525038fd1498Szrj }
525138fd1498Szrj }
525238fd1498Szrj }
525338fd1498Szrj
525438fd1498Szrj /* Returns true if OP is of a type for which we can do reassociation.
525538fd1498Szrj That is for integral or non-saturating fixed-point types, and for
525638fd1498Szrj floating point type when associative-math is enabled. */
525738fd1498Szrj
525838fd1498Szrj static bool
can_reassociate_p(tree op)525938fd1498Szrj can_reassociate_p (tree op)
526038fd1498Szrj {
526138fd1498Szrj tree type = TREE_TYPE (op);
526238fd1498Szrj if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
526338fd1498Szrj return false;
526438fd1498Szrj if ((ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
526538fd1498Szrj || NON_SAT_FIXED_POINT_TYPE_P (type)
526638fd1498Szrj || (flag_associative_math && FLOAT_TYPE_P (type)))
526738fd1498Szrj return true;
526838fd1498Szrj return false;
526938fd1498Szrj }
527038fd1498Szrj
527138fd1498Szrj /* Break up subtract operations in block BB.
527238fd1498Szrj
527338fd1498Szrj We do this top down because we don't know whether the subtract is
527438fd1498Szrj part of a possible chain of reassociation except at the top.
527538fd1498Szrj
527638fd1498Szrj IE given
527738fd1498Szrj d = f + g
527838fd1498Szrj c = a + e
527938fd1498Szrj b = c - d
528038fd1498Szrj q = b - r
528138fd1498Szrj k = t - q
528238fd1498Szrj
528338fd1498Szrj we want to break up k = t - q, but we won't until we've transformed q
528438fd1498Szrj = b - r, which won't be broken up until we transform b = c - d.
528538fd1498Szrj
528638fd1498Szrj En passant, clear the GIMPLE visited flag on every statement
528738fd1498Szrj and set UIDs within each basic block. */
528838fd1498Szrj
528938fd1498Szrj static void
break_up_subtract_bb(basic_block bb)529038fd1498Szrj break_up_subtract_bb (basic_block bb)
529138fd1498Szrj {
529238fd1498Szrj gimple_stmt_iterator gsi;
529338fd1498Szrj basic_block son;
529438fd1498Szrj unsigned int uid = 1;
529538fd1498Szrj
529638fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
529738fd1498Szrj {
529838fd1498Szrj gimple *stmt = gsi_stmt (gsi);
529938fd1498Szrj gimple_set_visited (stmt, false);
530038fd1498Szrj gimple_set_uid (stmt, uid++);
530138fd1498Szrj
530238fd1498Szrj if (!is_gimple_assign (stmt)
530338fd1498Szrj || !can_reassociate_p (gimple_assign_lhs (stmt)))
530438fd1498Szrj continue;
530538fd1498Szrj
530638fd1498Szrj /* Look for simple gimple subtract operations. */
530738fd1498Szrj if (gimple_assign_rhs_code (stmt) == MINUS_EXPR)
530838fd1498Szrj {
530938fd1498Szrj if (!can_reassociate_p (gimple_assign_rhs1 (stmt))
531038fd1498Szrj || !can_reassociate_p (gimple_assign_rhs2 (stmt)))
531138fd1498Szrj continue;
531238fd1498Szrj
531338fd1498Szrj /* Check for a subtract used only in an addition. If this
531438fd1498Szrj is the case, transform it into add of a negate for better
531538fd1498Szrj reassociation. IE transform C = A-B into C = A + -B if C
531638fd1498Szrj is only used in an addition. */
531738fd1498Szrj if (should_break_up_subtract (stmt))
531838fd1498Szrj break_up_subtract (stmt, &gsi);
531938fd1498Szrj }
532038fd1498Szrj else if (gimple_assign_rhs_code (stmt) == NEGATE_EXPR
532138fd1498Szrj && can_reassociate_p (gimple_assign_rhs1 (stmt)))
532238fd1498Szrj plus_negates.safe_push (gimple_assign_lhs (stmt));
532338fd1498Szrj }
532438fd1498Szrj for (son = first_dom_son (CDI_DOMINATORS, bb);
532538fd1498Szrj son;
532638fd1498Szrj son = next_dom_son (CDI_DOMINATORS, son))
532738fd1498Szrj break_up_subtract_bb (son);
532838fd1498Szrj }
532938fd1498Szrj
533038fd1498Szrj /* Used for repeated factor analysis. */
533138fd1498Szrj struct repeat_factor
533238fd1498Szrj {
533338fd1498Szrj /* An SSA name that occurs in a multiply chain. */
533438fd1498Szrj tree factor;
533538fd1498Szrj
533638fd1498Szrj /* Cached rank of the factor. */
533738fd1498Szrj unsigned rank;
533838fd1498Szrj
533938fd1498Szrj /* Number of occurrences of the factor in the chain. */
534038fd1498Szrj HOST_WIDE_INT count;
534138fd1498Szrj
534238fd1498Szrj /* An SSA name representing the product of this factor and
534338fd1498Szrj all factors appearing later in the repeated factor vector. */
534438fd1498Szrj tree repr;
534538fd1498Szrj };
534638fd1498Szrj
534738fd1498Szrj
534838fd1498Szrj static vec<repeat_factor> repeat_factor_vec;
534938fd1498Szrj
535038fd1498Szrj /* Used for sorting the repeat factor vector. Sort primarily by
535138fd1498Szrj ascending occurrence count, secondarily by descending rank. */
535238fd1498Szrj
535338fd1498Szrj static int
compare_repeat_factors(const void * x1,const void * x2)535438fd1498Szrj compare_repeat_factors (const void *x1, const void *x2)
535538fd1498Szrj {
535638fd1498Szrj const repeat_factor *rf1 = (const repeat_factor *) x1;
535738fd1498Szrj const repeat_factor *rf2 = (const repeat_factor *) x2;
535838fd1498Szrj
535938fd1498Szrj if (rf1->count != rf2->count)
536038fd1498Szrj return rf1->count - rf2->count;
536138fd1498Szrj
536238fd1498Szrj return rf2->rank - rf1->rank;
536338fd1498Szrj }
536438fd1498Szrj
536538fd1498Szrj /* Look for repeated operands in OPS in the multiply tree rooted at
536638fd1498Szrj STMT. Replace them with an optimal sequence of multiplies and powi
536738fd1498Szrj builtin calls, and remove the used operands from OPS. Return an
536838fd1498Szrj SSA name representing the value of the replacement sequence. */
536938fd1498Szrj
537038fd1498Szrj static tree
attempt_builtin_powi(gimple * stmt,vec<operand_entry * > * ops)537138fd1498Szrj attempt_builtin_powi (gimple *stmt, vec<operand_entry *> *ops)
537238fd1498Szrj {
537338fd1498Szrj unsigned i, j, vec_len;
537438fd1498Szrj int ii;
537538fd1498Szrj operand_entry *oe;
537638fd1498Szrj repeat_factor *rf1, *rf2;
537738fd1498Szrj repeat_factor rfnew;
537838fd1498Szrj tree result = NULL_TREE;
537938fd1498Szrj tree target_ssa, iter_result;
538038fd1498Szrj tree type = TREE_TYPE (gimple_get_lhs (stmt));
538138fd1498Szrj tree powi_fndecl = mathfn_built_in (type, BUILT_IN_POWI);
538238fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
538338fd1498Szrj gimple *mul_stmt, *pow_stmt;
538438fd1498Szrj
538538fd1498Szrj /* Nothing to do if BUILT_IN_POWI doesn't exist for this type and
538638fd1498Szrj target. */
538738fd1498Szrj if (!powi_fndecl)
538838fd1498Szrj return NULL_TREE;
538938fd1498Szrj
539038fd1498Szrj /* Allocate the repeated factor vector. */
539138fd1498Szrj repeat_factor_vec.create (10);
539238fd1498Szrj
539338fd1498Szrj /* Scan the OPS vector for all SSA names in the product and build
539438fd1498Szrj up a vector of occurrence counts for each factor. */
539538fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe)
539638fd1498Szrj {
539738fd1498Szrj if (TREE_CODE (oe->op) == SSA_NAME)
539838fd1498Szrj {
539938fd1498Szrj FOR_EACH_VEC_ELT (repeat_factor_vec, j, rf1)
540038fd1498Szrj {
540138fd1498Szrj if (rf1->factor == oe->op)
540238fd1498Szrj {
540338fd1498Szrj rf1->count += oe->count;
540438fd1498Szrj break;
540538fd1498Szrj }
540638fd1498Szrj }
540738fd1498Szrj
540838fd1498Szrj if (j >= repeat_factor_vec.length ())
540938fd1498Szrj {
541038fd1498Szrj rfnew.factor = oe->op;
541138fd1498Szrj rfnew.rank = oe->rank;
541238fd1498Szrj rfnew.count = oe->count;
541338fd1498Szrj rfnew.repr = NULL_TREE;
541438fd1498Szrj repeat_factor_vec.safe_push (rfnew);
541538fd1498Szrj }
541638fd1498Szrj }
541738fd1498Szrj }
541838fd1498Szrj
541938fd1498Szrj /* Sort the repeated factor vector by (a) increasing occurrence count,
542038fd1498Szrj and (b) decreasing rank. */
542138fd1498Szrj repeat_factor_vec.qsort (compare_repeat_factors);
542238fd1498Szrj
542338fd1498Szrj /* It is generally best to combine as many base factors as possible
542438fd1498Szrj into a product before applying __builtin_powi to the result.
542538fd1498Szrj However, the sort order chosen for the repeated factor vector
542638fd1498Szrj allows us to cache partial results for the product of the base
542738fd1498Szrj factors for subsequent use. When we already have a cached partial
542838fd1498Szrj result from a previous iteration, it is best to make use of it
542938fd1498Szrj before looking for another __builtin_pow opportunity.
543038fd1498Szrj
543138fd1498Szrj As an example, consider x * x * y * y * y * z * z * z * z.
543238fd1498Szrj We want to first compose the product x * y * z, raise it to the
543338fd1498Szrj second power, then multiply this by y * z, and finally multiply
543438fd1498Szrj by z. This can be done in 5 multiplies provided we cache y * z
543538fd1498Szrj for use in both expressions:
543638fd1498Szrj
543738fd1498Szrj t1 = y * z
543838fd1498Szrj t2 = t1 * x
543938fd1498Szrj t3 = t2 * t2
544038fd1498Szrj t4 = t1 * t3
544138fd1498Szrj result = t4 * z
544238fd1498Szrj
544338fd1498Szrj If we instead ignored the cached y * z and first multiplied by
544438fd1498Szrj the __builtin_pow opportunity z * z, we would get the inferior:
544538fd1498Szrj
544638fd1498Szrj t1 = y * z
544738fd1498Szrj t2 = t1 * x
544838fd1498Szrj t3 = t2 * t2
544938fd1498Szrj t4 = z * z
545038fd1498Szrj t5 = t3 * t4
545138fd1498Szrj result = t5 * y */
545238fd1498Szrj
545338fd1498Szrj vec_len = repeat_factor_vec.length ();
545438fd1498Szrj
545538fd1498Szrj /* Repeatedly look for opportunities to create a builtin_powi call. */
545638fd1498Szrj while (true)
545738fd1498Szrj {
545838fd1498Szrj HOST_WIDE_INT power;
545938fd1498Szrj
546038fd1498Szrj /* First look for the largest cached product of factors from
546138fd1498Szrj preceding iterations. If found, create a builtin_powi for
546238fd1498Szrj it if the minimum occurrence count for its factors is at
546338fd1498Szrj least 2, or just use this cached product as our next
546438fd1498Szrj multiplicand if the minimum occurrence count is 1. */
546538fd1498Szrj FOR_EACH_VEC_ELT (repeat_factor_vec, j, rf1)
546638fd1498Szrj {
546738fd1498Szrj if (rf1->repr && rf1->count > 0)
546838fd1498Szrj break;
546938fd1498Szrj }
547038fd1498Szrj
547138fd1498Szrj if (j < vec_len)
547238fd1498Szrj {
547338fd1498Szrj power = rf1->count;
547438fd1498Szrj
547538fd1498Szrj if (power == 1)
547638fd1498Szrj {
547738fd1498Szrj iter_result = rf1->repr;
547838fd1498Szrj
547938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
548038fd1498Szrj {
548138fd1498Szrj unsigned elt;
548238fd1498Szrj repeat_factor *rf;
548338fd1498Szrj fputs ("Multiplying by cached product ", dump_file);
548438fd1498Szrj for (elt = j; elt < vec_len; elt++)
548538fd1498Szrj {
548638fd1498Szrj rf = &repeat_factor_vec[elt];
548738fd1498Szrj print_generic_expr (dump_file, rf->factor);
548838fd1498Szrj if (elt < vec_len - 1)
548938fd1498Szrj fputs (" * ", dump_file);
549038fd1498Szrj }
549138fd1498Szrj fputs ("\n", dump_file);
549238fd1498Szrj }
549338fd1498Szrj }
549438fd1498Szrj else
549538fd1498Szrj {
549638fd1498Szrj iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
549738fd1498Szrj pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
549838fd1498Szrj build_int_cst (integer_type_node,
549938fd1498Szrj power));
550038fd1498Szrj gimple_call_set_lhs (pow_stmt, iter_result);
550138fd1498Szrj gimple_set_location (pow_stmt, gimple_location (stmt));
550238fd1498Szrj gimple_set_uid (pow_stmt, gimple_uid (stmt));
550338fd1498Szrj gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
550438fd1498Szrj
550538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
550638fd1498Szrj {
550738fd1498Szrj unsigned elt;
550838fd1498Szrj repeat_factor *rf;
550938fd1498Szrj fputs ("Building __builtin_pow call for cached product (",
551038fd1498Szrj dump_file);
551138fd1498Szrj for (elt = j; elt < vec_len; elt++)
551238fd1498Szrj {
551338fd1498Szrj rf = &repeat_factor_vec[elt];
551438fd1498Szrj print_generic_expr (dump_file, rf->factor);
551538fd1498Szrj if (elt < vec_len - 1)
551638fd1498Szrj fputs (" * ", dump_file);
551738fd1498Szrj }
551838fd1498Szrj fprintf (dump_file, ")^" HOST_WIDE_INT_PRINT_DEC"\n",
551938fd1498Szrj power);
552038fd1498Szrj }
552138fd1498Szrj }
552238fd1498Szrj }
552338fd1498Szrj else
552438fd1498Szrj {
552538fd1498Szrj /* Otherwise, find the first factor in the repeated factor
552638fd1498Szrj vector whose occurrence count is at least 2. If no such
552738fd1498Szrj factor exists, there are no builtin_powi opportunities
552838fd1498Szrj remaining. */
552938fd1498Szrj FOR_EACH_VEC_ELT (repeat_factor_vec, j, rf1)
553038fd1498Szrj {
553138fd1498Szrj if (rf1->count >= 2)
553238fd1498Szrj break;
553338fd1498Szrj }
553438fd1498Szrj
553538fd1498Szrj if (j >= vec_len)
553638fd1498Szrj break;
553738fd1498Szrj
553838fd1498Szrj power = rf1->count;
553938fd1498Szrj
554038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
554138fd1498Szrj {
554238fd1498Szrj unsigned elt;
554338fd1498Szrj repeat_factor *rf;
554438fd1498Szrj fputs ("Building __builtin_pow call for (", dump_file);
554538fd1498Szrj for (elt = j; elt < vec_len; elt++)
554638fd1498Szrj {
554738fd1498Szrj rf = &repeat_factor_vec[elt];
554838fd1498Szrj print_generic_expr (dump_file, rf->factor);
554938fd1498Szrj if (elt < vec_len - 1)
555038fd1498Szrj fputs (" * ", dump_file);
555138fd1498Szrj }
555238fd1498Szrj fprintf (dump_file, ")^" HOST_WIDE_INT_PRINT_DEC"\n", power);
555338fd1498Szrj }
555438fd1498Szrj
555538fd1498Szrj reassociate_stats.pows_created++;
555638fd1498Szrj
555738fd1498Szrj /* Visit each element of the vector in reverse order (so that
555838fd1498Szrj high-occurrence elements are visited first, and within the
555938fd1498Szrj same occurrence count, lower-ranked elements are visited
556038fd1498Szrj first). Form a linear product of all elements in this order
556138fd1498Szrj whose occurrencce count is at least that of element J.
556238fd1498Szrj Record the SSA name representing the product of each element
556338fd1498Szrj with all subsequent elements in the vector. */
556438fd1498Szrj if (j == vec_len - 1)
556538fd1498Szrj rf1->repr = rf1->factor;
556638fd1498Szrj else
556738fd1498Szrj {
556838fd1498Szrj for (ii = vec_len - 2; ii >= (int)j; ii--)
556938fd1498Szrj {
557038fd1498Szrj tree op1, op2;
557138fd1498Szrj
557238fd1498Szrj rf1 = &repeat_factor_vec[ii];
557338fd1498Szrj rf2 = &repeat_factor_vec[ii + 1];
557438fd1498Szrj
557538fd1498Szrj /* Init the last factor's representative to be itself. */
557638fd1498Szrj if (!rf2->repr)
557738fd1498Szrj rf2->repr = rf2->factor;
557838fd1498Szrj
557938fd1498Szrj op1 = rf1->factor;
558038fd1498Szrj op2 = rf2->repr;
558138fd1498Szrj
558238fd1498Szrj target_ssa = make_temp_ssa_name (type, NULL, "reassocpow");
558338fd1498Szrj mul_stmt = gimple_build_assign (target_ssa, MULT_EXPR,
558438fd1498Szrj op1, op2);
558538fd1498Szrj gimple_set_location (mul_stmt, gimple_location (stmt));
558638fd1498Szrj gimple_set_uid (mul_stmt, gimple_uid (stmt));
558738fd1498Szrj gsi_insert_before (&gsi, mul_stmt, GSI_SAME_STMT);
558838fd1498Szrj rf1->repr = target_ssa;
558938fd1498Szrj
559038fd1498Szrj /* Don't reprocess the multiply we just introduced. */
559138fd1498Szrj gimple_set_visited (mul_stmt, true);
559238fd1498Szrj }
559338fd1498Szrj }
559438fd1498Szrj
559538fd1498Szrj /* Form a call to __builtin_powi for the maximum product
559638fd1498Szrj just formed, raised to the power obtained earlier. */
559738fd1498Szrj rf1 = &repeat_factor_vec[j];
559838fd1498Szrj iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
559938fd1498Szrj pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
560038fd1498Szrj build_int_cst (integer_type_node,
560138fd1498Szrj power));
560238fd1498Szrj gimple_call_set_lhs (pow_stmt, iter_result);
560338fd1498Szrj gimple_set_location (pow_stmt, gimple_location (stmt));
560438fd1498Szrj gimple_set_uid (pow_stmt, gimple_uid (stmt));
560538fd1498Szrj gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
560638fd1498Szrj }
560738fd1498Szrj
560838fd1498Szrj /* If we previously formed at least one other builtin_powi call,
560938fd1498Szrj form the product of this one and those others. */
561038fd1498Szrj if (result)
561138fd1498Szrj {
561238fd1498Szrj tree new_result = make_temp_ssa_name (type, NULL, "reassocpow");
561338fd1498Szrj mul_stmt = gimple_build_assign (new_result, MULT_EXPR,
561438fd1498Szrj result, iter_result);
561538fd1498Szrj gimple_set_location (mul_stmt, gimple_location (stmt));
561638fd1498Szrj gimple_set_uid (mul_stmt, gimple_uid (stmt));
561738fd1498Szrj gsi_insert_before (&gsi, mul_stmt, GSI_SAME_STMT);
561838fd1498Szrj gimple_set_visited (mul_stmt, true);
561938fd1498Szrj result = new_result;
562038fd1498Szrj }
562138fd1498Szrj else
562238fd1498Szrj result = iter_result;
562338fd1498Szrj
562438fd1498Szrj /* Decrement the occurrence count of each element in the product
562538fd1498Szrj by the count found above, and remove this many copies of each
562638fd1498Szrj factor from OPS. */
562738fd1498Szrj for (i = j; i < vec_len; i++)
562838fd1498Szrj {
562938fd1498Szrj unsigned k = power;
563038fd1498Szrj unsigned n;
563138fd1498Szrj
563238fd1498Szrj rf1 = &repeat_factor_vec[i];
563338fd1498Szrj rf1->count -= power;
563438fd1498Szrj
563538fd1498Szrj FOR_EACH_VEC_ELT_REVERSE (*ops, n, oe)
563638fd1498Szrj {
563738fd1498Szrj if (oe->op == rf1->factor)
563838fd1498Szrj {
563938fd1498Szrj if (oe->count <= k)
564038fd1498Szrj {
564138fd1498Szrj ops->ordered_remove (n);
564238fd1498Szrj k -= oe->count;
564338fd1498Szrj
564438fd1498Szrj if (k == 0)
564538fd1498Szrj break;
564638fd1498Szrj }
564738fd1498Szrj else
564838fd1498Szrj {
564938fd1498Szrj oe->count -= k;
565038fd1498Szrj break;
565138fd1498Szrj }
565238fd1498Szrj }
565338fd1498Szrj }
565438fd1498Szrj }
565538fd1498Szrj }
565638fd1498Szrj
565738fd1498Szrj /* At this point all elements in the repeated factor vector have a
565838fd1498Szrj remaining occurrence count of 0 or 1, and those with a count of 1
565938fd1498Szrj don't have cached representatives. Re-sort the ops vector and
566038fd1498Szrj clean up. */
566138fd1498Szrj ops->qsort (sort_by_operand_rank);
566238fd1498Szrj repeat_factor_vec.release ();
566338fd1498Szrj
566438fd1498Szrj /* Return the final product computed herein. Note that there may
566538fd1498Szrj still be some elements with single occurrence count left in OPS;
566638fd1498Szrj those will be handled by the normal reassociation logic. */
566738fd1498Szrj return result;
566838fd1498Szrj }
566938fd1498Szrj
567038fd1498Szrj /* Attempt to optimize
567138fd1498Szrj CST1 * copysign (CST2, y) -> copysign (CST1 * CST2, y) if CST1 > 0, or
567238fd1498Szrj CST1 * copysign (CST2, y) -> -copysign (CST1 * CST2, y) if CST1 < 0. */
567338fd1498Szrj
567438fd1498Szrj static void
attempt_builtin_copysign(vec<operand_entry * > * ops)567538fd1498Szrj attempt_builtin_copysign (vec<operand_entry *> *ops)
567638fd1498Szrj {
567738fd1498Szrj operand_entry *oe;
567838fd1498Szrj unsigned int i;
567938fd1498Szrj unsigned int length = ops->length ();
568038fd1498Szrj tree cst = ops->last ()->op;
568138fd1498Szrj
568238fd1498Szrj if (length == 1 || TREE_CODE (cst) != REAL_CST)
568338fd1498Szrj return;
568438fd1498Szrj
568538fd1498Szrj FOR_EACH_VEC_ELT (*ops, i, oe)
568638fd1498Szrj {
568738fd1498Szrj if (TREE_CODE (oe->op) == SSA_NAME
568838fd1498Szrj && has_single_use (oe->op))
568938fd1498Szrj {
569038fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (oe->op);
569138fd1498Szrj if (gcall *old_call = dyn_cast <gcall *> (def_stmt))
569238fd1498Szrj {
569338fd1498Szrj tree arg0, arg1;
569438fd1498Szrj switch (gimple_call_combined_fn (old_call))
569538fd1498Szrj {
569638fd1498Szrj CASE_CFN_COPYSIGN:
569738fd1498Szrj CASE_CFN_COPYSIGN_FN:
569838fd1498Szrj arg0 = gimple_call_arg (old_call, 0);
569938fd1498Szrj arg1 = gimple_call_arg (old_call, 1);
570038fd1498Szrj /* The first argument of copysign must be a constant,
570138fd1498Szrj otherwise there's nothing to do. */
570238fd1498Szrj if (TREE_CODE (arg0) == REAL_CST)
570338fd1498Szrj {
570438fd1498Szrj tree type = TREE_TYPE (arg0);
570538fd1498Szrj tree mul = const_binop (MULT_EXPR, type, cst, arg0);
570638fd1498Szrj /* If we couldn't fold to a single constant, skip it.
570738fd1498Szrj That happens e.g. for inexact multiplication when
570838fd1498Szrj -frounding-math. */
570938fd1498Szrj if (mul == NULL_TREE)
571038fd1498Szrj break;
571138fd1498Szrj /* Instead of adjusting OLD_CALL, let's build a new
571238fd1498Szrj call to not leak the LHS and prevent keeping bogus
571338fd1498Szrj debug statements. DCE will clean up the old call. */
571438fd1498Szrj gcall *new_call;
571538fd1498Szrj if (gimple_call_internal_p (old_call))
571638fd1498Szrj new_call = gimple_build_call_internal
571738fd1498Szrj (IFN_COPYSIGN, 2, mul, arg1);
571838fd1498Szrj else
571938fd1498Szrj new_call = gimple_build_call
572038fd1498Szrj (gimple_call_fndecl (old_call), 2, mul, arg1);
572138fd1498Szrj tree lhs = make_ssa_name (type);
572238fd1498Szrj gimple_call_set_lhs (new_call, lhs);
572338fd1498Szrj gimple_set_location (new_call,
572438fd1498Szrj gimple_location (old_call));
572538fd1498Szrj insert_stmt_after (new_call, old_call);
572638fd1498Szrj /* We've used the constant, get rid of it. */
572738fd1498Szrj ops->pop ();
572838fd1498Szrj bool cst1_neg = real_isneg (TREE_REAL_CST_PTR (cst));
572938fd1498Szrj /* Handle the CST1 < 0 case by negating the result. */
573038fd1498Szrj if (cst1_neg)
573138fd1498Szrj {
573238fd1498Szrj tree negrhs = make_ssa_name (TREE_TYPE (lhs));
573338fd1498Szrj gimple *negate_stmt
573438fd1498Szrj = gimple_build_assign (negrhs, NEGATE_EXPR, lhs);
573538fd1498Szrj insert_stmt_after (negate_stmt, new_call);
573638fd1498Szrj oe->op = negrhs;
573738fd1498Szrj }
573838fd1498Szrj else
573938fd1498Szrj oe->op = lhs;
574038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
574138fd1498Szrj {
574238fd1498Szrj fprintf (dump_file, "Optimizing copysign: ");
574338fd1498Szrj print_generic_expr (dump_file, cst);
574438fd1498Szrj fprintf (dump_file, " * COPYSIGN (");
574538fd1498Szrj print_generic_expr (dump_file, arg0);
574638fd1498Szrj fprintf (dump_file, ", ");
574738fd1498Szrj print_generic_expr (dump_file, arg1);
574838fd1498Szrj fprintf (dump_file, ") into %sCOPYSIGN (",
574938fd1498Szrj cst1_neg ? "-" : "");
575038fd1498Szrj print_generic_expr (dump_file, mul);
575138fd1498Szrj fprintf (dump_file, ", ");
575238fd1498Szrj print_generic_expr (dump_file, arg1);
575338fd1498Szrj fprintf (dump_file, "\n");
575438fd1498Szrj }
575538fd1498Szrj return;
575638fd1498Szrj }
575738fd1498Szrj break;
575838fd1498Szrj default:
575938fd1498Szrj break;
576038fd1498Szrj }
576138fd1498Szrj }
576238fd1498Szrj }
576338fd1498Szrj }
576438fd1498Szrj }
576538fd1498Szrj
576638fd1498Szrj /* Transform STMT at *GSI into a copy by replacing its rhs with NEW_RHS. */
576738fd1498Szrj
576838fd1498Szrj static void
transform_stmt_to_copy(gimple_stmt_iterator * gsi,gimple * stmt,tree new_rhs)576938fd1498Szrj transform_stmt_to_copy (gimple_stmt_iterator *gsi, gimple *stmt, tree new_rhs)
577038fd1498Szrj {
577138fd1498Szrj tree rhs1;
577238fd1498Szrj
577338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
577438fd1498Szrj {
577538fd1498Szrj fprintf (dump_file, "Transforming ");
577638fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
577738fd1498Szrj }
577838fd1498Szrj
577938fd1498Szrj rhs1 = gimple_assign_rhs1 (stmt);
578038fd1498Szrj gimple_assign_set_rhs_from_tree (gsi, new_rhs);
578138fd1498Szrj update_stmt (stmt);
578238fd1498Szrj remove_visited_stmt_chain (rhs1);
578338fd1498Szrj
578438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
578538fd1498Szrj {
578638fd1498Szrj fprintf (dump_file, " into ");
578738fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
578838fd1498Szrj }
578938fd1498Szrj }
579038fd1498Szrj
579138fd1498Szrj /* Transform STMT at *GSI into a multiply of RHS1 and RHS2. */
579238fd1498Szrj
579338fd1498Szrj static void
transform_stmt_to_multiply(gimple_stmt_iterator * gsi,gimple * stmt,tree rhs1,tree rhs2)579438fd1498Szrj transform_stmt_to_multiply (gimple_stmt_iterator *gsi, gimple *stmt,
579538fd1498Szrj tree rhs1, tree rhs2)
579638fd1498Szrj {
579738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
579838fd1498Szrj {
579938fd1498Szrj fprintf (dump_file, "Transforming ");
580038fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
580138fd1498Szrj }
580238fd1498Szrj
580338fd1498Szrj gimple_assign_set_rhs_with_ops (gsi, MULT_EXPR, rhs1, rhs2);
580438fd1498Szrj update_stmt (gsi_stmt (*gsi));
580538fd1498Szrj remove_visited_stmt_chain (rhs1);
580638fd1498Szrj
580738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
580838fd1498Szrj {
580938fd1498Szrj fprintf (dump_file, " into ");
581038fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
581138fd1498Szrj }
581238fd1498Szrj }
581338fd1498Szrj
581438fd1498Szrj /* Reassociate expressions in basic block BB and its post-dominator as
581538fd1498Szrj children.
581638fd1498Szrj
581738fd1498Szrj Bubble up return status from maybe_optimize_range_tests. */
581838fd1498Szrj
581938fd1498Szrj static bool
reassociate_bb(basic_block bb)582038fd1498Szrj reassociate_bb (basic_block bb)
582138fd1498Szrj {
582238fd1498Szrj gimple_stmt_iterator gsi;
582338fd1498Szrj basic_block son;
582438fd1498Szrj gimple *stmt = last_stmt (bb);
582538fd1498Szrj bool cfg_cleanup_needed = false;
582638fd1498Szrj
582738fd1498Szrj if (stmt && !gimple_visited_p (stmt))
582838fd1498Szrj cfg_cleanup_needed |= maybe_optimize_range_tests (stmt);
582938fd1498Szrj
583038fd1498Szrj for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
583138fd1498Szrj {
583238fd1498Szrj stmt = gsi_stmt (gsi);
583338fd1498Szrj
583438fd1498Szrj if (is_gimple_assign (stmt)
583538fd1498Szrj && !stmt_could_throw_p (stmt))
583638fd1498Szrj {
583738fd1498Szrj tree lhs, rhs1, rhs2;
583838fd1498Szrj enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
583938fd1498Szrj
584038fd1498Szrj /* If this is not a gimple binary expression, there is
584138fd1498Szrj nothing for us to do with it. */
584238fd1498Szrj if (get_gimple_rhs_class (rhs_code) != GIMPLE_BINARY_RHS)
584338fd1498Szrj continue;
584438fd1498Szrj
584538fd1498Szrj /* If this was part of an already processed statement,
584638fd1498Szrj we don't need to touch it again. */
584738fd1498Szrj if (gimple_visited_p (stmt))
584838fd1498Szrj {
584938fd1498Szrj /* This statement might have become dead because of previous
585038fd1498Szrj reassociations. */
585138fd1498Szrj if (has_zero_uses (gimple_get_lhs (stmt)))
585238fd1498Szrj {
585338fd1498Szrj reassoc_remove_stmt (&gsi);
585438fd1498Szrj release_defs (stmt);
585538fd1498Szrj /* We might end up removing the last stmt above which
585638fd1498Szrj places the iterator to the end of the sequence.
585738fd1498Szrj Reset it to the last stmt in this case which might
585838fd1498Szrj be the end of the sequence as well if we removed
585938fd1498Szrj the last statement of the sequence. In which case
586038fd1498Szrj we need to bail out. */
586138fd1498Szrj if (gsi_end_p (gsi))
586238fd1498Szrj {
586338fd1498Szrj gsi = gsi_last_bb (bb);
586438fd1498Szrj if (gsi_end_p (gsi))
586538fd1498Szrj break;
586638fd1498Szrj }
586738fd1498Szrj }
586838fd1498Szrj continue;
586938fd1498Szrj }
587038fd1498Szrj
587138fd1498Szrj lhs = gimple_assign_lhs (stmt);
587238fd1498Szrj rhs1 = gimple_assign_rhs1 (stmt);
587338fd1498Szrj rhs2 = gimple_assign_rhs2 (stmt);
587438fd1498Szrj
587538fd1498Szrj /* For non-bit or min/max operations we can't associate
587638fd1498Szrj all types. Verify that here. */
587738fd1498Szrj if (rhs_code != BIT_IOR_EXPR
587838fd1498Szrj && rhs_code != BIT_AND_EXPR
587938fd1498Szrj && rhs_code != BIT_XOR_EXPR
588038fd1498Szrj && rhs_code != MIN_EXPR
588138fd1498Szrj && rhs_code != MAX_EXPR
588238fd1498Szrj && (!can_reassociate_p (lhs)
588338fd1498Szrj || !can_reassociate_p (rhs1)
588438fd1498Szrj || !can_reassociate_p (rhs2)))
588538fd1498Szrj continue;
588638fd1498Szrj
588738fd1498Szrj if (associative_tree_code (rhs_code))
588838fd1498Szrj {
588938fd1498Szrj auto_vec<operand_entry *> ops;
589038fd1498Szrj tree powi_result = NULL_TREE;
589138fd1498Szrj bool is_vector = VECTOR_TYPE_P (TREE_TYPE (lhs));
589238fd1498Szrj
589338fd1498Szrj /* There may be no immediate uses left by the time we
589438fd1498Szrj get here because we may have eliminated them all. */
589538fd1498Szrj if (TREE_CODE (lhs) == SSA_NAME && has_zero_uses (lhs))
589638fd1498Szrj continue;
589738fd1498Szrj
589838fd1498Szrj gimple_set_visited (stmt, true);
589938fd1498Szrj linearize_expr_tree (&ops, stmt, true, true);
590038fd1498Szrj ops.qsort (sort_by_operand_rank);
590138fd1498Szrj int orig_len = ops.length ();
590238fd1498Szrj optimize_ops_list (rhs_code, &ops);
590338fd1498Szrj if (undistribute_ops_list (rhs_code, &ops,
590438fd1498Szrj loop_containing_stmt (stmt)))
590538fd1498Szrj {
590638fd1498Szrj ops.qsort (sort_by_operand_rank);
590738fd1498Szrj optimize_ops_list (rhs_code, &ops);
590838fd1498Szrj }
590938fd1498Szrj
591038fd1498Szrj if (rhs_code == PLUS_EXPR
591138fd1498Szrj && transform_add_to_multiply (&ops))
591238fd1498Szrj ops.qsort (sort_by_operand_rank);
591338fd1498Szrj
591438fd1498Szrj if (rhs_code == BIT_IOR_EXPR || rhs_code == BIT_AND_EXPR)
591538fd1498Szrj {
591638fd1498Szrj if (is_vector)
591738fd1498Szrj optimize_vec_cond_expr (rhs_code, &ops);
591838fd1498Szrj else
591938fd1498Szrj optimize_range_tests (rhs_code, &ops, NULL);
592038fd1498Szrj }
592138fd1498Szrj
592238fd1498Szrj if (rhs_code == MULT_EXPR && !is_vector)
592338fd1498Szrj {
592438fd1498Szrj attempt_builtin_copysign (&ops);
592538fd1498Szrj
592638fd1498Szrj if (reassoc_insert_powi_p
592738fd1498Szrj && flag_unsafe_math_optimizations)
592838fd1498Szrj powi_result = attempt_builtin_powi (stmt, &ops);
592938fd1498Szrj }
593038fd1498Szrj
593138fd1498Szrj operand_entry *last;
593238fd1498Szrj bool negate_result = false;
593338fd1498Szrj if (ops.length () > 1
593438fd1498Szrj && rhs_code == MULT_EXPR)
593538fd1498Szrj {
593638fd1498Szrj last = ops.last ();
593738fd1498Szrj if ((integer_minus_onep (last->op)
593838fd1498Szrj || real_minus_onep (last->op))
593938fd1498Szrj && !HONOR_SNANS (TREE_TYPE (lhs))
594038fd1498Szrj && (!HONOR_SIGNED_ZEROS (TREE_TYPE (lhs))
594138fd1498Szrj || !COMPLEX_FLOAT_TYPE_P (TREE_TYPE (lhs))))
594238fd1498Szrj {
594338fd1498Szrj ops.pop ();
594438fd1498Szrj negate_result = true;
594538fd1498Szrj }
594638fd1498Szrj }
594738fd1498Szrj
594838fd1498Szrj tree new_lhs = lhs;
594938fd1498Szrj /* If the operand vector is now empty, all operands were
595038fd1498Szrj consumed by the __builtin_powi optimization. */
595138fd1498Szrj if (ops.length () == 0)
595238fd1498Szrj transform_stmt_to_copy (&gsi, stmt, powi_result);
595338fd1498Szrj else if (ops.length () == 1)
595438fd1498Szrj {
595538fd1498Szrj tree last_op = ops.last ()->op;
595638fd1498Szrj
595738fd1498Szrj /* If the stmt that defines operand has to be inserted, insert it
595838fd1498Szrj before the use. */
595938fd1498Szrj if (ops.last ()->stmt_to_insert)
596038fd1498Szrj insert_stmt_before_use (stmt, ops.last ()->stmt_to_insert);
596138fd1498Szrj if (powi_result)
596238fd1498Szrj transform_stmt_to_multiply (&gsi, stmt, last_op,
596338fd1498Szrj powi_result);
596438fd1498Szrj else
596538fd1498Szrj transform_stmt_to_copy (&gsi, stmt, last_op);
596638fd1498Szrj }
596738fd1498Szrj else
596838fd1498Szrj {
596938fd1498Szrj machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
597038fd1498Szrj int ops_num = ops.length ();
597138fd1498Szrj int width = get_reassociation_width (ops_num, rhs_code, mode);
597238fd1498Szrj
597338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
597438fd1498Szrj fprintf (dump_file,
597538fd1498Szrj "Width = %d was chosen for reassociation\n", width);
597638fd1498Szrj
597738fd1498Szrj
597838fd1498Szrj /* For binary bit operations, if there are at least 3
597938fd1498Szrj operands and the last last operand in OPS is a constant,
598038fd1498Szrj move it to the front. This helps ensure that we generate
598138fd1498Szrj (X & Y) & C rather than (X & C) & Y. The former will
598238fd1498Szrj often match a canonical bit test when we get to RTL. */
598338fd1498Szrj if (ops.length () > 2
598438fd1498Szrj && (rhs_code == BIT_AND_EXPR
598538fd1498Szrj || rhs_code == BIT_IOR_EXPR
598638fd1498Szrj || rhs_code == BIT_XOR_EXPR)
598738fd1498Szrj && TREE_CODE (ops.last ()->op) == INTEGER_CST)
598838fd1498Szrj std::swap (*ops[0], *ops[ops_num - 1]);
598938fd1498Szrj
599038fd1498Szrj if (width > 1
599138fd1498Szrj && ops.length () > 3)
599238fd1498Szrj rewrite_expr_tree_parallel (as_a <gassign *> (stmt),
599338fd1498Szrj width, ops);
599438fd1498Szrj else
599538fd1498Szrj {
599638fd1498Szrj /* When there are three operands left, we want
599738fd1498Szrj to make sure the ones that get the double
599838fd1498Szrj binary op are chosen wisely. */
599938fd1498Szrj int len = ops.length ();
600038fd1498Szrj if (len >= 3)
600138fd1498Szrj swap_ops_for_binary_stmt (ops, len - 3, stmt);
600238fd1498Szrj
600338fd1498Szrj new_lhs = rewrite_expr_tree (stmt, 0, ops,
600438fd1498Szrj powi_result != NULL
600538fd1498Szrj || negate_result,
600638fd1498Szrj len != orig_len);
600738fd1498Szrj }
600838fd1498Szrj
600938fd1498Szrj /* If we combined some repeated factors into a
601038fd1498Szrj __builtin_powi call, multiply that result by the
601138fd1498Szrj reassociated operands. */
601238fd1498Szrj if (powi_result)
601338fd1498Szrj {
601438fd1498Szrj gimple *mul_stmt, *lhs_stmt = SSA_NAME_DEF_STMT (lhs);
601538fd1498Szrj tree type = TREE_TYPE (lhs);
601638fd1498Szrj tree target_ssa = make_temp_ssa_name (type, NULL,
601738fd1498Szrj "reassocpow");
601838fd1498Szrj gimple_set_lhs (lhs_stmt, target_ssa);
601938fd1498Szrj update_stmt (lhs_stmt);
602038fd1498Szrj if (lhs != new_lhs)
602138fd1498Szrj {
602238fd1498Szrj target_ssa = new_lhs;
602338fd1498Szrj new_lhs = lhs;
602438fd1498Szrj }
602538fd1498Szrj mul_stmt = gimple_build_assign (lhs, MULT_EXPR,
602638fd1498Szrj powi_result, target_ssa);
602738fd1498Szrj gimple_set_location (mul_stmt, gimple_location (stmt));
602838fd1498Szrj gimple_set_uid (mul_stmt, gimple_uid (stmt));
602938fd1498Szrj gsi_insert_after (&gsi, mul_stmt, GSI_NEW_STMT);
603038fd1498Szrj }
603138fd1498Szrj }
603238fd1498Szrj
603338fd1498Szrj if (negate_result)
603438fd1498Szrj {
603538fd1498Szrj stmt = SSA_NAME_DEF_STMT (lhs);
603638fd1498Szrj tree tmp = make_ssa_name (TREE_TYPE (lhs));
603738fd1498Szrj gimple_set_lhs (stmt, tmp);
603838fd1498Szrj if (lhs != new_lhs)
603938fd1498Szrj tmp = new_lhs;
604038fd1498Szrj gassign *neg_stmt = gimple_build_assign (lhs, NEGATE_EXPR,
604138fd1498Szrj tmp);
604238fd1498Szrj gimple_set_uid (neg_stmt, gimple_uid (stmt));
604338fd1498Szrj gsi_insert_after (&gsi, neg_stmt, GSI_NEW_STMT);
604438fd1498Szrj update_stmt (stmt);
604538fd1498Szrj }
604638fd1498Szrj }
604738fd1498Szrj }
604838fd1498Szrj }
604938fd1498Szrj for (son = first_dom_son (CDI_POST_DOMINATORS, bb);
605038fd1498Szrj son;
605138fd1498Szrj son = next_dom_son (CDI_POST_DOMINATORS, son))
605238fd1498Szrj cfg_cleanup_needed |= reassociate_bb (son);
605338fd1498Szrj
605438fd1498Szrj return cfg_cleanup_needed;
605538fd1498Szrj }
605638fd1498Szrj
605738fd1498Szrj /* Add jumps around shifts for range tests turned into bit tests.
605838fd1498Szrj For each SSA_NAME VAR we have code like:
605938fd1498Szrj VAR = ...; // final stmt of range comparison
606038fd1498Szrj // bit test here...;
606138fd1498Szrj OTHERVAR = ...; // final stmt of the bit test sequence
606238fd1498Szrj RES = VAR | OTHERVAR;
606338fd1498Szrj Turn the above into:
606438fd1498Szrj VAR = ...;
606538fd1498Szrj if (VAR != 0)
606638fd1498Szrj goto <l3>;
606738fd1498Szrj else
606838fd1498Szrj goto <l2>;
606938fd1498Szrj <l2>:
607038fd1498Szrj // bit test here...;
607138fd1498Szrj OTHERVAR = ...;
607238fd1498Szrj <l3>:
607338fd1498Szrj # RES = PHI<1(l1), OTHERVAR(l2)>; */
607438fd1498Szrj
607538fd1498Szrj static void
branch_fixup(void)607638fd1498Szrj branch_fixup (void)
607738fd1498Szrj {
607838fd1498Szrj tree var;
607938fd1498Szrj unsigned int i;
608038fd1498Szrj
608138fd1498Szrj FOR_EACH_VEC_ELT (reassoc_branch_fixups, i, var)
608238fd1498Szrj {
608338fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (var);
608438fd1498Szrj gimple *use_stmt;
608538fd1498Szrj use_operand_p use;
608638fd1498Szrj bool ok = single_imm_use (var, &use, &use_stmt);
608738fd1498Szrj gcc_assert (ok
608838fd1498Szrj && is_gimple_assign (use_stmt)
608938fd1498Szrj && gimple_assign_rhs_code (use_stmt) == BIT_IOR_EXPR
609038fd1498Szrj && gimple_bb (def_stmt) == gimple_bb (use_stmt));
609138fd1498Szrj
609238fd1498Szrj basic_block cond_bb = gimple_bb (def_stmt);
609338fd1498Szrj basic_block then_bb = split_block (cond_bb, def_stmt)->dest;
609438fd1498Szrj basic_block merge_bb = split_block (then_bb, use_stmt)->dest;
609538fd1498Szrj
609638fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (def_stmt);
609738fd1498Szrj gimple *g = gimple_build_cond (NE_EXPR, var,
609838fd1498Szrj build_zero_cst (TREE_TYPE (var)),
609938fd1498Szrj NULL_TREE, NULL_TREE);
610038fd1498Szrj location_t loc = gimple_location (use_stmt);
610138fd1498Szrj gimple_set_location (g, loc);
610238fd1498Szrj gsi_insert_after (&gsi, g, GSI_NEW_STMT);
610338fd1498Szrj
610438fd1498Szrj edge etrue = make_edge (cond_bb, merge_bb, EDGE_TRUE_VALUE);
610538fd1498Szrj etrue->probability = profile_probability::even ();
610638fd1498Szrj edge efalse = find_edge (cond_bb, then_bb);
610738fd1498Szrj efalse->flags = EDGE_FALSE_VALUE;
610838fd1498Szrj efalse->probability -= etrue->probability;
610938fd1498Szrj then_bb->count -= etrue->count ();
611038fd1498Szrj
611138fd1498Szrj tree othervar = NULL_TREE;
611238fd1498Szrj if (gimple_assign_rhs1 (use_stmt) == var)
611338fd1498Szrj othervar = gimple_assign_rhs2 (use_stmt);
611438fd1498Szrj else if (gimple_assign_rhs2 (use_stmt) == var)
611538fd1498Szrj othervar = gimple_assign_rhs1 (use_stmt);
611638fd1498Szrj else
611738fd1498Szrj gcc_unreachable ();
611838fd1498Szrj tree lhs = gimple_assign_lhs (use_stmt);
611938fd1498Szrj gphi *phi = create_phi_node (lhs, merge_bb);
612038fd1498Szrj add_phi_arg (phi, build_one_cst (TREE_TYPE (lhs)), etrue, loc);
612138fd1498Szrj add_phi_arg (phi, othervar, single_succ_edge (then_bb), loc);
612238fd1498Szrj gsi = gsi_for_stmt (use_stmt);
612338fd1498Szrj gsi_remove (&gsi, true);
612438fd1498Szrj
612538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, merge_bb, cond_bb);
612638fd1498Szrj set_immediate_dominator (CDI_POST_DOMINATORS, cond_bb, merge_bb);
612738fd1498Szrj }
612838fd1498Szrj reassoc_branch_fixups.release ();
612938fd1498Szrj }
613038fd1498Szrj
613138fd1498Szrj void dump_ops_vector (FILE *file, vec<operand_entry *> ops);
613238fd1498Szrj void debug_ops_vector (vec<operand_entry *> ops);
613338fd1498Szrj
613438fd1498Szrj /* Dump the operand entry vector OPS to FILE. */
613538fd1498Szrj
613638fd1498Szrj void
dump_ops_vector(FILE * file,vec<operand_entry * > ops)613738fd1498Szrj dump_ops_vector (FILE *file, vec<operand_entry *> ops)
613838fd1498Szrj {
613938fd1498Szrj operand_entry *oe;
614038fd1498Szrj unsigned int i;
614138fd1498Szrj
614238fd1498Szrj FOR_EACH_VEC_ELT (ops, i, oe)
614338fd1498Szrj {
614438fd1498Szrj fprintf (file, "Op %d -> rank: %d, tree: ", i, oe->rank);
614538fd1498Szrj print_generic_expr (file, oe->op);
614638fd1498Szrj fprintf (file, "\n");
614738fd1498Szrj }
614838fd1498Szrj }
614938fd1498Szrj
615038fd1498Szrj /* Dump the operand entry vector OPS to STDERR. */
615138fd1498Szrj
615238fd1498Szrj DEBUG_FUNCTION void
debug_ops_vector(vec<operand_entry * > ops)615338fd1498Szrj debug_ops_vector (vec<operand_entry *> ops)
615438fd1498Szrj {
615538fd1498Szrj dump_ops_vector (stderr, ops);
615638fd1498Szrj }
615738fd1498Szrj
615838fd1498Szrj /* Bubble up return status from reassociate_bb. */
615938fd1498Szrj
616038fd1498Szrj static bool
do_reassoc(void)616138fd1498Szrj do_reassoc (void)
616238fd1498Szrj {
616338fd1498Szrj break_up_subtract_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
616438fd1498Szrj return reassociate_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
616538fd1498Szrj }
616638fd1498Szrj
616738fd1498Szrj /* Initialize the reassociation pass. */
616838fd1498Szrj
616938fd1498Szrj static void
init_reassoc(void)617038fd1498Szrj init_reassoc (void)
617138fd1498Szrj {
617238fd1498Szrj int i;
617338fd1498Szrj long rank = 2;
617438fd1498Szrj int *bbs = XNEWVEC (int, n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS);
617538fd1498Szrj
617638fd1498Szrj /* Find the loops, so that we can prevent moving calculations in
617738fd1498Szrj them. */
617838fd1498Szrj loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
617938fd1498Szrj
618038fd1498Szrj memset (&reassociate_stats, 0, sizeof (reassociate_stats));
618138fd1498Szrj
618238fd1498Szrj next_operand_entry_id = 0;
618338fd1498Szrj
618438fd1498Szrj /* Reverse RPO (Reverse Post Order) will give us something where
618538fd1498Szrj deeper loops come later. */
618638fd1498Szrj pre_and_rev_post_order_compute (NULL, bbs, false);
618738fd1498Szrj bb_rank = XCNEWVEC (long, last_basic_block_for_fn (cfun));
618838fd1498Szrj operand_rank = new hash_map<tree, long>;
618938fd1498Szrj
619038fd1498Szrj /* Give each default definition a distinct rank. This includes
619138fd1498Szrj parameters and the static chain. Walk backwards over all
619238fd1498Szrj SSA names so that we get proper rank ordering according
619338fd1498Szrj to tree_swap_operands_p. */
619438fd1498Szrj for (i = num_ssa_names - 1; i > 0; --i)
619538fd1498Szrj {
619638fd1498Szrj tree name = ssa_name (i);
619738fd1498Szrj if (name && SSA_NAME_IS_DEFAULT_DEF (name))
619838fd1498Szrj insert_operand_rank (name, ++rank);
619938fd1498Szrj }
620038fd1498Szrj
620138fd1498Szrj /* Set up rank for each BB */
620238fd1498Szrj for (i = 0; i < n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; i++)
620338fd1498Szrj bb_rank[bbs[i]] = ++rank << 16;
620438fd1498Szrj
620538fd1498Szrj free (bbs);
620638fd1498Szrj calculate_dominance_info (CDI_POST_DOMINATORS);
620738fd1498Szrj plus_negates = vNULL;
620838fd1498Szrj }
620938fd1498Szrj
621038fd1498Szrj /* Cleanup after the reassociation pass, and print stats if
621138fd1498Szrj requested. */
621238fd1498Szrj
621338fd1498Szrj static void
fini_reassoc(void)621438fd1498Szrj fini_reassoc (void)
621538fd1498Szrj {
621638fd1498Szrj statistics_counter_event (cfun, "Linearized",
621738fd1498Szrj reassociate_stats.linearized);
621838fd1498Szrj statistics_counter_event (cfun, "Constants eliminated",
621938fd1498Szrj reassociate_stats.constants_eliminated);
622038fd1498Szrj statistics_counter_event (cfun, "Ops eliminated",
622138fd1498Szrj reassociate_stats.ops_eliminated);
622238fd1498Szrj statistics_counter_event (cfun, "Statements rewritten",
622338fd1498Szrj reassociate_stats.rewritten);
622438fd1498Szrj statistics_counter_event (cfun, "Built-in pow[i] calls encountered",
622538fd1498Szrj reassociate_stats.pows_encountered);
622638fd1498Szrj statistics_counter_event (cfun, "Built-in powi calls created",
622738fd1498Szrj reassociate_stats.pows_created);
622838fd1498Szrj
622938fd1498Szrj delete operand_rank;
623038fd1498Szrj operand_entry_pool.release ();
623138fd1498Szrj free (bb_rank);
623238fd1498Szrj plus_negates.release ();
623338fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS);
623438fd1498Szrj loop_optimizer_finalize ();
623538fd1498Szrj }
623638fd1498Szrj
623738fd1498Szrj /* Gate and execute functions for Reassociation. If INSERT_POWI_P, enable
623838fd1498Szrj insertion of __builtin_powi calls.
623938fd1498Szrj
624038fd1498Szrj Returns TODO_cfg_cleanup if a CFG cleanup pass is desired due to
624138fd1498Szrj optimization of a gimple conditional. Otherwise returns zero. */
624238fd1498Szrj
624338fd1498Szrj static unsigned int
execute_reassoc(bool insert_powi_p)624438fd1498Szrj execute_reassoc (bool insert_powi_p)
624538fd1498Szrj {
624638fd1498Szrj reassoc_insert_powi_p = insert_powi_p;
624738fd1498Szrj
624838fd1498Szrj init_reassoc ();
624938fd1498Szrj
625038fd1498Szrj bool cfg_cleanup_needed;
625138fd1498Szrj cfg_cleanup_needed = do_reassoc ();
625238fd1498Szrj repropagate_negates ();
625338fd1498Szrj branch_fixup ();
625438fd1498Szrj
625538fd1498Szrj fini_reassoc ();
625638fd1498Szrj return cfg_cleanup_needed ? TODO_cleanup_cfg : 0;
625738fd1498Szrj }
625838fd1498Szrj
625938fd1498Szrj namespace {
626038fd1498Szrj
626138fd1498Szrj const pass_data pass_data_reassoc =
626238fd1498Szrj {
626338fd1498Szrj GIMPLE_PASS, /* type */
626438fd1498Szrj "reassoc", /* name */
626538fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
626638fd1498Szrj TV_TREE_REASSOC, /* tv_id */
626738fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
626838fd1498Szrj 0, /* properties_provided */
626938fd1498Szrj 0, /* properties_destroyed */
627038fd1498Szrj 0, /* todo_flags_start */
627138fd1498Szrj TODO_update_ssa_only_virtuals, /* todo_flags_finish */
627238fd1498Szrj };
627338fd1498Szrj
627438fd1498Szrj class pass_reassoc : public gimple_opt_pass
627538fd1498Szrj {
627638fd1498Szrj public:
pass_reassoc(gcc::context * ctxt)627738fd1498Szrj pass_reassoc (gcc::context *ctxt)
627838fd1498Szrj : gimple_opt_pass (pass_data_reassoc, ctxt), insert_powi_p (false)
627938fd1498Szrj {}
628038fd1498Szrj
628138fd1498Szrj /* opt_pass methods: */
clone()628238fd1498Szrj opt_pass * clone () { return new pass_reassoc (m_ctxt); }
set_pass_param(unsigned int n,bool param)628338fd1498Szrj void set_pass_param (unsigned int n, bool param)
628438fd1498Szrj {
628538fd1498Szrj gcc_assert (n == 0);
628638fd1498Szrj insert_powi_p = param;
628738fd1498Szrj }
gate(function *)628838fd1498Szrj virtual bool gate (function *) { return flag_tree_reassoc != 0; }
execute(function *)628938fd1498Szrj virtual unsigned int execute (function *)
629038fd1498Szrj { return execute_reassoc (insert_powi_p); }
629138fd1498Szrj
629238fd1498Szrj private:
629338fd1498Szrj /* Enable insertion of __builtin_powi calls during execute_reassoc. See
629438fd1498Szrj point 3a in the pass header comment. */
629538fd1498Szrj bool insert_powi_p;
629638fd1498Szrj }; // class pass_reassoc
629738fd1498Szrj
629838fd1498Szrj } // anon namespace
629938fd1498Szrj
630038fd1498Szrj gimple_opt_pass *
make_pass_reassoc(gcc::context * ctxt)630138fd1498Szrj make_pass_reassoc (gcc::context *ctxt)
630238fd1498Szrj {
630338fd1498Szrj return new pass_reassoc (ctxt);
630438fd1498Szrj }
6305