}
}
+/* Emit insns to copy SRC into DEST converting SRC if necessary. */
+
+static inline rtx
+emit_partition_copy (rtx dest, rtx src, int unsignedsrcp)
+{
+ rtx seq;
+
+ start_sequence ();
+
+ if (GET_MODE (src) != VOIDmode && GET_MODE (src) != GET_MODE (dest))
+ src = convert_to_mode (GET_MODE (dest), src, unsignedsrcp);
+ emit_move_insn (dest, src);
+
+ seq = get_insns ();
+ end_sequence ();
+
+ return seq;
+}
+
/* Insert a copy instruction from partition SRC to DEST onto edge E. */
static void
set_location_for_edge (e);
- /* Partition copy between same base variables only, so it's the same mode,
- hence we can use emit_move_insn. */
- start_sequence ();
- emit_move_insn (SA.partition_to_pseudo[dest], SA.partition_to_pseudo[src]);
- seq = get_insns ();
- end_sequence ();
+ seq = emit_partition_copy (SA.partition_to_pseudo[dest],
+ SA.partition_to_pseudo[src],
+ TYPE_UNSIGNED (TREE_TYPE (
+ partition_to_var (SA.map, src))));
insert_insn_on_edge (seq, e);
}
start_sequence ();
mode = GET_MODE (SA.partition_to_pseudo[dest]);
x = expand_expr (src, SA.partition_to_pseudo[dest], mode, EXPAND_NORMAL);
- if (GET_MODE (x) != mode)
+ if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode)
x = convert_to_mode (mode, x, TYPE_UNSIGNED (TREE_TYPE (src)));
+ if (CONSTANT_P (x) && GET_MODE (x) == VOIDmode
+ && mode != TYPE_MODE (TREE_TYPE (src)))
+ x = convert_modes (mode, TYPE_MODE (TREE_TYPE (src)),
+ x, TYPE_UNSIGNED (TREE_TYPE (src)));
if (x != SA.partition_to_pseudo[dest])
emit_move_insn (SA.partition_to_pseudo[dest], x);
seq = get_insns ();
onto edge E. */
static void
-insert_rtx_to_part_on_edge (edge e, int dest, rtx src)
+insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp)
{
rtx seq;
if (dump_file && (dump_flags & TDF_DETAILS))
gcc_assert (SA.partition_to_pseudo[dest]);
set_location_for_edge (e);
- start_sequence ();
- gcc_assert (GET_MODE (src) == GET_MODE (SA.partition_to_pseudo[dest]));
- emit_move_insn (SA.partition_to_pseudo[dest], src);
- seq = get_insns ();
- end_sequence ();
+ seq = emit_partition_copy (SA.partition_to_pseudo[dest],
+ src,
+ unsignedsrcp);
insert_insn_on_edge (seq, e);
}
gcc_assert (SA.partition_to_pseudo[src]);
set_location_for_edge (e);
- start_sequence ();
- gcc_assert (GET_MODE (dest) == GET_MODE (SA.partition_to_pseudo[src]));
- emit_move_insn (dest, SA.partition_to_pseudo[src]);
- seq = get_insns ();
- end_sequence ();
+ seq = emit_partition_copy (dest,
+ SA.partition_to_pseudo[src],
+ TYPE_UNSIGNED (TREE_TYPE (
+ partition_to_var (SA.map, src))));
insert_insn_on_edge (seq, e);
}
if (elim_unvisited_predecessor (g, T))
{
- rtx U = get_temp_reg (partition_to_var (g->map, T));
+ tree var = partition_to_var (g->map, T);
+ rtx U = get_temp_reg (var);
+ int unsignedsrcp = TYPE_UNSIGNED (TREE_TYPE (var));
+
insert_part_to_rtx_on_edge (g->e, U, T);
FOR_EACH_ELIM_GRAPH_PRED (g, T, P,
{
if (!TEST_BIT (g->visited, P))
{
elim_backward (g, P);
- insert_rtx_to_part_on_edge (g->e, P, U);
+ insert_rtx_to_part_on_edge (g->e, P, U, unsignedsrcp);
}
});
}
static void
remove_ssa_form (bool perform_ter, struct ssaexpand *sa)
{
- gimple *values = NULL;
+ bitmap values = NULL;
var_map map;
unsigned i;
}
+/* If not already done so for basic block BB, assign increasing uids
+ to each of its instructions. */
+
+static void
+maybe_renumber_stmts_bb (basic_block bb)
+{
+ unsigned i = 0;
+ gimple_stmt_iterator gsi;
+
+ if (!bb->aux)
+ return;
+ bb->aux = NULL;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ gimple_set_uid (stmt, i);
+ i++;
+ }
+}
+
+
+/* Return true if we can determine that the SSA_NAMEs RESULT (a result
+ of a PHI node) and ARG (one of its arguments) conflict. Return false
+ otherwise, also when we simply aren't sure. */
+
+static bool
+trivially_conflicts_p (basic_block bb, tree result, tree arg)
+{
+ use_operand_p use;
+ imm_use_iterator imm_iter;
+ gimple defa = SSA_NAME_DEF_STMT (arg);
+
+ /* If ARG isn't defined in the same block it's too complicated for
+ our little mind. */
+ if (gimple_bb (defa) != bb)
+ return false;
+
+ FOR_EACH_IMM_USE_FAST (use, imm_iter, result)
+ {
+ gimple use_stmt = USE_STMT (use);
+ /* Now, if there's a use of RESULT that lies outside this basic block,
+ then there surely is a conflict with ARG. */
+ if (gimple_bb (use_stmt) != bb)
+ return true;
+ if (gimple_code (use_stmt) == GIMPLE_PHI)
+ continue;
+ /* The use now is in a real stmt of BB, so if ARG was defined
+ in a PHI node (like RESULT) both conflict. */
+ if (gimple_code (defa) == GIMPLE_PHI)
+ return true;
+ maybe_renumber_stmts_bb (bb);
+ /* If the use of RESULT occurs after the definition of ARG,
+ the two conflict too. */
+ if (gimple_uid (defa) < gimple_uid (use_stmt))
+ return true;
+ }
+
+ return false;
+}
+
+
/* Search every PHI node for arguments associated with backedges which
we can trivially determine will need a copy (the argument is either
not an SSA_NAME or the argument has a different underlying variable
FOR_EACH_BB (bb)
{
+ /* 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);
needed. */
if ((e->flags & EDGE_DFS_BACK)
&& (TREE_CODE (arg) != SSA_NAME
- || SSA_NAME_VAR (arg) != result_var))
+ || SSA_NAME_VAR (arg) != result_var
+ || trivially_conflicts_p (bb, result, arg)))
{
tree name;
gimple stmt, last = NULL;
}
}
}
+
+ /* Unmark this block again. */
+ bb->aux = NULL;
}
}
{
free (sa->partition_to_pseudo);
if (sa->values)
- free (sa->values);
+ BITMAP_FREE (sa->values);
delete_var_map (sa->map);
BITMAP_FREE (sa->partition_has_default_def);
memset (sa, 0, sizeof *sa);