2004-05-13 08:41:07 +02:00
|
|
|
/* Dead store elimination
|
|
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
This file is part of GCC.
|
|
|
|
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with GCC; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "coretypes.h"
|
|
|
|
#include "tm.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "ggc.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "rtl.h"
|
|
|
|
#include "tm_p.h"
|
|
|
|
#include "basic-block.h"
|
|
|
|
#include "timevar.h"
|
|
|
|
#include "diagnostic.h"
|
|
|
|
#include "tree-flow.h"
|
|
|
|
#include "tree-pass.h"
|
|
|
|
#include "tree-dump.h"
|
|
|
|
#include "domwalk.h"
|
|
|
|
#include "flags.h"
|
|
|
|
|
|
|
|
/* This file implements dead store elimination.
|
|
|
|
|
|
|
|
A dead store is a store into a memory location which will later be
|
|
|
|
overwritten by another store without any intervening loads. In this
|
|
|
|
case the earlier store can be deleted.
|
|
|
|
|
|
|
|
In our SSA + virtual operand world we use immediate uses of virtual
|
|
|
|
operands to detect dead stores. If a store's virtual definition
|
|
|
|
is used precisely once by a later store to the same location which
|
|
|
|
post dominates the first store, then the first store is dead.
|
|
|
|
|
|
|
|
The single use of the store's virtual definition ensures that
|
|
|
|
there are no intervening aliased loads and the requirement that
|
|
|
|
the second load post dominate the first ensures that if the earlier
|
|
|
|
store executes, then the later stores will execute before the function
|
|
|
|
exits.
|
|
|
|
|
|
|
|
It may help to think of this as first moving the earlier store to
|
|
|
|
the point immediately before the later store. Again, the single
|
c-typeck.c, [...]: Fix comment typos.
* c-typeck.c, cfgexpand.c, ddg.c, ddg.h, df.c, fold-const.c,
gcov.c, gimplify.c, modulo-sched.c, passes.c, tree-cfg.c,
tree-mudflap.c, tree-nrv.c, tree-outof-ssa.c, tree-ssa-dom.c,
tree-ssa-dse.c, tree-ssa-operands.c, tree-ssa-pre.c,
tree-tailcall.c: Fix comment typos. Follow spelling
conventions.
From-SVN: r83703
2004-06-26 07:03:55 +02:00
|
|
|
use of the virtual definition and the post-dominance relationship
|
2004-05-13 08:41:07 +02:00
|
|
|
ensure that such movement would be safe. Clearly if there are
|
|
|
|
back to back stores, then the second is redundant.
|
|
|
|
|
|
|
|
Reviewing section 10.7.2 in Morgan's "Building an Optimizing Compiler"
|
|
|
|
may also help in understanding this code since it discusses the
|
|
|
|
relationship between dead store and redundant load elimination. In
|
|
|
|
fact, they are the same transformation applied to different views of
|
|
|
|
the CFG. */
|
|
|
|
|
|
|
|
|
|
|
|
struct dse_global_data
|
|
|
|
{
|
|
|
|
/* This is the global bitmap for store statements.
|
|
|
|
|
|
|
|
Each statement has a unique ID. When we encounter a store statement
|
|
|
|
that we want to record, set the bit corresponding to the statement's
|
|
|
|
unique ID in this bitmap. */
|
|
|
|
bitmap stores;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* We allocate a bitmap-per-block for stores which are encountered
|
|
|
|
during the scan of that block. This allows us to restore the
|
|
|
|
global bitmap of stores when we finish processing a block. */
|
|
|
|
struct dse_block_local_data
|
|
|
|
{
|
|
|
|
bitmap stores;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool gate_dse (void);
|
|
|
|
static void tree_ssa_dse (void);
|
|
|
|
static void dse_initialize_block_local_data (struct dom_walk_data *,
|
|
|
|
basic_block,
|
|
|
|
bool);
|
|
|
|
static void dse_optimize_stmt (struct dom_walk_data *,
|
|
|
|
basic_block,
|
|
|
|
block_stmt_iterator);
|
|
|
|
static void dse_record_phis (struct dom_walk_data *, basic_block);
|
|
|
|
static void dse_finalize_block (struct dom_walk_data *, basic_block);
|
|
|
|
static void fix_phi_uses (tree, tree);
|
2004-06-10 23:41:08 +02:00
|
|
|
static void fix_stmt_v_may_defs (tree, tree);
|
2004-05-13 08:41:07 +02:00
|
|
|
static void record_voperand_set (bitmap, bitmap *, unsigned int);
|
|
|
|
|
|
|
|
/* Function indicating whether we ought to include information for 'var'
|
|
|
|
when calculating immediate uses. For this pass we only want use
|
|
|
|
information for virtual variables. */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
need_imm_uses_for (tree var)
|
|
|
|
{
|
|
|
|
return !is_gimple_reg (var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Replace uses in PHI which match V_MAY_DEF_RESULTs in STMT with the
|
|
|
|
corresponding V_MAY_DEF_OP in STMT. */
|
2004-05-13 08:41:07 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
fix_phi_uses (tree phi, tree stmt)
|
|
|
|
{
|
|
|
|
stmt_ann_t ann = stmt_ann (stmt);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_def_optype v_may_defs;
|
2004-05-13 08:41:07 +02:00
|
|
|
unsigned int i;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
get_stmt_operands (stmt);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_defs = V_MAY_DEF_OPS (ann);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Walk each V_MAY_DEF in STMT. */
|
|
|
|
for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
2004-06-10 23:41:08 +02:00
|
|
|
tree v_may_def = V_MAY_DEF_RESULT (v_may_defs, i);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Find any uses in the PHI which match V_MAY_DEF and replace
|
|
|
|
them with the appropriate V_MAY_DEF_OP. */
|
2004-05-13 08:41:07 +02:00
|
|
|
for (j = 0; j < PHI_NUM_ARGS (phi); j++)
|
2004-06-10 23:41:08 +02:00
|
|
|
if (v_may_def == PHI_ARG_DEF (phi, j))
|
tree-cfg.c (tree_make_forwarder_block): Use SET_PHI_RESULT.
2004-06-16 Andrew MacLeod <amacleod@redhat.com>
* tree-cfg.c (tree_make_forwarder_block): Use SET_PHI_RESULT.
* tree-flow-inline.h (get_use_op_ptr): Return a use_operand_p.
(get_use_from_ptr, get_def_from_ptr): New. Return operand pointers.
(get_def_op_ptr): Return a def_operand_p instead of a 'tree *'.
(get_v_may_def_result_ptr): Return a def_operand_p.
(get_v_may_def_op_ptr, get_vuse_op_ptr): Return a use_operand_p.
(get_v_must_def_op_ptr): Return a def_operand_p.
(get_phi_result_ptr): New. Return a pointer to the result of a PHI.
(get_phi_arg_def_ptr): New. Return a pointer to an argument of a PHI.
(phi_element_for_edge): Remove.
* tree-flow.h (propagate_value, replace_exp): Change prototype.
(propagate_tree_value): Add new prototype.
(phi_element_for_edge): Remove prototype.
* tree-into-ssa.c (mark_def_sites): Use new operand types.
(prepare_operand_for_rename): Split into two functions.
(prepare_use_operand_for_rename): Prepare use operands.
(prepare_def_operand_for_rename): Prepare def operands.
(rewrite_stmt): Use new operand types.
(rewrite_operand): Use new operand types, change parameter type.
* tree-outof-ssa.c (replace_variable): Split into two functions.
(replace_use_variable): Rewrite uses.
(replace_def_variable): Rewrite defs.
(rewrite_trees, rewrite_vars_out_of_ssa): Use new operand types.
* tree-phinodes.c (make_phi_node, resize_phi_node): Use new types.
(add_phi_arg, remove_phi_arg_num): Use new operand types.
* tree-ssa-ccp.c (substitute_and_fold): Use new operand types.
(ccp_fold, replace_uses_in): Use new operand types.
* tree-ssa-copy.c (replace_ssa_names): Rename to replace_ssa_names_ann
and no longer set the value, change parameter type.
(replace_exp_1): Use new operand types.
(propagate_value): Change parameter type, use new operand types.
(propagate_tree_value): Propagate_value without SSA operands.
(replace_exp, cprop_operand, cprop_into_stmt): Use new operand types.
(cprop_into_successor_phis): Use new operand types.
* tree-ssa-dom.c (thread_across_edge): Use new operand types.
(eliminate_redundant_computations): Use new operand types.
* tree-ssa-dse.c (fix_phi_uses): Use new operand_types.
(fix_stmt_v_may_defs): Use new operand_types.
* tree-ssa-live.c (create_ssa_var_map): Use new operand_types.
(build_tree_conflict_graph): Use new operand_types.
* tree-ssa-loop.c (duplicate_blocks): Use PHI_ARG_DEF_FROM_EDGE.
* tree-ssa-operands.c (struct freelist_d): Remove.
(check_optype_freelist, add_optype_freelist): Remove.
(allocate_def_optype, allocate_use_optype, allocate_v_may_def_optype,
allocate_vuse_optype, allocate_v_must_def_optype): Call ggc_alloc.
(free_uses, free_defs, free_vuses, free_v_may_defs, free_v_must_defs):
Call ggc_free instead of add_optype_freelist.
(init_ssa_operands, fini_ssa_operands): Remove free list code.
(finalize_ssa_defs, finalize_ssa_uses): Set new use/def operands.
* tree-ssa-operands.h (struct def_optype_d): Change underlying type.
(struct use_optype_d): Change underlying type.
(def_operand_p, use_operand_p): New types for pointers to operands.
(USE_OP, DEF_OP, V_MAY_DEF_RESULT, V_MAY_DEF_OP, VUSE_OP,
V_MUST_DEF_OP): Use new pointer type instead of dereferencing directly.
(USE_FROM_PTR, DEF_FROM_PTR): New macros to "dereference" operand
pointer types.
(SET_USE, SET_DEF): New macros to set operands from their pointer.
(SET_USE_OP, SET_DEF_OP, SET_V_MAY_DEF_RESULT, SET_V_MAY_DEF_OP,
SET_VUSE_OP, SET_V_MUST_DEF_OP): New SET routines for operands.
(PHI_RESULT_PTR, PHI_RESULT, SET_PHI_RESULT): Macros to manage the
PHI result as an operand.
(PHI_ARG_DEF_PTR, PHI_ARG_DEF, SET_PHI_ARG_DEF, PHI_ARG_DEF_FROM_EDGE,
PHI_ARG_DEF_PTR_FROM_EDGE): Macros to manage the PHI arguments.
* tree-ssa-pre.c (eliminate): Call propagate_tree_value.
* tree-tailcall.c (independent_of_stmt_p, propagate_through_phis): Use
PHI_ARG_DEF_FROM_EDGE.
* tree.h (PHI_RESULT): Renamed to PHI_RESULT_TREE.
(PHI_ARG_DEF): Renamed to PHI_ARG_DEF_TREE.
From-SVN: r83298
2004-06-17 20:13:20 +02:00
|
|
|
SET_PHI_ARG_DEF (phi, j, V_MAY_DEF_OP (v_may_defs, i));
|
2004-05-13 08:41:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Replace the V_MAY_DEF_OPs in STMT1 which match V_MAY_DEF_RESULTs
|
|
|
|
in STMT2 with the appropriate V_MAY_DEF_OPs from STMT2. */
|
2004-05-13 08:41:07 +02:00
|
|
|
|
|
|
|
static void
|
2004-06-10 23:41:08 +02:00
|
|
|
fix_stmt_v_may_defs (tree stmt1, tree stmt2)
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
|
|
|
stmt_ann_t ann1 = stmt_ann (stmt1);
|
|
|
|
stmt_ann_t ann2 = stmt_ann (stmt2);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_def_optype v_may_defs1;
|
|
|
|
v_may_def_optype v_may_defs2;
|
2004-05-13 08:41:07 +02:00
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
get_stmt_operands (stmt1);
|
|
|
|
get_stmt_operands (stmt2);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_defs1 = V_MAY_DEF_OPS (ann1);
|
|
|
|
v_may_defs2 = V_MAY_DEF_OPS (ann2);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Walk each V_MAY_DEF_OP in stmt1. */
|
|
|
|
for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs1); i++)
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
2004-06-10 23:41:08 +02:00
|
|
|
tree v_may_def1 = V_MAY_DEF_OP (v_may_defs1, i);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
2004-06-10 23:41:08 +02:00
|
|
|
/* Find the appropriate V_MAY_DEF_RESULT in STMT2. */
|
|
|
|
for (j = 0; j < NUM_V_MAY_DEFS (v_may_defs2); j++)
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
2004-06-10 23:41:08 +02:00
|
|
|
if (v_may_def1 == V_MAY_DEF_RESULT (v_may_defs2, j))
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
|
|
|
/* Update. */
|
tree-cfg.c (tree_make_forwarder_block): Use SET_PHI_RESULT.
2004-06-16 Andrew MacLeod <amacleod@redhat.com>
* tree-cfg.c (tree_make_forwarder_block): Use SET_PHI_RESULT.
* tree-flow-inline.h (get_use_op_ptr): Return a use_operand_p.
(get_use_from_ptr, get_def_from_ptr): New. Return operand pointers.
(get_def_op_ptr): Return a def_operand_p instead of a 'tree *'.
(get_v_may_def_result_ptr): Return a def_operand_p.
(get_v_may_def_op_ptr, get_vuse_op_ptr): Return a use_operand_p.
(get_v_must_def_op_ptr): Return a def_operand_p.
(get_phi_result_ptr): New. Return a pointer to the result of a PHI.
(get_phi_arg_def_ptr): New. Return a pointer to an argument of a PHI.
(phi_element_for_edge): Remove.
* tree-flow.h (propagate_value, replace_exp): Change prototype.
(propagate_tree_value): Add new prototype.
(phi_element_for_edge): Remove prototype.
* tree-into-ssa.c (mark_def_sites): Use new operand types.
(prepare_operand_for_rename): Split into two functions.
(prepare_use_operand_for_rename): Prepare use operands.
(prepare_def_operand_for_rename): Prepare def operands.
(rewrite_stmt): Use new operand types.
(rewrite_operand): Use new operand types, change parameter type.
* tree-outof-ssa.c (replace_variable): Split into two functions.
(replace_use_variable): Rewrite uses.
(replace_def_variable): Rewrite defs.
(rewrite_trees, rewrite_vars_out_of_ssa): Use new operand types.
* tree-phinodes.c (make_phi_node, resize_phi_node): Use new types.
(add_phi_arg, remove_phi_arg_num): Use new operand types.
* tree-ssa-ccp.c (substitute_and_fold): Use new operand types.
(ccp_fold, replace_uses_in): Use new operand types.
* tree-ssa-copy.c (replace_ssa_names): Rename to replace_ssa_names_ann
and no longer set the value, change parameter type.
(replace_exp_1): Use new operand types.
(propagate_value): Change parameter type, use new operand types.
(propagate_tree_value): Propagate_value without SSA operands.
(replace_exp, cprop_operand, cprop_into_stmt): Use new operand types.
(cprop_into_successor_phis): Use new operand types.
* tree-ssa-dom.c (thread_across_edge): Use new operand types.
(eliminate_redundant_computations): Use new operand types.
* tree-ssa-dse.c (fix_phi_uses): Use new operand_types.
(fix_stmt_v_may_defs): Use new operand_types.
* tree-ssa-live.c (create_ssa_var_map): Use new operand_types.
(build_tree_conflict_graph): Use new operand_types.
* tree-ssa-loop.c (duplicate_blocks): Use PHI_ARG_DEF_FROM_EDGE.
* tree-ssa-operands.c (struct freelist_d): Remove.
(check_optype_freelist, add_optype_freelist): Remove.
(allocate_def_optype, allocate_use_optype, allocate_v_may_def_optype,
allocate_vuse_optype, allocate_v_must_def_optype): Call ggc_alloc.
(free_uses, free_defs, free_vuses, free_v_may_defs, free_v_must_defs):
Call ggc_free instead of add_optype_freelist.
(init_ssa_operands, fini_ssa_operands): Remove free list code.
(finalize_ssa_defs, finalize_ssa_uses): Set new use/def operands.
* tree-ssa-operands.h (struct def_optype_d): Change underlying type.
(struct use_optype_d): Change underlying type.
(def_operand_p, use_operand_p): New types for pointers to operands.
(USE_OP, DEF_OP, V_MAY_DEF_RESULT, V_MAY_DEF_OP, VUSE_OP,
V_MUST_DEF_OP): Use new pointer type instead of dereferencing directly.
(USE_FROM_PTR, DEF_FROM_PTR): New macros to "dereference" operand
pointer types.
(SET_USE, SET_DEF): New macros to set operands from their pointer.
(SET_USE_OP, SET_DEF_OP, SET_V_MAY_DEF_RESULT, SET_V_MAY_DEF_OP,
SET_VUSE_OP, SET_V_MUST_DEF_OP): New SET routines for operands.
(PHI_RESULT_PTR, PHI_RESULT, SET_PHI_RESULT): Macros to manage the
PHI result as an operand.
(PHI_ARG_DEF_PTR, PHI_ARG_DEF, SET_PHI_ARG_DEF, PHI_ARG_DEF_FROM_EDGE,
PHI_ARG_DEF_PTR_FROM_EDGE): Macros to manage the PHI arguments.
* tree-ssa-pre.c (eliminate): Call propagate_tree_value.
* tree-tailcall.c (independent_of_stmt_p, propagate_through_phis): Use
PHI_ARG_DEF_FROM_EDGE.
* tree.h (PHI_RESULT): Renamed to PHI_RESULT_TREE.
(PHI_ARG_DEF): Renamed to PHI_ARG_DEF_TREE.
From-SVN: r83298
2004-06-17 20:13:20 +02:00
|
|
|
SET_V_MAY_DEF_OP (v_may_defs1, i, V_MAY_DEF_OP (v_may_defs2, j));
|
2004-05-13 08:41:07 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_CHECKING
|
2004-06-10 23:41:08 +02:00
|
|
|
/* If we did not find a corresponding V_MAY_DEF_RESULT, then something
|
2004-05-13 08:41:07 +02:00
|
|
|
has gone terribly wrong. */
|
2004-06-10 23:41:08 +02:00
|
|
|
if (j == NUM_V_MAY_DEFS (v_may_defs2))
|
2004-05-13 08:41:07 +02:00
|
|
|
abort ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Set bit UID in bitmaps GLOBAL and *LOCAL, creating *LOCAL as needed. */
|
|
|
|
static void
|
|
|
|
record_voperand_set (bitmap global, bitmap *local, unsigned int uid)
|
|
|
|
{
|
|
|
|
/* Lazily allocate the bitmap. Note that we do not get a notification
|
|
|
|
when the block local data structures die, so we allocate the local
|
|
|
|
bitmap backed by the GC system. */
|
|
|
|
if (*local == NULL)
|
|
|
|
*local = BITMAP_GGC_ALLOC ();
|
|
|
|
|
|
|
|
/* Set the bit in the local and global bitmaps. */
|
|
|
|
bitmap_set_bit (*local, uid);
|
|
|
|
bitmap_set_bit (global, uid);
|
|
|
|
}
|
|
|
|
/* Initialize block local data structures. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
dse_initialize_block_local_data (struct dom_walk_data *walk_data,
|
|
|
|
basic_block bb ATTRIBUTE_UNUSED,
|
|
|
|
bool recycled)
|
|
|
|
{
|
|
|
|
struct dse_block_local_data *bd
|
|
|
|
= VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
|
|
|
|
|
|
|
|
/* If we are given a recycled block local data structure, ensure any
|
|
|
|
bitmap associated with the block is cleared. */
|
|
|
|
if (recycled)
|
|
|
|
{
|
|
|
|
if (bd->stores)
|
|
|
|
bitmap_clear (bd->stores);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attempt to eliminate dead stores in the statement referenced by BSI.
|
|
|
|
|
|
|
|
A dead store is a store into a memory location which will later be
|
|
|
|
overwritten by another store without any intervening loads. In this
|
|
|
|
case the earlier store can be deleted.
|
|
|
|
|
|
|
|
In our SSA + virtual operand world we use immediate uses of virtual
|
|
|
|
operands to detect dead stores. If a store's virtual definition
|
|
|
|
is used precisely once by a later store to the same location which
|
|
|
|
post dominates the first store, then the first store is dead. */
|
|
|
|
|
|
|
|
static void
|
|
|
|
dse_optimize_stmt (struct dom_walk_data *walk_data,
|
|
|
|
basic_block bb ATTRIBUTE_UNUSED,
|
|
|
|
block_stmt_iterator bsi)
|
|
|
|
{
|
|
|
|
struct dse_block_local_data *bd
|
|
|
|
= VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
|
|
|
|
struct dse_global_data *dse_gd = walk_data->global_data;
|
|
|
|
tree stmt = bsi_stmt (bsi);
|
|
|
|
stmt_ann_t ann = stmt_ann (stmt);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_def_optype v_may_defs;
|
2004-05-13 08:41:07 +02:00
|
|
|
|
|
|
|
get_stmt_operands (stmt);
|
2004-06-10 23:41:08 +02:00
|
|
|
v_may_defs = V_MAY_DEF_OPS (ann);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
|
|
|
/* If this statement has no virtual uses, then there is nothing
|
|
|
|
to do. */
|
2004-06-10 23:41:08 +02:00
|
|
|
if (NUM_V_MAY_DEFS (v_may_defs) == 0)
|
2004-05-13 08:41:07 +02:00
|
|
|
return;
|
|
|
|
|
2004-07-08 18:16:41 +02:00
|
|
|
/* We know we have virtual definitions. If this is a MODIFY_EXPR that's
|
|
|
|
not also a function call, then record it into our table. */
|
|
|
|
if (get_call_expr_in (stmt))
|
|
|
|
return;
|
|
|
|
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
2004-05-13 08:41:07 +02:00
|
|
|
{
|
|
|
|
dataflow_t df = get_immediate_uses (stmt);
|
|
|
|
unsigned int num_uses = num_immediate_uses (df);
|
|
|
|
tree use;
|
|
|
|
tree skipped_phi;
|
|
|
|
|
|
|
|
|
|
|
|
/* If there are no uses then there is nothing left to do. */
|
|
|
|
if (num_uses == 0)
|
|
|
|
{
|
|
|
|
record_voperand_set (dse_gd->stores, &bd->stores, ann->uid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
use = immediate_use (df, 0);
|
|
|
|
skipped_phi = NULL;
|
|
|
|
|
|
|
|
/* Skip through any PHI nodes we have already seen if the PHI
|
|
|
|
represents the only use of this store.
|
|
|
|
|
|
|
|
Note this does not handle the case where the store has
|
2004-06-10 23:41:08 +02:00
|
|
|
multiple V_MAY_DEFs which all reach a set of PHI nodes in the
|
2004-05-13 08:41:07 +02:00
|
|
|
same block. */
|
|
|
|
while (num_uses == 1
|
|
|
|
&& TREE_CODE (use) == PHI_NODE
|
|
|
|
&& bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid))
|
|
|
|
{
|
|
|
|
/* Record the first PHI we skip so that we can fix its
|
|
|
|
uses if we find that STMT is a dead store. */
|
|
|
|
if (!skipped_phi)
|
|
|
|
skipped_phi = use;
|
|
|
|
|
|
|
|
/* Skip past this PHI and loop again in case we had a PHI
|
|
|
|
chain. */
|
|
|
|
df = get_immediate_uses (use);
|
|
|
|
num_uses = num_immediate_uses (df);
|
|
|
|
use = immediate_use (df, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have precisely one immediate use at this point, then we may
|
|
|
|
have found redundant store. */
|
|
|
|
if (num_uses == 1
|
|
|
|
&& bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid)
|
|
|
|
&& operand_equal_p (TREE_OPERAND (stmt, 0),
|
|
|
|
TREE_OPERAND (use, 0), 0))
|
|
|
|
{
|
|
|
|
/* We need to fix the operands if either the first PHI we
|
|
|
|
skipped, or the store which we are not deleting if we did
|
|
|
|
not skip any PHIs. */
|
|
|
|
if (skipped_phi)
|
|
|
|
fix_phi_uses (skipped_phi, stmt);
|
|
|
|
else
|
2004-06-10 23:41:08 +02:00
|
|
|
fix_stmt_v_may_defs (use, stmt);
|
2004-05-13 08:41:07 +02:00
|
|
|
|
|
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|
|
|
{
|
|
|
|
fprintf (dump_file, " Deleted dead store '");
|
|
|
|
print_generic_expr (dump_file, bsi_stmt (bsi), dump_flags);
|
|
|
|
fprintf (dump_file, "'\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Any immediate uses which reference STMT need to instead
|
|
|
|
reference the new consumer, either SKIPPED_PHI or USE.
|
|
|
|
This allows us to cascade dead stores. */
|
|
|
|
redirect_immediate_uses (stmt, skipped_phi ? skipped_phi : use);
|
|
|
|
|
|
|
|
/* Finally remove the dead store. */
|
|
|
|
bsi_remove (&bsi);
|
|
|
|
}
|
|
|
|
|
|
|
|
record_voperand_set (dse_gd->stores, &bd->stores, ann->uid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Record that we have seen the PHIs at the start of BB which correspond
|
|
|
|
to virtual operands. */
|
|
|
|
static void
|
|
|
|
dse_record_phis (struct dom_walk_data *walk_data, basic_block bb)
|
|
|
|
{
|
|
|
|
struct dse_block_local_data *bd
|
|
|
|
= VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
|
|
|
|
struct dse_global_data *dse_gd = walk_data->global_data;
|
|
|
|
tree phi;
|
|
|
|
|
tree.h (PHI_CHAIN): New.
* tree.h (PHI_CHAIN): New.
* (tree-cfg.c, tree-dfa.c, tree-flow-inline.h, tree-into-ssa.c,
tree-outof-ssa.c, tree-phinodes.c, tree-pretty-print.c,
tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-dom.c, tree-ssa-dse.c,
tree-ssa-live.c, tree-ssa-loop.c, tree-ssa-phiopt.c, tree-ssa-pre.c,
tree-ssa.c, tree-tailcall.c): Use PHI_CHAIN instead of TREE_CHAIN
when traversing a list of PHI_NODEs.
From-SVN: r83273
2004-06-17 01:03:34 +02:00
|
|
|
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
2004-05-13 08:41:07 +02:00
|
|
|
if (need_imm_uses_for (PHI_RESULT (phi)))
|
|
|
|
record_voperand_set (dse_gd->stores,
|
|
|
|
&bd->stores,
|
|
|
|
get_stmt_ann (phi)->uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dse_finalize_block (struct dom_walk_data *walk_data,
|
|
|
|
basic_block bb ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
struct dse_block_local_data *bd
|
|
|
|
= VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
|
|
|
|
struct dse_global_data *dse_gd = walk_data->global_data;
|
|
|
|
bitmap stores = dse_gd->stores;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/* Unwind the stores noted in this basic block. */
|
|
|
|
if (bd->stores)
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP (bd->stores, 0, i, bitmap_clear_bit (stores, i););
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tree_ssa_dse (void)
|
|
|
|
{
|
|
|
|
struct dom_walk_data walk_data;
|
|
|
|
struct dse_global_data dse_gd;
|
|
|
|
unsigned int uid = 0;
|
|
|
|
basic_block bb;
|
|
|
|
|
|
|
|
/* Create a UID for each statement in the function. Ordering of the
|
|
|
|
UIDs is not important for this pass. */
|
|
|
|
FOR_EACH_BB (bb)
|
|
|
|
{
|
|
|
|
block_stmt_iterator bsi;
|
|
|
|
tree phi;
|
|
|
|
|
|
|
|
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
|
|
|
stmt_ann (bsi_stmt (bsi))->uid = uid++;
|
|
|
|
|
tree.h (PHI_CHAIN): New.
* tree.h (PHI_CHAIN): New.
* (tree-cfg.c, tree-dfa.c, tree-flow-inline.h, tree-into-ssa.c,
tree-outof-ssa.c, tree-phinodes.c, tree-pretty-print.c,
tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-dom.c, tree-ssa-dse.c,
tree-ssa-live.c, tree-ssa-loop.c, tree-ssa-phiopt.c, tree-ssa-pre.c,
tree-ssa.c, tree-tailcall.c): Use PHI_CHAIN instead of TREE_CHAIN
when traversing a list of PHI_NODEs.
From-SVN: r83273
2004-06-17 01:03:34 +02:00
|
|
|
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
|
2004-05-13 08:41:07 +02:00
|
|
|
stmt_ann (phi)->uid = uid++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We might consider making this a property of each pass so that it
|
|
|
|
can be [re]computed on an as-needed basis. Particularly since
|
|
|
|
this pass could be seen as an extension of DCE which needs post
|
|
|
|
dominators. */
|
|
|
|
calculate_dominance_info (CDI_POST_DOMINATORS);
|
|
|
|
|
|
|
|
/* We also need immediate use information for virtual operands. */
|
|
|
|
compute_immediate_uses (TDFA_USE_VOPS, need_imm_uses_for);
|
|
|
|
|
|
|
|
/* Dead store elimination is fundamentally a walk of the post-dominator
|
|
|
|
tree and a backwards walk of statements within each block. */
|
|
|
|
walk_data.walk_stmts_backward = true;
|
|
|
|
walk_data.dom_direction = CDI_POST_DOMINATORS;
|
|
|
|
walk_data.initialize_block_local_data = dse_initialize_block_local_data;
|
|
|
|
walk_data.before_dom_children_before_stmts = NULL;
|
|
|
|
walk_data.before_dom_children_walk_stmts = dse_optimize_stmt;
|
|
|
|
walk_data.before_dom_children_after_stmts = dse_record_phis;
|
|
|
|
walk_data.after_dom_children_before_stmts = NULL;
|
|
|
|
walk_data.after_dom_children_walk_stmts = NULL;
|
|
|
|
walk_data.after_dom_children_after_stmts = dse_finalize_block;
|
|
|
|
|
|
|
|
walk_data.block_local_data_size = sizeof (struct dse_block_local_data);
|
|
|
|
|
|
|
|
/* This is the main hash table for the dead store elimination pass. */
|
|
|
|
dse_gd.stores = BITMAP_XMALLOC ();
|
|
|
|
walk_data.global_data = &dse_gd;
|
|
|
|
|
|
|
|
/* Initialize the dominator walker. */
|
|
|
|
init_walk_dominator_tree (&walk_data);
|
|
|
|
|
|
|
|
/* Recursively walk the dominator tree. */
|
|
|
|
walk_dominator_tree (&walk_data, EXIT_BLOCK_PTR);
|
|
|
|
|
|
|
|
/* Finalize the dominator walker. */
|
|
|
|
fini_walk_dominator_tree (&walk_data);
|
|
|
|
|
|
|
|
/* Release the main bitmap. */
|
|
|
|
BITMAP_XFREE (dse_gd.stores);
|
|
|
|
|
|
|
|
/* Free dataflow information. It's probably out of date now anyway. */
|
|
|
|
free_df ();
|
|
|
|
|
|
|
|
/* For now, just wipe the post-dominator information. */
|
|
|
|
free_dominance_info (CDI_POST_DOMINATORS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
gate_dse (void)
|
|
|
|
{
|
|
|
|
return flag_tree_dse != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tree_opt_pass pass_dse = {
|
|
|
|
"dse", /* name */
|
|
|
|
gate_dse, /* gate */
|
|
|
|
tree_ssa_dse, /* execute */
|
|
|
|
NULL, /* sub */
|
|
|
|
NULL, /* next */
|
|
|
|
0, /* static_pass_number */
|
|
|
|
TV_TREE_DSE, /* tv_id */
|
2004-07-28 07:13:10 +02:00
|
|
|
PROP_cfg | PROP_ssa
|
|
|
|
| PROP_alias, /* properties_required */
|
2004-05-13 08:41:07 +02:00
|
|
|
0, /* properties_provided */
|
|
|
|
0, /* properties_destroyed */
|
|
|
|
0, /* todo_flags_start */
|
|
|
|
TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
|
|
|
|
| TODO_verify_ssa
|
|
|
|
};
|