diff options
author | Richard Guenther <rguenther@suse.de> | 2012-06-01 08:55:04 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2012-06-01 08:55:04 +0000 |
commit | 30d55936c5231f0e15104492cd979cc2ff84e0d4 (patch) | |
tree | 07d4b03d8e187ce6dbe5508022b4bcd63398bfaf /gcc/tree-loop-distribution.c | |
parent | c3a43311c13fb31610cdc82f8600dd0c254169c9 (diff) | |
download | gcc-30d55936c5231f0e15104492cd979cc2ff84e0d4.zip gcc-30d55936c5231f0e15104492cd979cc2ff84e0d4.tar.gz gcc-30d55936c5231f0e15104492cd979cc2ff84e0d4.tar.bz2 |
tree-loop-distribution.c (enum partition_kind): New enum.
2012-06-01 Richard Guenther <rguenther@suse.de>
* tree-loop-distribution.c (enum partition_kind): New enum.
(struct partition_s): Add kind and main_stmt members.
(partition_alloc): Initialize kind to PKIND_NORMAL.
(partition_builtin_p): New function.
(copy_loop_before): Remove failure path and assert instead.
(generate_loops_for_partition): Likewise.
(generate_memset_zero): Fold into ...
(generate_memset_builtin): ... this.
(classify_partition): New function with code from
can_generate_builtin and generate_builtin.
(generate_builtin): Remove.
(can_generate_builtin): Likewise.
(fuse_partitions_with_similar_memory_accesses): Call
partition_builtin_p instead of can_generate_builtin.
(rdg_build_partitions): Do not call
fuse_partitions_with_similar_memory_accesses here...
(ldist_gen): ... but here after classifying all partitions.
Remove failure path of generate_code_for_partition.
(generate_code_for_partition): Generate code according
to partition classification.
From-SVN: r188104
Diffstat (limited to 'gcc/tree-loop-distribution.c')
-rw-r--r-- | gcc/tree-loop-distribution.c | 283 |
1 files changed, 140 insertions, 143 deletions
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 3802467..84a8717 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -52,9 +52,14 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "tree-pass.h" +enum partition_kind { PKIND_NORMAL, PKIND_MEMSET }; + typedef struct partition_s { bitmap stmts; + enum partition_kind kind; + /* Main statement a kind != PKIND_NORMAL partition is about. */ + gimple main_stmt; } *partition_t; DEF_VEC_P (partition_t); @@ -67,6 +72,7 @@ partition_alloc (bitmap stmts) { partition_t partition = XCNEW (struct partition_s); partition->stmts = stmts ? stmts : BITMAP_ALLOC (NULL); + partition->kind = PKIND_NORMAL; return partition; } @@ -79,6 +85,13 @@ partition_free (partition_t partition) free (partition); } +/* Returns true if the partition can be generated as a builtin. */ + +static bool +partition_builtin_p (partition_t partition) +{ + return partition->kind != PKIND_NORMAL; +} /* If bit I is not set, it means that this node represents an operation that has already been performed, and that should not be @@ -183,16 +196,11 @@ copy_loop_before (struct loop *loop) struct loop *res; edge preheader = loop_preheader_edge (loop); - if (!single_exit (loop)) - return NULL; - initialize_original_copy_tables (); res = slpeel_tree_duplicate_loop_to_edge_cfg (loop, preheader); + gcc_assert (res != NULL); free_original_copy_tables (); - if (!res) - return NULL; - update_phis_for_loop_copy (loop, res); rename_variables_in_loop (res); @@ -216,10 +224,9 @@ create_bb_after_loop (struct loop *loop) copied when COPY_P is true. All the statements not flagged in the PARTITION bitmap are removed from the loop or from its copy. The statements are indexed in sequence inside a basic block, and the - basic blocks of a loop are taken in dom order. Returns true when - the code gen succeeded. */ + basic blocks of a loop are taken in dom order. */ -static bool +static void generate_loops_for_partition (struct loop *loop, partition_t partition, bool copy_p) { @@ -230,13 +237,11 @@ generate_loops_for_partition (struct loop *loop, partition_t partition, if (copy_p) { loop = copy_loop_before (loop); + gcc_assert (loop != NULL); create_preheader (loop, CP_SIMPLE_PREHEADERS); create_bb_after_loop (loop); } - if (loop == NULL) - return false; - /* Remove stmts not in the PARTITION bitmap. The order in which we visit the phi nodes and the statements is exactly as in stmts_from_loop. */ @@ -293,7 +298,6 @@ generate_loops_for_partition (struct loop *loop, partition_t partition, } free (bbs); - return true; } /* Build the size argument for a memset call. */ @@ -313,19 +317,29 @@ build_size_arg_loc (location_t loc, tree nb_iter, tree op, return x; } -/* Generate a call to memset. Return true when the operation succeeded. */ +/* Generate a call to memset for PARTITION in LOOP. */ static void -generate_memset_zero (gimple stmt, tree op0, tree nb_iter, - gimple_stmt_iterator bsi) +generate_memset_builtin (struct loop *loop, partition_t partition) { - tree addr_base, nb_bytes; - bool res = false; + gimple_stmt_iterator gsi; + gimple stmt, fn_call; + tree op0, nb_iter, mem, fn, addr_base, nb_bytes; gimple_seq stmt_list = NULL, stmts; - gimple fn_call; - tree mem, fn; struct data_reference *dr = XCNEW (struct data_reference); - location_t loc = gimple_location (stmt); + location_t loc; + bool res; + + stmt = partition->main_stmt; + loc = gimple_location (stmt); + op0 = gimple_assign_lhs (stmt); + if (gimple_bb (stmt) == loop->latch) + nb_iter = number_of_latch_executions (loop); + else + nb_iter = number_of_exit_cond_executions (loop); + + /* The new statements will be placed before LOOP. */ + gsi = gsi_last_bb (loop_preheader_edge (loop)->src); DR_STMT (dr) = stmt; DR_REF (dr) = op0; @@ -353,7 +367,7 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter, fn = build_fold_addr_expr (builtin_decl_implicit (BUILT_IN_MEMSET)); fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes); gimple_seq_add_stmt (&stmt_list, fn_call); - gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING); + gsi_insert_seq_after (&gsi, stmt_list, GSI_CONTINUE_LINKING); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "generated memset zero\n"); @@ -361,113 +375,56 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter, free_data_ref (dr); } -/* Tries to generate a builtin function for the instructions of LOOP - pointed to by the bits set in PARTITION. Returns true when the - operation succeeded. */ +/* Remove and destroy the loop LOOP. */ -static bool -generate_builtin (struct loop *loop, partition_t partition, bool copy_p) +static void +destroy_loop (struct loop *loop) { - bool res = false; - unsigned i, x = 0; + unsigned nbbs = loop->num_nodes; + edge exit = single_exit (loop); + basic_block src = loop_preheader_edge (loop)->src, dest = exit->dest; basic_block *bbs; - gimple write = NULL; - gimple_stmt_iterator bsi; - tree nb_iter = number_of_exit_cond_executions (loop); - - if (!nb_iter || nb_iter == chrec_dont_know) - return false; + unsigned i; bbs = get_loop_body_in_dom_order (loop); - for (i = 0; i < loop->num_nodes; i++) - { - basic_block bb = bbs[i]; - - for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi)) - x++; - - for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) - { - gimple stmt = gsi_stmt (bsi); - - if (gimple_code (stmt) == GIMPLE_LABEL - || is_gimple_debug (stmt)) - continue; - - if (!bitmap_bit_p (partition->stmts, x++)) - continue; - - /* If the stmt has uses outside of the loop fail. - ??? If the stmt is generated in another partition that - is not created as builtin we can ignore this. */ - if (stmt_has_scalar_dependences_outside_loop (loop, stmt)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "not generating builtin, partition has " - "scalar uses outside of the loop\n"); - goto end; - } - - if (is_gimple_assign (stmt) - && !is_gimple_reg (gimple_assign_lhs (stmt))) - { - /* Don't generate the builtins when there are more than - one memory write. */ - if (write != NULL) - goto end; - - write = stmt; - if (bb == loop->latch) - nb_iter = number_of_latch_executions (loop); - } - } - } - - if (!stmt_with_adjacent_zero_store_dr_p (write)) - goto end; - - /* The new statements will be placed before LOOP. */ - bsi = gsi_last_bb (loop_preheader_edge (loop)->src); - generate_memset_zero (write, gimple_assign_lhs (write), nb_iter, bsi); - res = true; - - /* If this is the last partition for which we generate code, we have - to destroy the loop. */ - if (!copy_p) - { - unsigned nbbs = loop->num_nodes; - edge exit = single_exit (loop); - basic_block src = loop_preheader_edge (loop)->src, dest = exit->dest; - redirect_edge_pred (exit, src); - exit->flags &= ~(EDGE_TRUE_VALUE|EDGE_FALSE_VALUE); - exit->flags |= EDGE_FALLTHRU; - cancel_loop_tree (loop); - rescan_loop_exit (exit, false, true); - - for (i = 0; i < nbbs; i++) - delete_basic_block (bbs[i]); - - set_immediate_dominator (CDI_DOMINATORS, dest, - recompute_dominator (CDI_DOMINATORS, dest)); - } + redirect_edge_pred (exit, src); + exit->flags &= ~(EDGE_TRUE_VALUE|EDGE_FALSE_VALUE); + exit->flags |= EDGE_FALLTHRU; + cancel_loop_tree (loop); + rescan_loop_exit (exit, false, true); - end: + for (i = 0; i < nbbs; i++) + delete_basic_block (bbs[i]); free (bbs); - return res; + + set_immediate_dominator (CDI_DOMINATORS, dest, + recompute_dominator (CDI_DOMINATORS, dest)); } -/* Generates code for PARTITION. For simple loops, this function can - generate a built-in. */ +/* Generates code for PARTITION. */ -static bool +static void generate_code_for_partition (struct loop *loop, partition_t partition, bool copy_p) { - if (generate_builtin (loop, partition, copy_p)) - return true; - - return generate_loops_for_partition (loop, partition, copy_p); + switch (partition->kind) + { + case PKIND_MEMSET: + generate_memset_builtin (loop, partition); + /* If this is the last partition for which we generate code, we have + to destroy the loop. */ + if (!copy_p) + destroy_loop (loop); + break; + + case PKIND_NORMAL: + generate_loops_for_partition (loop, partition, copy_p); + break; + + default: + gcc_unreachable (); + } } @@ -828,32 +785,71 @@ rdg_build_components (struct graph *rdg, VEC (int, heap) *starting_vertices, BITMAP_FREE (saved_components); } -/* Returns true when it is possible to generate a builtin pattern for - the PARTITION of RDG. For the moment we detect only the memset - zero pattern. */ +/* Classifies the builtin kind we can generate for PARTITION of RDG and LOOP. + For the moment we detect only the memset zero pattern. */ -static bool -can_generate_builtin (struct graph *rdg, partition_t partition) +static void +classify_partition (loop_p loop, struct graph *rdg, partition_t partition) { - unsigned i; bitmap_iterator bi; - int nb_reads = 0; - int nb_writes = 0; - int stores_zero = 0; + unsigned i; + tree nb_iter; + + partition->kind = PKIND_NORMAL; + partition->main_stmt = NULL; + + /* Perform general partition disqualification for builtins. */ + nb_iter = number_of_exit_cond_executions (loop); + if (!nb_iter || nb_iter == chrec_dont_know) + return; EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi) - if (RDG_MEM_READS_STMT (rdg, i)) - nb_reads++; - else if (RDG_MEM_WRITE_STMT (rdg, i)) - { - gimple stmt = RDG_STMT (rdg, i); - nb_writes++; - if (!gimple_has_volatile_ops (stmt) - && stmt_with_adjacent_zero_store_dr_p (stmt)) - stores_zero++; - } + { + gimple stmt = RDG_STMT (rdg, i); + + if (gimple_has_volatile_ops (stmt)) + return; - return stores_zero == 1 && nb_writes == 1 && nb_reads == 0; + /* If the stmt has uses outside of the loop fail. + ??? If the stmt is generated in another partition that + is not created as builtin we can ignore this. */ + if (gimple_code (stmt) != GIMPLE_PHI + && stmt_has_scalar_dependences_outside_loop (loop, stmt)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "not generating builtin, partition has " + "scalar uses outside of the loop\n"); + return; + } + } + + /* Detect memset. */ + EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi) + { + gimple stmt = RDG_STMT (rdg, i); + + if (gimple_code (stmt) == GIMPLE_PHI) + continue; + + /* Any scalar stmts are ok. */ + if (!gimple_vuse (stmt)) + continue; + + /* Exactly one store. */ + if (gimple_assign_single_p (stmt) + && !is_gimple_reg (gimple_assign_lhs (stmt))) + { + if (partition->main_stmt != NULL) + return; + partition->main_stmt = stmt; + } + else + return; + } + + if (partition->main_stmt != NULL + && stmt_with_adjacent_zero_store_dr_p (partition->main_stmt)) + partition->kind = PKIND_MEMSET; } /* Returns true when PARTITION1 and PARTITION2 have similar memory @@ -891,10 +887,10 @@ fuse_partitions_with_similar_memory_accesses (struct graph *rdg, partition_t partition1, partition2; FOR_EACH_VEC_ELT (partition_t, *partitions, p1, partition1) - if (!can_generate_builtin (rdg, partition1)) + if (!partition_builtin_p (partition1)) FOR_EACH_VEC_ELT (partition_t, *partitions, p2, partition2) if (p1 != p2 - && !can_generate_builtin (rdg, partition2) + && !partition_builtin_p (partition2) && similar_memory_accesses (rdg, partition1, partition2)) { bitmap_ior_into (partition1->stmts, partition2->stmts); @@ -971,8 +967,6 @@ rdg_build_partitions (struct graph *rdg, VEC (rdgc, heap) *components, VEC_safe_push (partition_t, heap, *partitions, partition); else partition_free (partition); - - fuse_partitions_with_similar_memory_accesses (rdg, partitions); } /* Dump to FILE the PARTITIONS. */ @@ -1101,11 +1095,15 @@ ldist_gen (struct loop *loop, struct graph *rdg, processed); BITMAP_FREE (processed); + FOR_EACH_VEC_ELT (partition_t, partitions, i, partition) + classify_partition (loop, rdg, partition); + + fuse_partitions_with_similar_memory_accesses (rdg, &partitions); + nbp = VEC_length (partition_t, partitions); if (nbp == 0 || (nbp == 1 - && !can_generate_builtin (rdg, - VEC_index (partition_t, partitions, 0))) + && !partition_builtin_p (VEC_index (partition_t, partitions, 0))) || (nbp > 1 && partition_contains_all_rw (rdg, partitions))) goto ldist_done; @@ -1114,8 +1112,7 @@ ldist_gen (struct loop *loop, struct graph *rdg, dump_rdg_partitions (dump_file, partitions); FOR_EACH_VEC_ELT (partition_t, partitions, i, partition) - if (!generate_code_for_partition (loop, partition, i < nbp - 1)) - goto ldist_done; + generate_code_for_partition (loop, partition, i < nbp - 1); rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); mark_sym_for_renaming (gimple_vop (cfun)); |