/* Convert a program in SSA form into Normal form.
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
Contributed by Andrew Macleod <amacleod@redhat.com>
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
-#include "ggc.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
#include "basic-block.h"
#include "gimple-pretty-print.h"
#include "bitmap.h"
-#include "tree-flow.h"
+#include "sbitmap.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
#include "dumpfile.h"
#include "diagnostic-core.h"
-#include "ssaexpand.h"
+#include "tree-ssa-live.h"
+#include "tree-ssa-ter.h"
+#include "tree-ssa-coalesce.h"
+#include "tree-outof-ssa.h"
/* FIXME: A lot of code here deals with expanding to RTL. All that code
should be in cfgexpand.c. */
+#include "hashtab.h"
+#include "rtl.h"
+#include "flags.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
+/* Return TRUE if expression STMT is suitable for replacement. */
+
+bool
+ssa_is_replaceable_p (gimple stmt)
+{
+ use_operand_p use_p;
+ tree def;
+ gimple use_stmt;
+
+ /* Only consider modify stmts. */
+ if (!is_gimple_assign (stmt))
+ return false;
+
+ /* If the statement may throw an exception, it cannot be replaced. */
+ if (stmt_could_throw_p (stmt))
+ return false;
+
+ /* Punt if there is more than 1 def. */
+ def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF);
+ if (!def)
+ return false;
+
+ /* Only consider definitions which have a single use. */
+ if (!single_imm_use (def, &use_p, &use_stmt))
+ return false;
+
+ /* Used in this block, but at the TOP of the block, not the end. */
+ if (gimple_code (use_stmt) == GIMPLE_PHI)
+ return false;
+
+ /* There must be no VDEFs. */
+ if (gimple_vdef (stmt))
+ return false;
+
+ /* Float expressions must go through memory if float-store is on. */
+ if (flag_float_store
+ && FLOAT_TYPE_P (gimple_expr_type (stmt)))
+ return false;
+
+ /* An assignment with a register variable on the RHS is not
+ replaceable. */
+ if (gimple_assign_rhs_code (stmt) == VAR_DECL
+ && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt)))
+ return false;
+
+ /* No function calls can be replaced. */
+ if (is_gimple_call (stmt))
+ return false;
+
+ /* Leave any stmt with volatile operands alone as well. */
+ if (gimple_has_volatile_ops (stmt))
+ return false;
+
+ return true;
+}
/* Used to hold all the components required to do SSA PHI elimination.
SRC/DEST might be BLKmode memory locations SIZEEXP is a tree from
which we deduce the size to copy in that case. */
-static inline rtx
+static inline rtx_insn *
emit_partition_copy (rtx dest, rtx src, int unsignedsrcp, tree sizeexp)
{
- rtx seq;
-
start_sequence ();
if (GET_MODE (src) != VOIDmode && GET_MODE (src) != GET_MODE (dest))
else
emit_move_insn (dest, src);
- seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
return seq;
insert_partition_copy_on_edge (edge e, int dest, int src, source_location locus)
{
tree var;
- rtx seq;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
set_curr_insn_location (locus);
var = partition_to_var (SA.map, src);
- seq = emit_partition_copy (SA.partition_to_pseudo[dest],
- SA.partition_to_pseudo[src],
- TYPE_UNSIGNED (TREE_TYPE (var)),
- var);
+ rtx_insn *seq = emit_partition_copy (copy_rtx (SA.partition_to_pseudo[dest]),
+ copy_rtx (SA.partition_to_pseudo[src]),
+ TYPE_UNSIGNED (TREE_TYPE (var)),
+ var);
insert_insn_on_edge (seq, e);
}
static void
insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus)
{
- rtx seq, x;
- enum machine_mode dest_mode, src_mode;
+ rtx dest_rtx, seq, x;
+ machine_mode dest_mode, src_mode;
int unsignedp;
tree var;
fprintf (dump_file, "\n");
}
- gcc_assert (SA.partition_to_pseudo[dest]);
+ dest_rtx = copy_rtx (SA.partition_to_pseudo[dest]);
+ gcc_assert (dest_rtx);
set_location_for_edge (e);
/* If a locus is provided, override the default. */
var = SSA_NAME_VAR (partition_to_var (SA.map, dest));
src_mode = TYPE_MODE (TREE_TYPE (src));
- dest_mode = GET_MODE (SA.partition_to_pseudo[dest]);
+ dest_mode = GET_MODE (dest_rtx);
gcc_assert (src_mode == TYPE_MODE (TREE_TYPE (var)));
- gcc_assert (!REG_P (SA.partition_to_pseudo[dest])
+ gcc_assert (!REG_P (dest_rtx)
|| dest_mode == promote_decl_mode (var, &unsignedp));
if (src_mode != dest_mode)
}
else if (src_mode == BLKmode)
{
- x = SA.partition_to_pseudo[dest];
+ x = dest_rtx;
store_expr (src, x, 0, false);
}
else
- x = expand_expr (src, SA.partition_to_pseudo[dest],
- dest_mode, EXPAND_NORMAL);
+ x = expand_expr (src, dest_rtx, dest_mode, EXPAND_NORMAL);
- if (x != SA.partition_to_pseudo[dest])
- emit_move_insn (SA.partition_to_pseudo[dest], x);
+ if (x != dest_rtx)
+ emit_move_insn (dest_rtx, x);
seq = get_insns ();
end_sequence ();
insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp,
source_location locus)
{
- rtx seq;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
mems. Usually we give the source. As we result from SSA names
the left and right size should be the same (and no WITH_SIZE_EXPR
involved), so it doesn't matter. */
- seq = emit_partition_copy (SA.partition_to_pseudo[dest],
- src, unsignedsrcp,
- partition_to_var (SA.map, dest));
+ rtx_insn *seq = emit_partition_copy (copy_rtx (SA.partition_to_pseudo[dest]),
+ src, unsignedsrcp,
+ partition_to_var (SA.map, dest));
insert_insn_on_edge (seq, e);
}
insert_part_to_rtx_on_edge (edge e, rtx dest, int src, source_location locus)
{
tree var;
- rtx seq;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
set_curr_insn_location (locus);
var = partition_to_var (SA.map, src);
- seq = emit_partition_copy (dest,
- SA.partition_to_pseudo[src],
- TYPE_UNSIGNED (TREE_TYPE (var)),
- var);
+ rtx_insn *seq = emit_partition_copy (dest,
+ copy_rtx (SA.partition_to_pseudo[src]),
+ TYPE_UNSIGNED (TREE_TYPE (var)),
+ var);
insert_insn_on_edge (seq, e);
}
elim_graph_add_node (g, T);
}
+/* Return true if this phi argument T should have a copy queued when using
+ var_map MAP. PHI nodes should contain only ssa_names and invariants. A
+ test for ssa_name is definitely simpler, but don't let invalid contents
+ slip through in the meantime. */
+
+static inline bool
+queue_phi_copy_p (var_map map, tree t)
+{
+ if (TREE_CODE (t) == SSA_NAME)
+ {
+ if (var_to_partition (map, t) == NO_PARTITION)
+ return true;
+ return false;
+ }
+ gcc_checking_assert (is_gimple_min_invariant (t));
+ return true;
+}
/* Build elimination graph G for basic block BB on incoming PHI edge
G->e. */
{
tree Ti;
int p0, pi;
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
clear_elim_graph (g);
for (gsi = gsi_start_phis (g->e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
source_location locus;
p0 = var_to_partition (g->map, gimple_phi_result (phi));
/* If this argument is a constant, or a SSA_NAME which is being
left in SSA form, just queue a copy to be emitted on this
edge. */
- if (!phi_ssa_name_p (Ti)
- || (TREE_CODE (Ti) == SSA_NAME
- && var_to_partition (g->map, Ti) == NO_PARTITION))
+ if (queue_phi_copy_p (g->map, Ti))
{
/* Save constant copies until all other copies have been emitted
on this edge. */
tree var = TREE_CODE (name) == SSA_NAME ? SSA_NAME_VAR (name) : name;
tree type = TREE_TYPE (var);
int unsignedp;
- enum machine_mode reg_mode = promote_decl_mode (var, &unsignedp);
+ machine_mode reg_mode = promote_decl_mode (var, &unsignedp);
rtx x = gen_reg_rtx (reg_mode);
if (POINTER_TYPE_P (type))
mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (var))));
check to see if this allows another PHI node to be removed. */
static void
-remove_gimple_phi_args (gimple phi)
+remove_gimple_phi_args (gphi *phi)
{
use_operand_p arg_p;
ssa_op_iter iter;
/* Also remove the def if it is a PHI node. */
if (gimple_code (stmt) == GIMPLE_PHI)
{
- remove_gimple_phi_args (stmt);
+ remove_gimple_phi_args (as_a <gphi *> (stmt));
gsi = gsi_for_stmt (stmt);
remove_phi_node (&gsi, true);
}
eliminate_useless_phis (void)
{
basic_block bb;
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
tree result;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
result = gimple_phi_result (phi);
if (virtual_operand_p (result))
{
/* Search for PHIs where the destination has no partition, but one
or more arguments has a partition. This should not happen and can
create incorrect code. */
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
tree T0 = var_to_partition_to_var (map, gimple_phi_result (phi));
if (T0 == NULL_TREE)
{
elim_graph g = new_elim_graph (sa->map->num_partitions);
g->map = sa->map;
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR, next_bb)
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb,
+ EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
if (!gimple_seq_empty_p (phi_nodes (bb)))
{
edge e;
if (e->insns.r && (e->flags & EDGE_EH)
&& !single_pred_p (e->dest))
{
- rtx insns = e->insns.r;
+ rtx_insn *insns = e->insns.r;
basic_block bb;
- e->insns.r = NULL_RTX;
+ e->insns.r = NULL;
bb = split_edge (e);
single_pred_edge (bb)->insns.r = insns;
}
insert_backedge_copies (void)
{
basic_block bb;
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
mark_dfs_back_edges ();
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
/* Mark block as possibly needing calculation of UIDs. */
bb->aux = &bb->aux;
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
tree result = gimple_phi_result (phi);
size_t i;
|| trivially_conflicts_p (bb, result, arg)))
{
tree name;
- gimple stmt, last = NULL;
+ gassign *stmt;
+ gimple last = NULL;
gimple_stmt_iterator gsi2;
gsi2 = gsi_last_bb (gimple_phi_arg_edge (phi, i)->src);
/* Create a new instance of the underlying variable of the
PHI result. */
- name = copy_ssa_name (result, NULL);
+ name = copy_ssa_name (result);
stmt = gimple_build_assign (name,
gimple_phi_arg_def (phi, i));