X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-outof-ssa.c;h=d3901c34f0e76945de53ee25a3995e7aa63e4985;hb=db899978cbb5a0ffe7e7ddf741c5c61f949f28d2;hp=50d3089340a3c1922e0d021ad0ea4af6823c1849;hpb=4ef1170b5e8bddbaa04cbcb5846dd4bfdc30aee0;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index 50d3089340a..d3901c34f0e 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -1,5 +1,6 @@ /* Convert a program in SSA form into Normal form. - Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. Contributed by Andrew Macleod This file is part of GCC. @@ -36,6 +37,9 @@ along with GCC; see the file COPYING3. If not see #include "ssaexpand.h" +DEF_VEC_I(source_location); +DEF_VEC_ALLOC_I(source_location,heap); + /* Used to hold all the components required to do SSA PHI elimination. The node and pred/succ list is a simple linear list of nodes and edges represented as pairs of nodes. @@ -67,6 +71,9 @@ typedef struct _elim_graph { /* The predecessor and successor edge list. */ VEC(int,heap) *edge_list; + /* Source locus on each edge */ + VEC(source_location,heap) *edge_locus; + /* Visited vector. */ sbitmap visited; @@ -82,6 +89,9 @@ typedef struct _elim_graph { /* List of constant copies to emit. These are pushed on in pairs. */ VEC(int,heap) *const_dests; VEC(tree,heap) *const_copies; + + /* Source locations for any constant copies. */ + VEC(source_location,heap) *copy_locus; } *elim_graph; @@ -110,6 +120,8 @@ set_location_for_edge (edge e) for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) { gimple stmt = gsi_stmt (gsi); + if (is_gimple_debug (stmt)) + continue; if (gimple_has_location (stmt) || gimple_block (stmt)) { set_curr_insn_source_location (gimple_location (stmt)); @@ -150,7 +162,7 @@ emit_partition_copy (rtx dest, rtx src, int unsignedsrcp) /* Insert a copy instruction from partition SRC to DEST onto edge E. */ static void -insert_partition_copy_on_edge (edge e, int dest, int src) +insert_partition_copy_on_edge (edge e, int dest, int src, source_location locus) { rtx seq; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -167,6 +179,9 @@ insert_partition_copy_on_edge (edge e, int dest, int src) gcc_assert (SA.partition_to_pseudo[src]); set_location_for_edge (e); + /* If a locus is provided, override the default. */ + if (locus) + set_curr_insn_source_location (locus); seq = emit_partition_copy (SA.partition_to_pseudo[dest], SA.partition_to_pseudo[src], @@ -180,10 +195,13 @@ insert_partition_copy_on_edge (edge e, int dest, int src) onto edge E. */ static void -insert_value_copy_on_edge (edge e, int dest, tree src) +insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus) { rtx seq, x; - enum machine_mode mode; + enum machine_mode dest_mode, src_mode; + int unsignedp; + tree var; + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, @@ -197,16 +215,27 @@ insert_value_copy_on_edge (edge e, int dest, tree src) gcc_assert (SA.partition_to_pseudo[dest]); set_location_for_edge (e); + /* If a locus is provided, override the default. */ + if (locus) + set_curr_insn_source_location (locus); 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) != 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))); + + var = SSA_NAME_VAR (partition_to_var (SA.map, dest)); + src_mode = TYPE_MODE (TREE_TYPE (src)); + dest_mode = promote_decl_mode (var, &unsignedp); + gcc_assert (src_mode == TYPE_MODE (TREE_TYPE (var))); + gcc_assert (dest_mode == GET_MODE (SA.partition_to_pseudo[dest])); + + if (src_mode != dest_mode) + { + x = expand_expr (src, NULL, src_mode, EXPAND_NORMAL); + x = convert_modes (dest_mode, src_mode, x, unsignedp); + } + else + x = expand_expr (src, SA.partition_to_pseudo[dest], + dest_mode, EXPAND_NORMAL); + if (x != SA.partition_to_pseudo[dest]) emit_move_insn (SA.partition_to_pseudo[dest], x); seq = get_insns (); @@ -219,7 +248,8 @@ insert_value_copy_on_edge (edge e, int dest, tree src) onto edge E. */ static void -insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp) +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)) @@ -233,7 +263,11 @@ insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp) } gcc_assert (SA.partition_to_pseudo[dest]); + set_location_for_edge (e); + /* If a locus is provided, override the default. */ + if (locus) + set_curr_insn_source_location (locus); seq = emit_partition_copy (SA.partition_to_pseudo[dest], src, @@ -246,7 +280,7 @@ insert_rtx_to_part_on_edge (edge e, int dest, rtx src, int unsignedsrcp) onto edge E. */ static void -insert_part_to_rtx_on_edge (edge e, rtx dest, int src) +insert_part_to_rtx_on_edge (edge e, rtx dest, int src, source_location locus) { rtx seq; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -260,7 +294,11 @@ insert_part_to_rtx_on_edge (edge e, rtx dest, int src) } gcc_assert (SA.partition_to_pseudo[src]); + set_location_for_edge (e); + /* If a locus is provided, override the default. */ + if (locus) + set_curr_insn_source_location (locus); seq = emit_partition_copy (dest, SA.partition_to_pseudo[src], @@ -282,7 +320,9 @@ new_elim_graph (int size) g->nodes = VEC_alloc (int, heap, 30); g->const_dests = VEC_alloc (int, heap, 20); g->const_copies = VEC_alloc (tree, heap, 20); + g->copy_locus = VEC_alloc (source_location, heap, 10); g->edge_list = VEC_alloc (int, heap, 20); + g->edge_locus = VEC_alloc (source_location, heap, 10); g->stack = VEC_alloc (int, heap, 30); g->visited = sbitmap_alloc (size); @@ -298,6 +338,7 @@ clear_elim_graph (elim_graph g) { VEC_truncate (int, g->nodes, 0); VEC_truncate (int, g->edge_list, 0); + VEC_truncate (source_location, g->edge_locus, 0); } @@ -312,6 +353,9 @@ delete_elim_graph (elim_graph g) VEC_free (tree, heap, g->const_copies); VEC_free (int, heap, g->const_dests); VEC_free (int, heap, g->nodes); + VEC_free (source_location, heap, g->copy_locus); + VEC_free (source_location, heap, g->edge_locus); + free (g); } @@ -343,10 +387,11 @@ elim_graph_add_node (elim_graph g, int node) /* Add the edge PRED->SUCC to graph G. */ static inline void -elim_graph_add_edge (elim_graph g, int pred, int succ) +elim_graph_add_edge (elim_graph g, int pred, int succ, source_location locus) { VEC_safe_push (int, heap, g->edge_list, pred); VEC_safe_push (int, heap, g->edge_list, succ); + VEC_safe_push (source_location, heap, g->edge_locus, locus); } @@ -354,7 +399,7 @@ elim_graph_add_edge (elim_graph g, int pred, int succ) return the successor node. -1 is returned if there is no such edge. */ static inline int -elim_graph_remove_succ_edge (elim_graph g, int node) +elim_graph_remove_succ_edge (elim_graph g, int node, source_location *locus) { int y; unsigned x; @@ -364,8 +409,11 @@ elim_graph_remove_succ_edge (elim_graph g, int node) VEC_replace (int, g->edge_list, x, -1); y = VEC_index (int, g->edge_list, x + 1); VEC_replace (int, g->edge_list, x + 1, -1); + *locus = VEC_index (source_location, g->edge_locus, x / 2); + VEC_replace (source_location, g->edge_locus, x / 2, UNKNOWN_LOCATION); return y; } + *locus = UNKNOWN_LOCATION; return -1; } @@ -374,7 +422,7 @@ elim_graph_remove_succ_edge (elim_graph g, int node) edge list. VAR will hold the partition number found. CODE is the code fragment executed for every node found. */ -#define FOR_EACH_ELIM_GRAPH_SUCC(GRAPH, NODE, VAR, CODE) \ +#define FOR_EACH_ELIM_GRAPH_SUCC(GRAPH, NODE, VAR, LOCUS, CODE) \ do { \ unsigned x_; \ int y_; \ @@ -384,6 +432,7 @@ do { \ if (y_ != (NODE)) \ continue; \ (VAR) = VEC_index (int, (GRAPH)->edge_list, x_ + 1); \ + (LOCUS) = VEC_index (source_location, (GRAPH)->edge_locus, x_ / 2); \ CODE; \ } \ } while (0) @@ -393,7 +442,7 @@ do { \ GRAPH. VAR will hold the partition number found. CODE is the code fragment executed for every node found. */ -#define FOR_EACH_ELIM_GRAPH_PRED(GRAPH, NODE, VAR, CODE) \ +#define FOR_EACH_ELIM_GRAPH_PRED(GRAPH, NODE, VAR, LOCUS, CODE) \ do { \ unsigned x_; \ int y_; \ @@ -403,6 +452,7 @@ do { \ if (y_ != (NODE)) \ continue; \ (VAR) = VEC_index (int, (GRAPH)->edge_list, x_); \ + (LOCUS) = VEC_index (source_location, (GRAPH)->edge_locus, x_ / 2); \ CODE; \ } \ } while (0) @@ -432,6 +482,7 @@ eliminate_build (elim_graph g) for (gsi = gsi_start_phis (g->e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); + source_location locus; p0 = var_to_partition (g->map, gimple_phi_result (phi)); /* Ignore results which are not in partitions. */ @@ -439,6 +490,7 @@ eliminate_build (elim_graph g) continue; Ti = PHI_ARG_DEF (phi, g->e->dest_idx); + locus = gimple_phi_arg_location_from_edge (phi, g->e); /* 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 @@ -451,6 +503,7 @@ eliminate_build (elim_graph g) on this edge. */ VEC_safe_push (int, heap, g->const_dests, p0); VEC_safe_push (tree, heap, g->const_copies, Ti); + VEC_safe_push (source_location, heap, g->copy_locus, locus); } else { @@ -459,7 +512,7 @@ eliminate_build (elim_graph g) { eliminate_name (g, p0); eliminate_name (g, pi); - elim_graph_add_edge (g, p0, pi); + elim_graph_add_edge (g, p0, pi, locus); } } } @@ -472,8 +525,10 @@ static void elim_forward (elim_graph g, int T) { int S; + source_location locus; + SET_BIT (g->visited, T); - FOR_EACH_ELIM_GRAPH_SUCC (g, T, S, + FOR_EACH_ELIM_GRAPH_SUCC (g, T, S, locus, { if (!TEST_BIT (g->visited, S)) elim_forward (g, S); @@ -488,7 +543,9 @@ static int elim_unvisited_predecessor (elim_graph g, int T) { int P; - FOR_EACH_ELIM_GRAPH_PRED (g, T, P, + source_location locus; + + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus, { if (!TEST_BIT (g->visited, P)) return 1; @@ -502,13 +559,15 @@ static void elim_backward (elim_graph g, int T) { int P; + source_location locus; + SET_BIT (g->visited, T); - FOR_EACH_ELIM_GRAPH_PRED (g, T, P, + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus, { if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); - insert_partition_copy_on_edge (g->e, P, T); + insert_partition_copy_on_edge (g->e, P, T, locus); } }); } @@ -521,9 +580,8 @@ get_temp_reg (tree name) { tree var = TREE_CODE (name) == SSA_NAME ? SSA_NAME_VAR (name) : name; tree type = TREE_TYPE (var); - int unsignedp = TYPE_UNSIGNED (type); - enum machine_mode reg_mode - = promote_mode (type, DECL_MODE (var), &unsignedp, 0); + int unsignedp; + enum 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)))); @@ -537,6 +595,7 @@ static void elim_create (elim_graph g, int T) { int P, S; + source_location locus; if (elim_unvisited_predecessor (g, T)) { @@ -544,23 +603,23 @@ elim_create (elim_graph g, int 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, + insert_part_to_rtx_on_edge (g->e, U, T, UNKNOWN_LOCATION); + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, locus, { if (!TEST_BIT (g->visited, P)) { elim_backward (g, P); - insert_rtx_to_part_on_edge (g->e, P, U, unsignedsrcp); + insert_rtx_to_part_on_edge (g->e, P, U, unsignedsrcp, locus); } }); } else { - S = elim_graph_remove_succ_edge (g, T); + S = elim_graph_remove_succ_edge (g, T, &locus); if (S != -1) { SET_BIT (g->visited, T); - insert_partition_copy_on_edge (g->e, T, S); + insert_partition_copy_on_edge (g->e, T, S, locus); } } } @@ -574,6 +633,7 @@ eliminate_phi (edge e, elim_graph g) int x; gcc_assert (VEC_length (tree, g->const_copies) == 0); + gcc_assert (VEC_length (source_location, g->copy_locus) == 0); /* Abnormal edges already have everything coalesced. */ if (e->flags & EDGE_ABNORMAL) @@ -610,9 +670,12 @@ eliminate_phi (edge e, elim_graph g) { int dest; tree src; + source_location locus; + src = VEC_pop (tree, g->const_copies); dest = VEC_pop (int, g->const_dests); - insert_value_copy_on_edge (e, dest, src); + locus = VEC_pop (source_location, g->copy_locus); + insert_value_copy_on_edge (e, dest, src, locus); } } @@ -853,6 +916,67 @@ remove_ssa_form (bool perform_ter, struct ssaexpand *sa) } +/* 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 @@ -870,6 +994,9 @@ insert_backedge_copies (void) 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); @@ -892,7 +1019,8 @@ insert_backedge_copies (void) 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; @@ -926,6 +1054,11 @@ insert_backedge_copies (void) name = make_ssa_name (result_var, stmt); gimple_assign_set_lhs (stmt, name); + /* copy location if present. */ + if (gimple_phi_arg_has_location (phi, i)) + gimple_set_location (stmt, + gimple_phi_arg_location (phi, i)); + /* Insert the new statement into the block and update the PHI node. */ if (last && stmt_ends_bb_p (last)) @@ -936,6 +1069,9 @@ insert_backedge_copies (void) } } } + + /* Unmark this block again. */ + bb->aux = NULL; } }