138fd1498Szrj /* Backward propagation of indirect loads through PHIs.
238fd1498Szrj Copyright (C) 2007-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Richard Guenther <rguenther@suse.de>
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 "tree.h"
2638fd1498Szrj #include "gimple.h"
2738fd1498Szrj #include "tree-pass.h"
2838fd1498Szrj #include "ssa.h"
2938fd1498Szrj #include "gimple-pretty-print.h"
3038fd1498Szrj #include "fold-const.h"
3138fd1498Szrj #include "tree-eh.h"
3238fd1498Szrj #include "gimplify.h"
3338fd1498Szrj #include "gimple-iterator.h"
3438fd1498Szrj #include "stor-layout.h"
3538fd1498Szrj #include "tree-ssa-loop.h"
3638fd1498Szrj
3738fd1498Szrj /* This pass propagates indirect loads through the PHI node for its
3838fd1498Szrj address to make the load source possibly non-addressable and to
3938fd1498Szrj allow for PHI optimization to trigger.
4038fd1498Szrj
4138fd1498Szrj For example the pass changes
4238fd1498Szrj
4338fd1498Szrj # addr_1 = PHI <&a, &b>
4438fd1498Szrj tmp_1 = *addr_1;
4538fd1498Szrj
4638fd1498Szrj to
4738fd1498Szrj
4838fd1498Szrj # tmp_1 = PHI <a, b>
4938fd1498Szrj
5038fd1498Szrj but also handles more complex scenarios like
5138fd1498Szrj
5238fd1498Szrj D.2077_2 = &this_1(D)->a1;
5338fd1498Szrj ...
5438fd1498Szrj
5538fd1498Szrj # b_12 = PHI <&c(2), D.2077_2(3)>
5638fd1498Szrj D.2114_13 = *b_12;
5738fd1498Szrj ...
5838fd1498Szrj
5938fd1498Szrj # b_15 = PHI <b_12(4), &b(5)>
6038fd1498Szrj D.2080_5 = &this_1(D)->a0;
6138fd1498Szrj ...
6238fd1498Szrj
6338fd1498Szrj # b_18 = PHI <D.2080_5(6), &c(7)>
6438fd1498Szrj ...
6538fd1498Szrj
6638fd1498Szrj # b_21 = PHI <b_15(8), b_18(9)>
6738fd1498Szrj D.2076_8 = *b_21;
6838fd1498Szrj
6938fd1498Szrj where the addresses loaded are defined by PHIs itself.
7038fd1498Szrj The above happens for
7138fd1498Szrj
7238fd1498Szrj std::max(std::min(a0, c), std::min(std::max(a1, c), b))
7338fd1498Szrj
7438fd1498Szrj where this pass transforms it to a form later PHI optimization
7538fd1498Szrj recognizes and transforms it to the simple
7638fd1498Szrj
7738fd1498Szrj D.2109_10 = this_1(D)->a1;
7838fd1498Szrj D.2110_11 = c;
7938fd1498Szrj D.2114_31 = MAX_EXPR <D.2109_10, D.2110_11>;
8038fd1498Szrj D.2115_14 = b;
8138fd1498Szrj D.2125_17 = MIN_EXPR <D.2115_14, D.2114_31>;
8238fd1498Szrj D.2119_16 = this_1(D)->a0;
8338fd1498Szrj D.2124_32 = MIN_EXPR <D.2110_11, D.2119_16>;
8438fd1498Szrj D.2076_33 = MAX_EXPR <D.2125_17, D.2124_32>;
8538fd1498Szrj
8638fd1498Szrj The pass does a dominator walk processing loads using a basic-block
8738fd1498Szrj local analysis and stores the result for use by transformations on
8838fd1498Szrj dominated basic-blocks. */
8938fd1498Szrj
9038fd1498Szrj
9138fd1498Szrj /* Structure to keep track of the value of a dereferenced PHI result
9238fd1498Szrj and the virtual operand used for that dereference. */
9338fd1498Szrj
9438fd1498Szrj struct phiprop_d
9538fd1498Szrj {
9638fd1498Szrj tree value;
9738fd1498Szrj tree vuse;
9838fd1498Szrj };
9938fd1498Szrj
10038fd1498Szrj /* Verify if the value recorded for NAME in PHIVN is still valid at
10138fd1498Szrj the start of basic block BB. */
10238fd1498Szrj
10338fd1498Szrj static bool
phivn_valid_p(struct phiprop_d * phivn,tree name,basic_block bb)10438fd1498Szrj phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
10538fd1498Szrj {
10638fd1498Szrj tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
10738fd1498Szrj gimple *use_stmt;
10838fd1498Szrj imm_use_iterator ui2;
10938fd1498Szrj bool ok = true;
11038fd1498Szrj
11138fd1498Szrj /* The def stmts of the virtual uses need to be dominated by bb. */
11238fd1498Szrj gcc_assert (vuse != NULL_TREE);
11338fd1498Szrj
11438fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
11538fd1498Szrj {
11638fd1498Szrj /* If BB does not dominate a VDEF, the value is invalid. */
11738fd1498Szrj if ((gimple_vdef (use_stmt) != NULL_TREE
11838fd1498Szrj || gimple_code (use_stmt) == GIMPLE_PHI)
11938fd1498Szrj && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
12038fd1498Szrj {
12138fd1498Szrj ok = false;
12238fd1498Szrj BREAK_FROM_IMM_USE_STMT (ui2);
12338fd1498Szrj }
12438fd1498Szrj }
12538fd1498Szrj
12638fd1498Szrj return ok;
12738fd1498Szrj }
12838fd1498Szrj
12938fd1498Szrj /* Insert a new phi node for the dereference of PHI at basic_block
13038fd1498Szrj BB with the virtual operands from USE_STMT. */
13138fd1498Szrj
13238fd1498Szrj static tree
phiprop_insert_phi(basic_block bb,gphi * phi,gimple * use_stmt,struct phiprop_d * phivn,size_t n)13338fd1498Szrj phiprop_insert_phi (basic_block bb, gphi *phi, gimple *use_stmt,
13438fd1498Szrj struct phiprop_d *phivn, size_t n)
13538fd1498Szrj {
13638fd1498Szrj tree res;
13738fd1498Szrj gphi *new_phi = NULL;
13838fd1498Szrj edge_iterator ei;
13938fd1498Szrj edge e;
14038fd1498Szrj
14138fd1498Szrj gcc_assert (is_gimple_assign (use_stmt)
14238fd1498Szrj && gimple_assign_rhs_code (use_stmt) == MEM_REF);
14338fd1498Szrj
14438fd1498Szrj /* Build a new PHI node to replace the definition of
14538fd1498Szrj the indirect reference lhs. */
14638fd1498Szrj res = gimple_assign_lhs (use_stmt);
14738fd1498Szrj if (TREE_CODE (res) == SSA_NAME)
14838fd1498Szrj new_phi = create_phi_node (res, bb);
14938fd1498Szrj
15038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
15138fd1498Szrj {
15238fd1498Szrj fprintf (dump_file, "Inserting PHI for result of load ");
15338fd1498Szrj print_gimple_stmt (dump_file, use_stmt, 0);
15438fd1498Szrj }
15538fd1498Szrj
15638fd1498Szrj /* Add PHI arguments for each edge inserting loads of the
15738fd1498Szrj addressable operands. */
15838fd1498Szrj FOR_EACH_EDGE (e, ei, bb->preds)
15938fd1498Szrj {
16038fd1498Szrj tree old_arg, new_var;
16138fd1498Szrj gassign *tmp;
16238fd1498Szrj source_location locus;
16338fd1498Szrj
16438fd1498Szrj old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
16538fd1498Szrj locus = gimple_phi_arg_location_from_edge (phi, e);
16638fd1498Szrj while (TREE_CODE (old_arg) == SSA_NAME
16738fd1498Szrj && (SSA_NAME_VERSION (old_arg) >= n
16838fd1498Szrj || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
16938fd1498Szrj {
17038fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (old_arg);
17138fd1498Szrj old_arg = gimple_assign_rhs1 (def_stmt);
17238fd1498Szrj locus = gimple_location (def_stmt);
17338fd1498Szrj }
17438fd1498Szrj
17538fd1498Szrj if (TREE_CODE (old_arg) == SSA_NAME)
17638fd1498Szrj {
17738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
17838fd1498Szrj {
17938fd1498Szrj fprintf (dump_file, " for edge defining ");
18038fd1498Szrj print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
18138fd1498Szrj fprintf (dump_file, " reusing PHI result ");
18238fd1498Szrj print_generic_expr (dump_file,
18338fd1498Szrj phivn[SSA_NAME_VERSION (old_arg)].value);
18438fd1498Szrj fprintf (dump_file, "\n");
18538fd1498Szrj }
18638fd1498Szrj /* Reuse a formerly created dereference. */
18738fd1498Szrj new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
18838fd1498Szrj }
18938fd1498Szrj else
19038fd1498Szrj {
19138fd1498Szrj tree rhs = gimple_assign_rhs1 (use_stmt);
19238fd1498Szrj gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
19338fd1498Szrj if (TREE_CODE (res) == SSA_NAME)
19438fd1498Szrj new_var = make_ssa_name (TREE_TYPE (rhs));
19538fd1498Szrj else
19638fd1498Szrj new_var = unshare_expr (res);
19738fd1498Szrj if (!is_gimple_min_invariant (old_arg))
19838fd1498Szrj old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
19938fd1498Szrj else
20038fd1498Szrj old_arg = unshare_expr (old_arg);
20138fd1498Szrj tmp = gimple_build_assign (new_var,
20238fd1498Szrj fold_build2 (MEM_REF, TREE_TYPE (rhs),
20338fd1498Szrj old_arg,
20438fd1498Szrj TREE_OPERAND (rhs, 1)));
20538fd1498Szrj gimple_set_location (tmp, locus);
20638fd1498Szrj
20738fd1498Szrj gsi_insert_on_edge (e, tmp);
20838fd1498Szrj update_stmt (tmp);
20938fd1498Szrj
21038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
21138fd1498Szrj {
21238fd1498Szrj fprintf (dump_file, " for edge defining ");
21338fd1498Szrj print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e));
21438fd1498Szrj fprintf (dump_file, " inserting load ");
21538fd1498Szrj print_gimple_stmt (dump_file, tmp, 0);
21638fd1498Szrj }
21738fd1498Szrj }
21838fd1498Szrj
21938fd1498Szrj if (new_phi)
22038fd1498Szrj add_phi_arg (new_phi, new_var, e, locus);
22138fd1498Szrj }
22238fd1498Szrj
22338fd1498Szrj if (new_phi)
22438fd1498Szrj {
22538fd1498Szrj update_stmt (new_phi);
22638fd1498Szrj
22738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
22838fd1498Szrj print_gimple_stmt (dump_file, new_phi, 0);
22938fd1498Szrj }
23038fd1498Szrj
23138fd1498Szrj return res;
23238fd1498Szrj }
23338fd1498Szrj
23438fd1498Szrj /* Verify if *idx is available at *DATA. */
23538fd1498Szrj
23638fd1498Szrj static bool
chk_uses(tree,tree * idx,void * data)23738fd1498Szrj chk_uses (tree, tree *idx, void *data)
23838fd1498Szrj {
23938fd1498Szrj basic_block dom = (basic_block) data;
24038fd1498Szrj if (TREE_CODE (*idx) == SSA_NAME)
24138fd1498Szrj return (SSA_NAME_IS_DEFAULT_DEF (*idx)
24238fd1498Szrj || ! dominated_by_p (CDI_DOMINATORS,
24338fd1498Szrj gimple_bb (SSA_NAME_DEF_STMT (*idx)), dom));
24438fd1498Szrj return true;
24538fd1498Szrj }
24638fd1498Szrj
24738fd1498Szrj /* Propagate between the phi node arguments of PHI in BB and phi result
24838fd1498Szrj users. For now this matches
24938fd1498Szrj # p_2 = PHI <&x, &y>
25038fd1498Szrj <Lx>:;
25138fd1498Szrj p_3 = p_2;
25238fd1498Szrj z_2 = *p_3;
25338fd1498Szrj and converts it to
25438fd1498Szrj # z_2 = PHI <x, y>
25538fd1498Szrj <Lx>:;
25638fd1498Szrj Returns true if a transformation was done and edge insertions
25738fd1498Szrj need to be committed. Global data PHIVN and N is used to track
25838fd1498Szrj past transformation results. We need to be especially careful here
25938fd1498Szrj with aliasing issues as we are moving memory reads. */
26038fd1498Szrj
26138fd1498Szrj static bool
propagate_with_phi(basic_block bb,gphi * phi,struct phiprop_d * phivn,size_t n)26238fd1498Szrj propagate_with_phi (basic_block bb, gphi *phi, struct phiprop_d *phivn,
26338fd1498Szrj size_t n)
26438fd1498Szrj {
26538fd1498Szrj tree ptr = PHI_RESULT (phi);
26638fd1498Szrj gimple *use_stmt;
26738fd1498Szrj tree res = NULL_TREE;
26838fd1498Szrj gimple_stmt_iterator gsi;
26938fd1498Szrj imm_use_iterator ui;
27038fd1498Szrj use_operand_p arg_p, use;
27138fd1498Szrj ssa_op_iter i;
27238fd1498Szrj bool phi_inserted;
27338fd1498Szrj bool changed;
27438fd1498Szrj tree type = NULL_TREE;
27538fd1498Szrj
27638fd1498Szrj if (!POINTER_TYPE_P (TREE_TYPE (ptr))
27738fd1498Szrj || (!is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr)))
27838fd1498Szrj && TYPE_MODE (TREE_TYPE (TREE_TYPE (ptr))) == BLKmode))
27938fd1498Szrj return false;
28038fd1498Szrj
28138fd1498Szrj /* Check if we can "cheaply" dereference all phi arguments. */
28238fd1498Szrj FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_USE)
28338fd1498Szrj {
28438fd1498Szrj tree arg = USE_FROM_PTR (arg_p);
28538fd1498Szrj /* Walk the ssa chain until we reach a ssa name we already
28638fd1498Szrj created a value for or we reach a definition of the form
28738fd1498Szrj ssa_name_n = &var; */
28838fd1498Szrj while (TREE_CODE (arg) == SSA_NAME
28938fd1498Szrj && !SSA_NAME_IS_DEFAULT_DEF (arg)
29038fd1498Szrj && (SSA_NAME_VERSION (arg) >= n
29138fd1498Szrj || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
29238fd1498Szrj {
29338fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
29438fd1498Szrj if (!gimple_assign_single_p (def_stmt))
29538fd1498Szrj return false;
29638fd1498Szrj arg = gimple_assign_rhs1 (def_stmt);
29738fd1498Szrj }
29838fd1498Szrj if (TREE_CODE (arg) != ADDR_EXPR
29938fd1498Szrj && !(TREE_CODE (arg) == SSA_NAME
30038fd1498Szrj && SSA_NAME_VERSION (arg) < n
30138fd1498Szrj && phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
30238fd1498Szrj && (!type
30338fd1498Szrj || types_compatible_p
30438fd1498Szrj (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value)))
30538fd1498Szrj && phivn_valid_p (phivn, arg, bb)))
30638fd1498Szrj return false;
30738fd1498Szrj if (!type
30838fd1498Szrj && TREE_CODE (arg) == SSA_NAME)
30938fd1498Szrj type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
31038fd1498Szrj }
31138fd1498Szrj
31238fd1498Szrj /* Find a dereferencing use. First follow (single use) ssa
31338fd1498Szrj copy chains for ptr. */
31438fd1498Szrj while (single_imm_use (ptr, &use, &use_stmt)
31538fd1498Szrj && gimple_assign_ssa_name_copy_p (use_stmt))
31638fd1498Szrj ptr = gimple_assign_lhs (use_stmt);
31738fd1498Szrj
31838fd1498Szrj /* Replace the first dereference of *ptr if there is one and if we
31938fd1498Szrj can move the loads to the place of the ptr phi node. */
32038fd1498Szrj phi_inserted = false;
32138fd1498Szrj changed = false;
32238fd1498Szrj FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
32338fd1498Szrj {
32438fd1498Szrj gimple *def_stmt;
32538fd1498Szrj tree vuse;
32638fd1498Szrj
32738fd1498Szrj /* Only replace loads in blocks that post-dominate the PHI node. That
32838fd1498Szrj makes sure we don't end up speculating loads. */
32938fd1498Szrj if (!dominated_by_p (CDI_POST_DOMINATORS,
33038fd1498Szrj bb, gimple_bb (use_stmt)))
33138fd1498Szrj continue;
33238fd1498Szrj
33338fd1498Szrj /* Check whether this is a load of *ptr. */
33438fd1498Szrj if (!(is_gimple_assign (use_stmt)
33538fd1498Szrj && gimple_assign_rhs_code (use_stmt) == MEM_REF
33638fd1498Szrj && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
33738fd1498Szrj && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
33838fd1498Szrj && (!type
33938fd1498Szrj || types_compatible_p
34038fd1498Szrj (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
34138fd1498Szrj /* We cannot replace a load that may throw or is volatile. */
34238fd1498Szrj && !stmt_can_throw_internal (use_stmt)))
34338fd1498Szrj continue;
34438fd1498Szrj
34538fd1498Szrj /* Check if we can move the loads. The def stmt of the virtual use
34638fd1498Szrj needs to be in a different basic block dominating bb. When the
34738fd1498Szrj def is an edge-inserted one we know it dominates us. */
34838fd1498Szrj vuse = gimple_vuse (use_stmt);
34938fd1498Szrj def_stmt = SSA_NAME_DEF_STMT (vuse);
35038fd1498Szrj if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
35138fd1498Szrj && (gimple_bb (def_stmt) == bb
35238fd1498Szrj || (gimple_bb (def_stmt)
35338fd1498Szrj && !dominated_by_p (CDI_DOMINATORS,
35438fd1498Szrj bb, gimple_bb (def_stmt)))))
35538fd1498Szrj goto next;
35638fd1498Szrj
35738fd1498Szrj /* Found a proper dereference with an aggregate copy. Just
35838fd1498Szrj insert aggregate copies on the edges instead. */
35938fd1498Szrj if (!is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (use_stmt))))
36038fd1498Szrj {
36138fd1498Szrj if (!gimple_vdef (use_stmt))
36238fd1498Szrj goto next;
36338fd1498Szrj
36438fd1498Szrj /* As we replicate the lhs on each incoming edge all
36538fd1498Szrj used SSA names have to be available there. */
36638fd1498Szrj if (! for_each_index (gimple_assign_lhs_ptr (use_stmt),
36738fd1498Szrj chk_uses,
36838fd1498Szrj get_immediate_dominator (CDI_DOMINATORS,
36938fd1498Szrj gimple_bb (phi))))
37038fd1498Szrj goto next;
37138fd1498Szrj
37238fd1498Szrj gimple *vuse_stmt;
37338fd1498Szrj imm_use_iterator vui;
37438fd1498Szrj use_operand_p vuse_p;
37538fd1498Szrj /* In order to move the aggregate copies earlier, make sure
37638fd1498Szrj there are no statements that could read from memory
37738fd1498Szrj aliasing the lhs in between the start of bb and use_stmt.
37838fd1498Szrj As we require use_stmt to have a VDEF above, loads after
37938fd1498Szrj use_stmt will use a different virtual SSA_NAME. */
38038fd1498Szrj FOR_EACH_IMM_USE_FAST (vuse_p, vui, vuse)
38138fd1498Szrj {
38238fd1498Szrj vuse_stmt = USE_STMT (vuse_p);
38338fd1498Szrj if (vuse_stmt == use_stmt)
38438fd1498Szrj continue;
38538fd1498Szrj if (!dominated_by_p (CDI_DOMINATORS,
38638fd1498Szrj gimple_bb (vuse_stmt), bb))
38738fd1498Szrj continue;
38838fd1498Szrj if (ref_maybe_used_by_stmt_p (vuse_stmt,
38938fd1498Szrj gimple_assign_lhs (use_stmt)))
39038fd1498Szrj goto next;
39138fd1498Szrj }
39238fd1498Szrj
39338fd1498Szrj phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
39438fd1498Szrj
39538fd1498Szrj /* Remove old stmt. The phi is taken care of by DCE. */
39638fd1498Szrj gsi = gsi_for_stmt (use_stmt);
39738fd1498Szrj /* Unlinking the VDEF here is fine as we are sure that we process
39838fd1498Szrj stmts in execution order due to aggregate copies having VDEFs
39938fd1498Szrj and we emit loads on the edges in the very same order.
40038fd1498Szrj We get multiple copies (or intermediate register loads) handled
40138fd1498Szrj only by walking PHIs or immediate uses in a lucky order though,
40238fd1498Szrj so we could signal the caller to re-start iterating over PHIs
40338fd1498Szrj when we come here which would make it quadratic in the number
40438fd1498Szrj of PHIs. */
40538fd1498Szrj unlink_stmt_vdef (use_stmt);
40638fd1498Szrj gsi_remove (&gsi, true);
40738fd1498Szrj
40838fd1498Szrj changed = true;
40938fd1498Szrj }
41038fd1498Szrj
41138fd1498Szrj /* Found a proper dereference. Insert a phi node if this
41238fd1498Szrj is the first load transformation. */
41338fd1498Szrj else if (!phi_inserted)
41438fd1498Szrj {
41538fd1498Szrj res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
41638fd1498Szrj type = TREE_TYPE (res);
41738fd1498Szrj
41838fd1498Szrj /* Remember the value we created for *ptr. */
41938fd1498Szrj phivn[SSA_NAME_VERSION (ptr)].value = res;
42038fd1498Szrj phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
42138fd1498Szrj
42238fd1498Szrj /* Remove old stmt. The phi is taken care of by DCE, if we
42338fd1498Szrj want to delete it here we also have to delete all intermediate
42438fd1498Szrj copies. */
42538fd1498Szrj gsi = gsi_for_stmt (use_stmt);
42638fd1498Szrj gsi_remove (&gsi, true);
42738fd1498Szrj
42838fd1498Szrj phi_inserted = true;
42938fd1498Szrj changed = true;
43038fd1498Szrj }
43138fd1498Szrj else
43238fd1498Szrj {
43338fd1498Szrj /* Further replacements are easy, just make a copy out of the
43438fd1498Szrj load. */
43538fd1498Szrj gimple_assign_set_rhs1 (use_stmt, res);
43638fd1498Szrj update_stmt (use_stmt);
43738fd1498Szrj changed = true;
43838fd1498Szrj }
43938fd1498Szrj
44038fd1498Szrj next:;
44138fd1498Szrj /* Continue searching for a proper dereference. */
44238fd1498Szrj }
44338fd1498Szrj
44438fd1498Szrj return changed;
44538fd1498Szrj }
44638fd1498Szrj
44738fd1498Szrj /* Main entry for phiprop pass. */
44838fd1498Szrj
44938fd1498Szrj namespace {
45038fd1498Szrj
45138fd1498Szrj const pass_data pass_data_phiprop =
45238fd1498Szrj {
45338fd1498Szrj GIMPLE_PASS, /* type */
45438fd1498Szrj "phiprop", /* name */
45538fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
45638fd1498Szrj TV_TREE_PHIPROP, /* tv_id */
45738fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
45838fd1498Szrj 0, /* properties_provided */
45938fd1498Szrj 0, /* properties_destroyed */
46038fd1498Szrj 0, /* todo_flags_start */
46138fd1498Szrj TODO_update_ssa, /* todo_flags_finish */
46238fd1498Szrj };
46338fd1498Szrj
46438fd1498Szrj class pass_phiprop : public gimple_opt_pass
46538fd1498Szrj {
46638fd1498Szrj public:
pass_phiprop(gcc::context * ctxt)46738fd1498Szrj pass_phiprop (gcc::context *ctxt)
46838fd1498Szrj : gimple_opt_pass (pass_data_phiprop, ctxt)
46938fd1498Szrj {}
47038fd1498Szrj
47138fd1498Szrj /* opt_pass methods: */
gate(function *)47238fd1498Szrj virtual bool gate (function *) { return flag_tree_phiprop; }
47338fd1498Szrj virtual unsigned int execute (function *);
47438fd1498Szrj
47538fd1498Szrj }; // class pass_phiprop
47638fd1498Szrj
47738fd1498Szrj unsigned int
execute(function * fun)47838fd1498Szrj pass_phiprop::execute (function *fun)
47938fd1498Szrj {
48038fd1498Szrj vec<basic_block> bbs;
48138fd1498Szrj struct phiprop_d *phivn;
48238fd1498Szrj bool did_something = false;
48338fd1498Szrj basic_block bb;
48438fd1498Szrj gphi_iterator gsi;
48538fd1498Szrj unsigned i;
48638fd1498Szrj size_t n;
48738fd1498Szrj
48838fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
48938fd1498Szrj calculate_dominance_info (CDI_POST_DOMINATORS);
49038fd1498Szrj
49138fd1498Szrj n = num_ssa_names;
49238fd1498Szrj phivn = XCNEWVEC (struct phiprop_d, n);
49338fd1498Szrj
49438fd1498Szrj /* Walk the dominator tree in preorder. */
49538fd1498Szrj bbs = get_all_dominated_blocks (CDI_DOMINATORS,
49638fd1498Szrj single_succ (ENTRY_BLOCK_PTR_FOR_FN (fun)));
49738fd1498Szrj FOR_EACH_VEC_ELT (bbs, i, bb)
498*58e805e6Szrj {
499*58e805e6Szrj /* Since we're going to move dereferences across predecessor
500*58e805e6Szrj edges avoid blocks with abnormal predecessors. */
501*58e805e6Szrj if (bb_has_abnormal_pred (bb))
502*58e805e6Szrj continue;
50338fd1498Szrj for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
50438fd1498Szrj did_something |= propagate_with_phi (bb, gsi.phi (), phivn, n);
505*58e805e6Szrj }
50638fd1498Szrj
50738fd1498Szrj if (did_something)
50838fd1498Szrj gsi_commit_edge_inserts ();
50938fd1498Szrj
51038fd1498Szrj bbs.release ();
51138fd1498Szrj free (phivn);
51238fd1498Szrj
51338fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS);
51438fd1498Szrj
51538fd1498Szrj return 0;
51638fd1498Szrj }
51738fd1498Szrj
51838fd1498Szrj } // anon namespace
51938fd1498Szrj
52038fd1498Szrj gimple_opt_pass *
make_pass_phiprop(gcc::context * ctxt)52138fd1498Szrj make_pass_phiprop (gcc::context *ctxt)
52238fd1498Szrj {
52338fd1498Szrj return new pass_phiprop (ctxt);
52438fd1498Szrj }
525