From: Sebastian Pop Date: Thu, 11 Dec 2008 07:23:02 +0000 (+0000) Subject: Fix testsuite/gfortran.dg/graphite/id-4.f90. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=81b822d5d08d3158fe0dd4afdef519e6a1cc4ee1;p=gcc.git Fix testsuite/gfortran.dg/graphite/id-4.f90. 2008-12-11 Sebastian Pop Fix testsuite/gfortran.dg/graphite/id-4.f90. * graphite.c (scan_tree_for_params): Do not compute the multiplicand when not needed. 2008-12-11 Sebastian Pop * graphite.c (build_scops_1): Initialize open_scop.exit and sinfo.last. 2008-12-11 Sebastian Pop Jan Sjodin Harsha Jagasia PR middle-end/37852 PR middle-end/37883 PR middle-end/37928 PR middle-end/37980 PR middle-end/38038 PR middle-end/38039 PR middle-end/38073 PR middle-end/38083 PR middle-end/38125 * tree-phinodes.c (remove_phi_nodes): New, extracted from... * tree-cfg.c (remove_phi_nodes_and_edges_for_unreachable_block): ...here. * tree-flow.h (remove_phi_nodes, canonicalize_loop_ivs): Declared. * Makefile.in (graphite.o): Depend on value-prof.h. (graphite.o-warn): Removed -Wno-error. * tree-parloops.c (canonicalize_loop_ivs): Allow reduction_list to be a NULL pointer. Call update_stmt. Return the newly created cannonical induction variable. * graphite.h (debug_rename_map): Declared. Fix some comments. * graphite.c: Reimplement the code generation from graphite to gimple. Include value-prof.h. (loop_iv_stack_get_iv): Do not return NULL for constant substitutions. (get_old_iv_from_ssa_name): Removed. (graphite_stmt_p): New. (new_graphite_bb): Test for useful statements before building a graphite statement for the basic block. (free_graphite_bb): Do not free GBB_DATA_REFS: this is a bug in free_data_ref that calls BITMAP_FREE (DR_VOPS (dr)) without reason. (recompute_all_dominators, graphite_verify, nb_reductions_in_loop, graphite_loop_normal_form): New. (scop_record_loop): Call graphite_loop_normal_form. (build_scop_loop_nests): Iterate over all the blocks of the function instead of relying on the incomplete information from SCOP_BBS. Return the success of the operation. (find_params_in_bb): Use the data from GBB_DATA_REFS. (add_bb_domains): Removed. (build_loop_iteration_domains): Don't call add_bb_domains. Add the iteration domain only to the basic blocks that have been translated to graphite. (build_scop_conditions_1): Add constraints only if the basic block have been translated to graphite. (build_scop_data_accesses): Completely disabled until data dependence is correctly implemented. (debug_rename_elt, debug_rename_map_1, debug_rename_map): New. (remove_all_edges_1, remove_all_edges): Removed. (get_new_name_from_old_name): New. (graphite_rename_variables_in_stmt): Renamed rename_variables_in_stmt. Call get_new_name_from_old_name. Use replace_exp and update_stmt. (is_old_iv): Renamed is_iv. (expand_scalar_variables_stmt): Extra parameter for renaming map. Use replace_exp and update_stmt. (expand_scalar_variables_expr): Same. Use the map to get the new names for the renaming of induction variables and for the renaming of variables after a basic block has been copied. (expand_scalar_variables): Same. (graphite_rename_variables): Renamed rename_variables. (move_phi_nodes): Removed. (get_false_edge_from_guard_bb): New. (build_iv_mapping): Do not insert the induction variable of a loop in the renaming iv map if the basic block does not belong to that loop. (register_old_new_names, graphite_copy_stmts_from_block, copy_bb_and_scalar_dependences): New. (translate_clast): Heavily reimplemented: copy basic blocks, do not move them. Finally, in call cleanup_tree_cfg in gloog. At each translation step call graphite_verify ensuring the consistency of the SSA, loops and dominators information. (collect_virtual_phis, find_vdef_for_var_in_bb, find_vdef_for_var_1, find_vdef_for_var, patch_phis_for_virtual_defs): Removed huge hack. (mark_old_loops, remove_dead_loops, skip_phi_defs, collect_scop_exit_phi_args, patch_scop_exit_phi_args, gbb_can_be_ignored, scop_remove_ignoreable_gbbs, ): Removed. (remove_sese_region, ifsese, if_region_entry, if_region_exit, if_region_get_condition_block, if_region_set_false_region, create_if_region_on_edge, move_sese_in_condition, bb_in_sese_p, sese_find_uses_to_rename_use, sese_find_uses_to_rename_bb, sese_add_exit_phis_edge, sese_add_exit_phis_var, rewrite_into_sese_closed_ssa): New. (gloog): Remove dead code. Early return if code cannot be generated. Call cleanup_tree_cfg once the scop has been code generated. (graphite_trans_scop_block, graphite_trans_loop_block): Do not block loops with less than two loops. (graphite_apply_transformations): Remove the call to scop_remove_ignoreable_gbbs. (limit_scops): When build_scop_loop_nests fails, continue on next scop. Fix open_scop.entry. (graphite_transform_loops): Call recompute_all_dominators: force the recomputation of correct CDI_DOMINATORS and CDI_POST_DOMINATORS. Call initialize_original_copy_tables and free_original_copy_tables to be able to copy basic blocks during code generation. When build_scop_loop_nests fails, continue on next scop. (value_clast): New union. (clast_to_gcc_expression): Fix type cast warning. 2008-12-11 Sebastian Pop * gcc.dg/graphite/pr37928.c: New. * gcc.dg/graphite/pr37883.c: New. * gcc.dg/graphite/pr38073.c: New. * gcc.dg/graphite/pr38125.c: New. * gfortran.dg/graphite/pr38083.f90: New. * gfortran.dg/graphite/pr37852.f90: New. * gfortran.dg/graphite/pr37980.f90: New. * gfortran.dg/graphite/id-2.f90: New. * gfortran.dg/graphite/id-4.f90: New. * gcc.dg/graphite/scop-18.c: Remove reduction, test for the number of detected scops. Copy exact same test for loop blocking... * gcc.dg/graphite/block-1.c: Fix the number of expected loops to be blocked as reductions are not handled. * gcc.dg/graphite/block-4.c: ...here. New. From-SVN: r142673 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e8ee6f2a567..f51730a1f4b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,118 @@ +2008-12-11 Sebastian Pop + + Fix testsuite/gfortran.dg/graphite/id-4.f90. + * graphite.c (scan_tree_for_params): Do not compute the multiplicand + when not needed. + +2008-12-11 Sebastian Pop + + * graphite.c (build_scops_1): Initialize open_scop.exit + and sinfo.last. + +2008-12-11 Sebastian Pop + Jan Sjodin + Harsha Jagasia + + PR middle-end/37852 + PR middle-end/37883 + PR middle-end/37928 + PR middle-end/37980 + PR middle-end/38038 + PR middle-end/38039 + PR middle-end/38073 + PR middle-end/38083 + PR middle-end/38125 + + * tree-phinodes.c (remove_phi_nodes): New, extracted from... + * tree-cfg.c (remove_phi_nodes_and_edges_for_unreachable_block): ...here. + * tree-flow.h (remove_phi_nodes, canonicalize_loop_ivs): Declared. + * Makefile.in (graphite.o): Depend on value-prof.h. + (graphite.o-warn): Removed -Wno-error. + * tree-parloops.c (canonicalize_loop_ivs): Allow reduction_list + to be a NULL pointer. Call update_stmt. Return the newly created + cannonical induction variable. + + * graphite.h (debug_rename_map): Declared. Fix some comments. + + * graphite.c: Reimplement the code generation from graphite to gimple. + Include value-prof.h. + (loop_iv_stack_get_iv): Do not return NULL for constant substitutions. + (get_old_iv_from_ssa_name): Removed. + (graphite_stmt_p): New. + (new_graphite_bb): Test for useful statements before building a + graphite statement for the basic block. + (free_graphite_bb): Do not free GBB_DATA_REFS: this is a bug + in free_data_ref that calls BITMAP_FREE (DR_VOPS (dr)) without + reason. + (recompute_all_dominators, graphite_verify, + nb_reductions_in_loop, graphite_loop_normal_form): New. + (scop_record_loop): Call graphite_loop_normal_form. + (build_scop_loop_nests): Iterate over all the blocks of the + function instead of relying on the incomplete information from + SCOP_BBS. Return the success of the operation. + (find_params_in_bb): Use the data from GBB_DATA_REFS. + (add_bb_domains): Removed. + (build_loop_iteration_domains): Don't call add_bb_domains. + Add the iteration domain only to the basic blocks that have been + translated to graphite. + (build_scop_conditions_1): Add constraints only if the basic + block have been translated to graphite. + (build_scop_data_accesses): Completely disabled until data + dependence is correctly implemented. + (debug_rename_elt, debug_rename_map_1, debug_rename_map): New. + (remove_all_edges_1, remove_all_edges): Removed. + (get_new_name_from_old_name): New. + (graphite_rename_variables_in_stmt): Renamed + rename_variables_in_stmt. Call get_new_name_from_old_name. + Use replace_exp and update_stmt. + (is_old_iv): Renamed is_iv. + (expand_scalar_variables_stmt): Extra parameter for renaming map. + Use replace_exp and update_stmt. + (expand_scalar_variables_expr): Same. Use the map to get the + new names for the renaming of induction variables and for the + renaming of variables after a basic block has been copied. + (expand_scalar_variables): Same. + (graphite_rename_variables): Renamed rename_variables. + (move_phi_nodes): Removed. + (get_false_edge_from_guard_bb): New. + (build_iv_mapping): Do not insert the induction variable of a + loop in the renaming iv map if the basic block does not belong + to that loop. + (register_old_new_names, graphite_copy_stmts_from_block, + copy_bb_and_scalar_dependences): New. + (translate_clast): Heavily reimplemented: copy basic blocks, + do not move them. Finally, in call cleanup_tree_cfg in gloog. + At each translation step call graphite_verify ensuring the + consistency of the SSA, loops and dominators information. + (collect_virtual_phis, find_vdef_for_var_in_bb, + find_vdef_for_var_1, find_vdef_for_var, + patch_phis_for_virtual_defs): Removed huge hack. + (mark_old_loops, remove_dead_loops, skip_phi_defs, + collect_scop_exit_phi_args, patch_scop_exit_phi_args, + gbb_can_be_ignored, scop_remove_ignoreable_gbbs, ): Removed. + (remove_sese_region, ifsese, if_region_entry, if_region_exit, + if_region_get_condition_block, if_region_set_false_region, + create_if_region_on_edge, move_sese_in_condition, bb_in_sese_p, + sese_find_uses_to_rename_use, sese_find_uses_to_rename_bb, + sese_add_exit_phis_edge, sese_add_exit_phis_var, + rewrite_into_sese_closed_ssa): New. + (gloog): Remove dead code. Early return if code cannot be + generated. Call cleanup_tree_cfg once the scop has been code + generated. + (graphite_trans_scop_block, graphite_trans_loop_block): Do not + block loops with less than two loops. + (graphite_apply_transformations): Remove the call to + scop_remove_ignoreable_gbbs. + (limit_scops): When build_scop_loop_nests fails, continue on next scop. + Fix open_scop.entry. + (graphite_transform_loops): Call recompute_all_dominators: force the + recomputation of correct CDI_DOMINATORS and CDI_POST_DOMINATORS. + Call initialize_original_copy_tables and free_original_copy_tables + to be able to copy basic blocks during code generation. + When build_scop_loop_nests fails, continue on next scop. + (value_clast): New union. + (clast_to_gcc_expression): Fix type cast warning. + 2008-12-10 Richard Guenther PR tree-optimization/36792 @@ -261,8 +376,6 @@ Fix testsuite/gfortran.dg/graphite/id-3.f90. * graphite.c (scopdet_basic_block_info): Fix bug that found some regions more than once. - * testsuite/gfortran.dg/graphite/id-3.f90: New. - * gcc/testsuite/gcc.dg/graphite/pr38084.c: New. 2008-12-09 Ben Elliston diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 097159c6457..644694b6adb 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -183,8 +183,6 @@ dfp.o-warn = -Wno-error bitmap.o-warn = -Wno-error # dominance.c contains a -Wc++compat warning. dominance.o-warn = -Wno-error -# graphite.c contains code calling cloog that has problems. -graphite.o-warn = -Wno-error # mips-tfile.c contains -Wcast-qual warnings. mips-tfile.o-warn = -Wno-error @@ -2368,7 +2366,8 @@ tree-data-ref.o: tree-data-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ graphite.o: graphite.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) $(TOPLEV_H) \ $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) $(GIMPLE_H) domwalk.h \ - $(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h graphite.h pointer-set.h + $(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h graphite.h pointer-set.h \ + value-prof.h tree-vect-analyze.o: tree-vect-analyze.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(RECOG_H) $(BASIC_BLOCK_H) \ $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \ diff --git a/gcc/graphite.c b/gcc/graphite.c index 78485a2c833..7c2b8da90b9 100644 --- a/gcc/graphite.c +++ b/gcc/graphite.c @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "tree-pass.h" #include "domwalk.h" +#include "value-prof.h" #include "pointer-set.h" #include "gimple.h" @@ -167,13 +168,9 @@ static tree loop_iv_stack_get_iv (loop_iv_stack stack, int index) { iv_stack_entry_p entry = VEC_index (iv_stack_entry_p, *stack, index); + iv_stack_entry_data data = entry->data; - tree result = NULL; - - if (entry->kind != iv_stack_entry_const) - result = entry->data.iv->t; - - return result; + return iv_stack_entry_is_iv (entry) ? data.iv->t : data.constant; } /* Get the IV from its NAME in STACK. */ @@ -293,33 +290,6 @@ loop_iv_stack_remove_constants (loop_iv_stack stack) } } -/* In SCOP, get the induction variable from NAME. OLD is the original - loop that contained the definition of NAME. */ - -static name_tree -get_old_iv_from_ssa_name (scop_p scop, loop_p old, tree name) -{ - tree var = SSA_NAME_VAR (name); - int i; - name_tree oldiv; - - for (i = 0; VEC_iterate (name_tree, SCOP_OLDIVS (scop), i, oldiv); i++) - { - loop_p current = old; - - while (current) - { - if (var == oldiv->t - && oldiv->loop == current) - return oldiv; - - current = loop_outer (current); - } - } - return NULL; - -} - /* Returns a new loop_to_cloog_loop_str structure. */ static inline struct loop_to_cloog_loop_str * @@ -610,14 +580,6 @@ debug_scops (int verbosity) print_scops (stderr, verbosity); } -/* Return true when BB is contained in SCOP. */ - -static inline bool -bb_in_scop_p (basic_block bb, scop_p scop) -{ - return bitmap_bit_p (SCOP_BBS_B (scop), bb->index); -} - /* Pretty print to FILE the SCOP in DOT format. */ static void @@ -818,15 +780,6 @@ dot_all_scops (void) #endif } -/* Returns true when LOOP is in SCOP. */ - -static inline bool -loop_in_scop_p (struct loop *loop, scop_p scop) -{ - return (bb_in_scop_p (loop->header, scop) - && bb_in_scop_p (loop->latch, scop)); -} - /* Returns the outermost loop in SCOP that contains BB. */ static struct loop * @@ -1025,23 +978,85 @@ harmful_stmt_in_bb (basic_block scop_entry, basic_block bb) return NULL; } +/* Returns true when BB will be represented in graphite. Return false + for the basic blocks that contain code eliminated in the code + generation pass: i.e. induction variables and exit conditions. */ + +static bool +graphite_stmt_p (scop_p scop, basic_block bb, + VEC (data_reference_p, heap) *drs) +{ + gimple_stmt_iterator gsi; + loop_p loop = bb->loop_father; + + if (VEC_length (data_reference_p, drs) > 0) + return true; + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + + switch (gimple_code (stmt)) + { + /* Control flow expressions can be ignored, as they are + represented in the iteration domains and will be + regenerated by graphite. */ + case GIMPLE_COND: + case GIMPLE_GOTO: + case GIMPLE_SWITCH: + break; + + case GIMPLE_ASSIGN: + { + tree var = gimple_assign_lhs (stmt); + var = analyze_scalar_evolution (loop, var); + var = instantiate_scev (block_before_scop (scop), loop, var); + + if (chrec_contains_undetermined (var)) + return true; + + break; + } + + default: + return true; + } + } + + return false; +} + /* Store the GRAPHITE representation of BB. */ static void new_graphite_bb (scop_p scop, basic_block bb) { - struct graphite_bb *gbb = XNEW (struct graphite_bb); + struct graphite_bb *gbb; + VEC (data_reference_p, heap) *drs = VEC_alloc (data_reference_p, heap, 5); + struct loop *nest = outermost_loop_in_scop (scop, bb); + gimple_stmt_iterator gsi; + + bitmap_set_bit (SCOP_BBS_B (scop), bb->index); + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + find_data_references_in_stmt (nest, gsi_stmt (gsi), &drs); + + if (!graphite_stmt_p (scop, bb, drs)) + { + free_data_refs (drs); + return; + } + + gbb = XNEW (struct graphite_bb); bb->aux = gbb; GBB_BB (gbb) = bb; GBB_SCOP (gbb) = scop; - GBB_DATA_REFS (gbb) = NULL; + GBB_DATA_REFS (gbb) = drs; GBB_DOMAIN (gbb) = NULL; GBB_CONDITIONS (gbb) = NULL; GBB_CONDITION_CASES (gbb) = NULL; GBB_LOOPS (gbb) = NULL; VEC_safe_push (graphite_bb_p, heap, SCOP_BBS (scop), gbb); - bitmap_set_bit (SCOP_BBS_B (scop), bb->index); } /* Frees GBB. */ @@ -1052,11 +1067,9 @@ free_graphite_bb (struct graphite_bb *gbb) if (GBB_DOMAIN (gbb)) cloog_matrix_free (GBB_DOMAIN (gbb)); - free_data_refs (GBB_DATA_REFS (gbb)); VEC_free (gimple, heap, GBB_CONDITIONS (gbb)); VEC_free (gimple, heap, GBB_CONDITION_CASES (gbb)); VEC_free (loop_p, heap, GBB_LOOPS (gbb)); - GBB_BB (gbb)->aux = 0; XDELETE (gbb); } @@ -1078,6 +1091,7 @@ new_scop (edge entry, edge exit) SCOP_BBS_B (scop) = BITMAP_ALLOC (NULL); SCOP_LOOPS (scop) = BITMAP_ALLOC (NULL); SCOP_LOOP_NEST (scop) = VEC_alloc (loop_p, heap, 3); + SCOP_ADD_PARAMS (scop) = true; SCOP_PARAMS (scop) = VEC_alloc (name_tree, heap, 3); SCOP_PROG (scop) = cloog_program_malloc (); cloog_program_set_names (SCOP_PROG (scop), cloog_names_malloc ()); @@ -1511,6 +1525,8 @@ build_scops_1 (basic_block current, VEC (sd_region, heap) **scops, loop_p loop) result.next = NULL; result.last = NULL; open_scop.entry = NULL; + open_scop.exit = NULL; + sinfo.last = NULL; /* Loop over the dominance tree. If we meet a difficult bb, close the current SCoP. Loop and condition header start a new layer, @@ -1799,6 +1815,29 @@ mark_exit_edges (VEC (sd_region, heap) *regions) e->aux = s; } +/* Free and compute again all the dominators information. */ + +static inline void +recompute_all_dominators (void) +{ + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); +} + +/* Verifies properties that GRAPHITE should maintain during translation. */ + +static inline void +graphite_verify (void) +{ +#ifdef ENABLE_CHECKING + verify_loop_structure (); + verify_dominators (CDI_DOMINATORS); + verify_dominators (CDI_POST_DOMINATORS); + verify_ssa (false); +#endif +} /* Create for all scop regions a single entry and a single exit edge. */ @@ -1937,64 +1976,108 @@ build_scop_bbs (scop_p scop) sbitmap_free (visited); } +/* Returns the number of reduction phi nodes in LOOP. */ + +static int +nb_reductions_in_loop (loop_p loop) +{ + int res = 0; + gimple_stmt_iterator gsi; -/* Record LOOP as occuring in SCOP. */ + for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + tree scev; -static void -scop_record_loop (scop_p scop, struct loop *loop) + if (!is_gimple_reg (PHI_RESULT (phi))) + continue; + + scev = analyze_scalar_evolution (loop, PHI_RESULT (phi)); + scev = instantiate_parameters (loop, scev); + if (chrec_contains_undetermined (scev)) + res++; + } + + return res; +} + +/* A LOOP is in normal form when it contains only one scalar phi node + that defines the main induction variable of the loop, only one + increment of the IV, and only one exit condition. */ + +static tree +graphite_loop_normal_form (loop_p loop) { - loop_p parent; - tree induction_var; + struct tree_niter_desc niter; + tree nit; + gimple_seq stmts; + edge exit = single_dom_exit (loop); - if (bitmap_bit_p (SCOP_LOOPS (scop), loop->num)) - return; + if (!number_of_iterations_exit (loop, exit, &niter, false)) + gcc_unreachable (); - parent = loop_outer (loop); - induction_var = find_induction_var_from_exit_cond (loop); + nit = force_gimple_operand (unshare_expr (niter.niter), &stmts, true, + NULL_TREE); + if (stmts) + gsi_insert_seq_on_edge_immediate (loop_preheader_edge (loop), stmts); - if (!bb_in_scop_p (parent->latch, scop)) - parent = NULL; + /* One IV per loop. */ + if (nb_reductions_in_loop (loop) > 0) + return NULL_TREE; - if (induction_var != NULL_TREE) - { - name_tree oldiv = XNEW (struct name_tree); - oldiv->t = SSA_NAME_VAR (induction_var); - if (DECL_NAME (oldiv->t)) - oldiv->name = IDENTIFIER_POINTER (DECL_NAME (oldiv->t)); - else - { - int len = 2 + 16; - char *n = XNEWVEC (char, len); - snprintf (n, len, "D.%u", DECL_UID (oldiv->t)); - oldiv->name = n; - } - oldiv->loop = loop; + return canonicalize_loop_ivs (loop, NULL, nit); +} - VEC_safe_push (name_tree, heap, SCOP_OLDIVS (scop), oldiv); - } +/* Record LOOP as occuring in SCOP. Returns true when the operation + was successful. */ + +static bool +scop_record_loop (scop_p scop, loop_p loop) +{ + tree induction_var; + name_tree oldiv; + + if (bitmap_bit_p (SCOP_LOOPS (scop), loop->num)) + return true; bitmap_set_bit (SCOP_LOOPS (scop), loop->num); VEC_safe_push (loop_p, heap, SCOP_LOOP_NEST (scop), loop); + + induction_var = graphite_loop_normal_form (loop); + if (!induction_var) + return false; + + oldiv = XNEW (struct name_tree); + oldiv->t = induction_var; + oldiv->name = get_name (SSA_NAME_VAR (oldiv->t)); + oldiv->loop = loop; + VEC_safe_push (name_tree, heap, SCOP_OLDIVS (scop), oldiv); + return true; } -/* Build the loop nests contained in SCOP. */ +/* Build the loop nests contained in SCOP. Returns true when the + operation was successful. */ -static void +static bool build_scop_loop_nests (scop_p scop) { unsigned i; - graphite_bb_p gb; + basic_block bb; struct loop *loop0, *loop1; - for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) - { - struct loop *loop = gbb_loop (gb); + FOR_EACH_BB (bb) + if (bb_in_scop_p (bb, scop)) + { + struct loop *loop = bb->loop_father; - /* Only add loops, if they are completely contained in the SCoP. */ - if (loop->header == GBB_BB (gb) - && bb_in_scop_p (loop->latch, scop)) - scop_record_loop (scop, gbb_loop (gb)); - } + /* Only add loops if they are completely contained in the SCoP. */ + if (loop->header == bb + && bb_in_scop_p (loop->latch, scop)) + { + if (!scop_record_loop (scop, loop)) + return false; + } + } /* Make sure that the loops in the SCOP_LOOP_NEST are ordered. It can be the case that an inner loop is inserted before an outer @@ -2011,20 +2094,37 @@ build_scop_loop_nests (scop_p scop) VEC_replace (loop_p, SCOP_LOOP_NEST (scop), i + 1, loop0); } } + + return true; } -/* Calculate the number of loops around GB in the current SCOP. */ +/* Build dynamic schedules for all the BBs. */ -static inline int -nb_loops_around_gb (graphite_bb_p gb) +static void +build_scop_dynamic_schedules (scop_p scop) { - scop_p scop = GBB_SCOP (gb); - struct loop *l = gbb_loop (gb); - int d = 0; + int i, dim, loop_num, row, col; + graphite_bb_p gb; - for (; loop_in_scop_p (l, scop); d++, l = loop_outer (l)); + for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) + { + loop_num = GBB_BB (gb)->loop_father->num; - return d; + if (loop_num != 0) + { + dim = nb_loops_around_gb (gb); + GBB_DYNAMIC_SCHEDULE (gb) = cloog_matrix_alloc (dim, dim); + + for (row = 0; row < GBB_DYNAMIC_SCHEDULE (gb)->NbRows; row++) + for (col = 0; col < GBB_DYNAMIC_SCHEDULE (gb)->NbColumns; col++) + if (row == col) + value_set_si (GBB_DYNAMIC_SCHEDULE (gb)->p[row][col], 1); + else + value_set_si (GBB_DYNAMIC_SCHEDULE (gb)->p[row][col], 0); + } + else + GBB_DYNAMIC_SCHEDULE (gb) = NULL; + } } /* Build for BB the static schedule. @@ -2138,6 +2238,8 @@ param_index (tree var, scop_p scop) if (p->t == var) return i; + gcc_assert (SCOP_ADD_PARAMS (scop)); + nvar = XNEW (struct name_tree); nvar->t = var; nvar->name = NULL; @@ -2217,26 +2319,28 @@ scan_tree_for_params (scop_p s, tree e, CloogMatrix *c, int r, Value k, case MULT_EXPR: if (chrec_contains_symbols (TREE_OPERAND (e, 0))) { - Value val; - - gcc_assert (host_integerp (TREE_OPERAND (e, 1), 0)); - - value_init (val); - value_set_si (val, int_cst_value (TREE_OPERAND (e, 1))); - value_multiply (k, k, val); - value_clear (val); + if (c) + { + Value val; + gcc_assert (host_integerp (TREE_OPERAND (e, 1), 0)); + value_init (val); + value_set_si (val, int_cst_value (TREE_OPERAND (e, 1))); + value_multiply (k, k, val); + value_clear (val); + } scan_tree_for_params (s, TREE_OPERAND (e, 0), c, r, k, subtract); } else { - Value val; - - gcc_assert (host_integerp (TREE_OPERAND (e, 0), 0)); - - value_init (val); - value_set_si (val, int_cst_value (TREE_OPERAND (e, 0))); - value_multiply (k, k, val); - value_clear (val); + if (c) + { + Value val; + gcc_assert (host_integerp (TREE_OPERAND (e, 0), 0)); + value_init (val); + value_set_si (val, int_cst_value (TREE_OPERAND (e, 0))); + value_multiply (k, k, val); + value_clear (val); + } scan_tree_for_params (s, TREE_OPERAND (e, 1), c, r, k, subtract); } break; @@ -2347,58 +2451,44 @@ idx_record_params (tree base, tree *idx, void *dta) access functions, conditions and loop bounds. */ static void -find_params_in_bb (scop_p scop, basic_block bb) +find_params_in_bb (scop_p scop, graphite_bb_p gb) { int i; data_reference_p dr; - VEC (data_reference_p, heap) *drs; - gimple_stmt_iterator gsi; - struct loop *nest = outermost_loop_in_scop (scop, bb); - - /* Find the parameters used in the memory access functions. */ - drs = VEC_alloc (data_reference_p, heap, 5); - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - find_data_references_in_stmt (nest, gsi_stmt (gsi), &drs); + gimple stmt; + loop_p father = GBB_BB (gb)->loop_father; - for (i = 0; VEC_iterate (data_reference_p, drs, i, dr); i++) + for (i = 0; VEC_iterate (data_reference_p, GBB_DATA_REFS (gb), i, dr); i++) { struct irp_data irp; - irp.loop = bb->loop_father; + irp.loop = father; irp.scop = scop; for_each_index (&dr->ref, idx_record_params, &irp); free_data_ref (dr); } - VEC_free (data_reference_p, heap, drs); - /* Find parameters in conditional statements. */ - gsi = gsi_last_bb (bb); - if (!gsi_end_p (gsi)) + for (i = 0; VEC_iterate (gimple, GBB_CONDITIONS (gb), i, stmt); i++) { - gimple stmt = gsi_stmt (gsi); + Value one; + loop_p loop = father; - if (gimple_code (stmt) == GIMPLE_COND) - { - Value one; - loop_p loop = bb->loop_father; - - tree lhs, rhs; - - lhs = gimple_cond_lhs (stmt); - lhs = analyze_scalar_evolution (loop, lhs); - lhs = instantiate_scev (block_before_scop (scop), loop, lhs); - - rhs = gimple_cond_rhs (stmt); - rhs = analyze_scalar_evolution (loop, rhs); - rhs = instantiate_scev (block_before_scop (scop), loop, rhs); - - value_init (one); - scan_tree_for_params (scop, lhs, NULL, 0, one, false); - value_set_si (one, 1); - scan_tree_for_params (scop, rhs, NULL, 0, one, false); - value_clear (one); - } + tree lhs, rhs; + + lhs = gimple_cond_lhs (stmt); + lhs = analyze_scalar_evolution (loop, lhs); + lhs = instantiate_scev (block_before_scop (scop), loop, lhs); + + rhs = gimple_cond_rhs (stmt); + rhs = analyze_scalar_evolution (loop, rhs); + rhs = instantiate_scev (block_before_scop (scop), loop, rhs); + + value_init (one); + scan_tree_for_params (scop, lhs, NULL, 0, one, false); + value_set_si (one, 1); + scan_tree_for_params (scop, rhs, NULL, 0, one, false); + value_clear (one); } } @@ -2522,7 +2612,9 @@ find_scop_parameters (scop_p scop) /* Find the parameters used in data accesses. */ for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) - find_params_in_bb (scop, GBB_BB (gb)); + find_params_in_bb (scop, gb); + + SCOP_ADD_PARAMS (scop) = false; } /* Build the context constraints for SCOP: constraints and relations @@ -2554,24 +2646,6 @@ gbb_from_bb (basic_block bb) return (graphite_bb_p) bb->aux; } -/* Add DOMAIN to all the basic blocks in LOOP. */ - -static void -add_bb_domains (struct loop *loop, CloogMatrix *domain) -{ - basic_block *bbs = get_loop_body (loop); - unsigned i; - - for (i = 0; i < loop->num_nodes; i++) - if (bbs[i]->loop_father == loop) - { - graphite_bb_p gbb = gbb_from_bb (bbs[i]); - GBB_DOMAIN (gbb) = cloog_matrix_copy (domain); - } - - free (bbs); -} - /* Builds the constraint matrix for LOOP in SCOP. NB_OUTER_LOOPS is the number of loops surrounding LOOP in SCOP. OUTER_CSTR gives the constraints matrix for the surrounding loops. */ @@ -2582,6 +2656,7 @@ build_loop_iteration_domains (scop_p scop, struct loop *loop, { int i, j, row; CloogMatrix *cstr; + graphite_bb_p gb; int nb_rows = outer_cstr->NbRows + 1; int nb_cols = outer_cstr->NbColumns + 1; @@ -2662,7 +2737,9 @@ build_loop_iteration_domains (scop_p scop, struct loop *loop, if (nb_outer_loops != 0 && loop->next && loop_in_scop_p (loop->next, scop)) build_loop_iteration_domains (scop, loop->next, outer_cstr, nb_outer_loops); - add_bb_domains (loop, cstr); + for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) + if (gbb_loop (gb) == loop) + GBB_DOMAIN (gb) = cloog_matrix_copy (cstr); cloog_matrix_free (cstr); } @@ -2884,10 +2961,12 @@ build_scop_conditions_1 (VEC (gimple, heap) **conditions, /* Record conditions in graphite_bb. */ gbb = gbb_from_bb (bb); - GBB_CONDITIONS (gbb) = VEC_copy (gimple, heap, *conditions); - GBB_CONDITION_CASES (gbb) = VEC_copy (gimple, heap, *cases); - - add_conditions_to_domain (gbb); + if (gbb) + { + GBB_CONDITIONS (gbb) = VEC_copy (gimple, heap, *conditions); + GBB_CONDITION_CASES (gbb) = VEC_copy (gimple, heap, *cases); + add_conditions_to_domain (gbb); + } dom = get_dominated_by (CDI_DOMINATORS, bb); @@ -3049,27 +3128,31 @@ build_scop_iteration_domain (scop_p scop) } /* Initializes an equation CY of the access matrix using the - information for a subscript from ACCESS_FUN, relatively to the loop + information for a subscript from AF, relatively to the loop indexes from LOOP_NEST and parameter indexes from PARAMS. NDIM is the dimension of the array access, i.e. the number of subscripts. Returns true when the operation succeeds. */ static bool -build_access_matrix_with_af (tree access_fun, lambda_vector cy, +build_access_matrix_with_af (tree af, lambda_vector cy, scop_p scop, int ndim) { - switch (TREE_CODE (access_fun)) + int param_col; + + switch (TREE_CODE (af)) { case POLYNOMIAL_CHREC: { - tree left = CHREC_LEFT (access_fun); - tree right = CHREC_RIGHT (access_fun); + struct loop *outer_loop; + tree left = CHREC_LEFT (af); + tree right = CHREC_RIGHT (af); int var; if (TREE_CODE (right) != INTEGER_CST) return false; - - var = loop_iteration_vector_dim (CHREC_VARIABLE (access_fun), scop); + + outer_loop = get_loop (CHREC_VARIABLE (af)); + var = nb_loops_around_loop_in_scop (outer_loop, scop); cy[var] = int_cst_value (right); switch (TREE_CODE (left)) @@ -3082,12 +3165,27 @@ build_access_matrix_with_af (tree access_fun, lambda_vector cy, return true; default: - /* FIXME: access_fn can have parameters. */ - return false; + return build_access_matrix_with_af (left, cy, scop, ndim); } } + + case PLUS_EXPR: + build_access_matrix_with_af (TREE_OPERAND (af, 0), cy, scop, ndim); + build_access_matrix_with_af (TREE_OPERAND (af, 1), cy, scop, ndim); + return true; + + case MINUS_EXPR: + build_access_matrix_with_af (TREE_OPERAND (af, 0), cy, scop, ndim); + build_access_matrix_with_af (TREE_OPERAND (af, 1), cy, scop, ndim); + return true; + case INTEGER_CST: - cy[ndim - 1] = int_cst_value (access_fun); + cy[ndim - 1] = int_cst_value (af); + return true; + + case SSA_NAME: + param_col = param_index (af, scop); + cy [ndim - scop_nb_params (scop) + param_col - 1] = 1; return true; default: @@ -3133,23 +3231,14 @@ build_scop_data_accesses (scop_p scop) int i; graphite_bb_p gb; + /* FIXME: Construction of access matrix is disabled until some + pass, like the data dependence analysis, is using it. */ + return; + for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) { int j; - gimple_stmt_iterator gsi; data_reference_p dr; - struct loop *nest = outermost_loop_in_scop (scop, GBB_BB (gb)); - - /* On each statement of the basic block, gather all the occurences - to read/write memory. */ - GBB_DATA_REFS (gb) = VEC_alloc (data_reference_p, heap, 5); - for (gsi = gsi_start_bb (GBB_BB (gb)); !gsi_end_p (gsi); gsi_next (&gsi)) - find_data_references_in_stmt (nest, gsi_stmt (gsi), - &GBB_DATA_REFS (gb)); - - /* FIXME: Construction of access matrix is disabled until some - pass, like the data dependence analysis, is using it. */ - continue; /* Construct the access matrix for each data ref, with respect to the loop nest of the current BB in the considered SCOP. */ @@ -3199,6 +3288,13 @@ clast_name_to_gcc (const char *name, VEC (name_tree, heap) *params, gcc_unreachable (); } +/* A union needed to convert from CLAST expressions to GMP values. */ + +typedef union { + struct clast_expr *c; + Value v; +} value_clast; + /* Converts a Cloog AST expression E back to a GCC expression tree. */ static tree @@ -3299,15 +3395,12 @@ clast_to_gcc_expression (struct clast_expr *e, { struct clast_binary *b = (struct clast_binary *) e; struct clast_expr *lhs = (struct clast_expr *) b->LHS; - struct clast_expr *rhs = (struct clast_expr *) b->RHS; tree tl = clast_to_gcc_expression (lhs, params, ivstack); + value_clast r; + tree tr; - /* FIXME: The next statement produces a warning: Cloog assumes - that the RHS is a constant, but this is a "void *" pointer - that should be casted into a Value, but this cast cannot be - done as Value is a GMP type, that is an array. Cloog must - be fixed for removing this warning. */ - tree tr = gmp_cst_to_tree (rhs); + r.c = (struct clast_expr *) b->RHS; + tr = gmp_cst_to_tree (r.v); switch (b->type) { @@ -3426,97 +3519,149 @@ graphite_create_new_loop (scop_p scop, edge entry_edge, return loop; } -/* Remove all the edges from EDGES except the edge KEEP. */ - -static void -remove_all_edges_1 (VEC (edge, gc) *edges, edge keep) +/* Structure containing the mapping between the old names and the new + names used after block copy in the new loop context. */ +typedef struct rename_map_elt { - edge e; - edge_iterator ei; + tree old_name, new_name; +} *rename_map_elt; - for (ei = ei_start (edges); (e = ei_safe_edge (ei)); ) - { - if (e != keep) - { - remove_edge (e); - e = ei_safe_edge (ei); - } - else - ei_next (&ei); - } -} -/* Remove all the edges from BB except the edge KEEP. */ +/* Print to stderr the element ELT. */ static void -remove_all_edges (basic_block bb, edge keep) +debug_rename_elt (rename_map_elt elt) { - remove_all_edges_1 (bb->succs, keep); - remove_all_edges_1 (bb->preds, keep); + fprintf (stderr, "("); + print_generic_expr (stderr, elt->old_name, 0); + fprintf (stderr, ", "); + print_generic_expr (stderr, elt->new_name, 0); + fprintf (stderr, ")\n"); } -/* Rename the SSA_NAMEs used in STMT and that appear in IVSTACK. */ +/* Helper function for debug_rename_map. */ -static void -graphite_rename_ivs_stmt (gimple stmt, graphite_bb_p gbb, scop_p scop, - loop_p old, loop_iv_stack ivstack) +static int +debug_rename_map_1 (void **slot, void *s ATTRIBUTE_UNUSED) { - ssa_op_iter iter; - use_operand_p use_p; + struct rename_map_elt *entry = (struct rename_map_elt *) *slot; + debug_rename_elt (entry); + return 1; +} - FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) - { - tree use = USE_FROM_PTR (use_p); - tree new_iv = NULL; - name_tree old_iv = get_old_iv_from_ssa_name (scop, old, use); - - if (old_iv) - new_iv = loop_iv_stack_get_iv (ivstack, - gbb_loop_index (gbb, old_iv->loop)); +/* Print to stderr all the elements of MAP. */ - if (new_iv) - SET_USE (use_p, new_iv); - } +void +debug_rename_map (htab_t map) +{ + htab_traverse (map, debug_rename_map_1, NULL); } -/* Returns true if SSA_NAME is a parameter of SCOP. */ +/* Constructs a new SCEV_INFO_STR structure for VAR and INSTANTIATED_BELOW. */ -static bool -is_parameter (scop_p scop, tree ssa_name) +static inline rename_map_elt +new_rename_map_elt (tree old_name, tree new_name) { - int i; - VEC (name_tree, heap) *params = SCOP_PARAMS (scop); - name_tree param; + rename_map_elt res; + + res = XNEW (struct rename_map_elt); + res->old_name = old_name; + res->new_name = new_name; - for (i = 0; VEC_iterate (name_tree, params, i, param); i++) - if (param->t == ssa_name) - return true; + return res; +} - return false; +/* Computes a hash function for database element ELT. */ + +static hashval_t +rename_map_elt_info (const void *elt) +{ + return htab_hash_pointer (((const struct rename_map_elt *) elt)->old_name); } -/* Returns true if NAME is an old induction variable in SCOP. OLD is - the original loop that contained the definition of NAME. */ +/* Compares database elements E1 and E2. */ -static bool -is_old_iv (scop_p scop, loop_p old, tree name) +static int +eq_rename_map_elts (const void *e1, const void *e2) { - return get_old_iv_from_ssa_name (scop, old, name) != NULL; + const struct rename_map_elt *elt1 = (const struct rename_map_elt *) e1; + const struct rename_map_elt *elt2 = (const struct rename_map_elt *) e2; + return (elt1->old_name == elt2->old_name); } -static void expand_scalar_variables_stmt (gimple, graphite_bb_p, scop_p, loop_p, - loop_iv_stack); +/* Returns the new name associated to OLD_NAME in MAP. */ -/* Constructs a tree which only contains old_ivs and parameters. Any - other variables that are defined outside GBB will be eliminated by - using their definitions in the constructed tree. OLD_LOOP_FATHER - is the original loop that contained GBB. */ +static tree +get_new_name_from_old_name (htab_t map, tree old_name) +{ + struct rename_map_elt tmp; + PTR *slot; + + tmp.old_name = old_name; + slot = htab_find_slot (map, &tmp, NO_INSERT); + + if (slot && *slot) + return ((rename_map_elt) *slot)->new_name; + + return old_name; +} + +/* Rename the SSA_NAMEs used in STMT and that appear in IVSTACK. */ + +static void +rename_variables_in_stmt (gimple stmt, htab_t map) +{ + ssa_op_iter iter; + use_operand_p use_p; + + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) + { + tree use = USE_FROM_PTR (use_p); + tree new_name = get_new_name_from_old_name (map, use); + + replace_exp (use_p, new_name); + } + + update_stmt (stmt); +} + +/* Returns true if SSA_NAME is a parameter of SCOP. */ + +static bool +is_parameter (scop_p scop, tree ssa_name) +{ + int i; + VEC (name_tree, heap) *params = SCOP_PARAMS (scop); + name_tree param; + + for (i = 0; VEC_iterate (name_tree, params, i, param); i++) + if (param->t == ssa_name) + return true; + + return false; +} + +/* Returns true if NAME is an induction variable. */ + +static bool +is_iv (tree name) +{ + return gimple_code (SSA_NAME_DEF_STMT (name)) == GIMPLE_PHI; +} + +static void expand_scalar_variables_stmt (gimple, basic_block, scop_p, + loop_p, htab_t); + +/* Constructs a tree which only contains old_ivs and parameters. Any + other variables that are defined outside BB will be eliminated by + using their definitions in the constructed tree. OLD_LOOP_FATHER + is the original loop that contained BB. */ static tree expand_scalar_variables_expr (tree type, tree op0, enum tree_code code, - tree op1, graphite_bb_p gbb, scop_p scop, - loop_p old_loop_father, loop_iv_stack ivstack) + tree op1, basic_block bb, scop_p scop, + loop_p old_loop_father, htab_t map) { if ((TREE_CODE_CLASS (code) == tcc_constant && code == INTEGER_CST) @@ -3529,8 +3674,7 @@ expand_scalar_variables_expr (tree type, tree op0, enum tree_code code, enum tree_code op0_code = TREE_CODE (op0); tree op0_expr = expand_scalar_variables_expr (op0_type, op0, op0_code, - NULL, gbb, scop, old_loop_father, - ivstack); + NULL, bb, scop, old_loop_father, map); return fold_build1 (code, type, op0_expr); } @@ -3541,14 +3685,12 @@ expand_scalar_variables_expr (tree type, tree op0, enum tree_code code, enum tree_code op0_code = TREE_CODE (op0); tree op0_expr = expand_scalar_variables_expr (op0_type, op0, op0_code, - NULL, gbb, scop, old_loop_father, - ivstack); + NULL, bb, scop, old_loop_father, map); tree op1_type = TREE_TYPE (op1); enum tree_code op1_code = TREE_CODE (op1); tree op1_expr = expand_scalar_variables_expr (op1_type, op1, op1_code, - NULL, gbb, scop, old_loop_father, - ivstack); + NULL, bb, scop, old_loop_father, map); return fold_build2 (code, type, op0_expr, op1_expr); } @@ -3559,34 +3701,34 @@ expand_scalar_variables_expr (tree type, tree op0, enum tree_code code, gimple def_stmt; enum tree_code subcode; - if(is_parameter (scop, op0) || - is_old_iv (scop, old_loop_father, op0)) - return op0; + if (is_parameter (scop, op0) + || is_iv (op0)) + return get_new_name_from_old_name (map, op0); def_stmt = SSA_NAME_DEF_STMT (op0); - if (gimple_bb (def_stmt) == GBB_BB (gbb)) + if (gimple_bb (def_stmt) == bb) { /* If the defining statement is in the basic block already we do not need to create a new expression for it, we only need to ensure its operands are expanded. */ - expand_scalar_variables_stmt (def_stmt, gbb, scop, - old_loop_father, ivstack); - return op0; + expand_scalar_variables_stmt (def_stmt, bb, scop, + old_loop_father, map); + return get_new_name_from_old_name (map, op0); } else { - if (gimple_code (def_stmt) != GIMPLE_ASSIGN) - return op0; + if (gimple_code (def_stmt) != GIMPLE_ASSIGN + || !bb_in_scop_p (gimple_bb (def_stmt), scop)) + return get_new_name_from_old_name (map, op0); var0 = gimple_assign_rhs1 (def_stmt); subcode = gimple_assign_rhs_code (def_stmt); var1 = gimple_assign_rhs2 (def_stmt); - return expand_scalar_variables_expr (type, var0, subcode, var1, - gbb, scop, old_loop_father, - ivstack); + return expand_scalar_variables_expr (type, var0, subcode, var1, + bb, scop, old_loop_father, map); } } @@ -3595,106 +3737,66 @@ expand_scalar_variables_expr (tree type, tree op0, enum tree_code code, } /* Replicates any uses of non-parameters and non-old-ivs variablesthat - are defind outside GBB with code that is inserted in GBB. + are defind outside BB with code that is inserted in BB. OLD_LOOP_FATHER is the original loop that contained STMT. */ static void -expand_scalar_variables_stmt (gimple stmt, graphite_bb_p gbb, scop_p scop, - loop_p old_loop_father, loop_iv_stack ivstack) +expand_scalar_variables_stmt (gimple stmt, basic_block bb, scop_p scop, + loop_p old_loop_father, htab_t map) { ssa_op_iter iter; use_operand_p use_p; - basic_block bb = GBB_BB (gbb); FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) { tree use = USE_FROM_PTR (use_p); tree type = TREE_TYPE (use); enum tree_code code = TREE_CODE (use); - tree use_expr = expand_scalar_variables_expr (type, use, code, NULL, - gbb, scop, old_loop_father, - ivstack); + tree use_expr = expand_scalar_variables_expr (type, use, code, NULL, bb, + scop, old_loop_father, map); if (use_expr != use) { gimple_stmt_iterator gsi = gsi_after_labels (bb); tree new_use = force_gimple_operand_gsi (&gsi, use_expr, true, NULL, true, GSI_NEW_STMT); - SET_USE (use_p, new_use); + replace_exp (use_p, new_use); } } + + update_stmt (stmt); } -/* Copies the definitions outside of GBB of variables that are not - induction variables nor parameters. GBB must only contain +/* Copies the definitions outside of BB of variables that are not + induction variables nor parameters. BB must only contain "external" references to these types of variables. OLD_LOOP_FATHER - is the original loop that contained GBB. */ + is the original loop that contained BB. */ static void -expand_scalar_variables (graphite_bb_p gbb, scop_p scop, - loop_p old_loop_father, loop_iv_stack ivstack) +expand_scalar_variables (basic_block bb, scop_p scop, + loop_p old_loop_father, htab_t map) { - basic_block bb = GBB_BB (gbb); gimple_stmt_iterator gsi; for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);) { gimple stmt = gsi_stmt (gsi); - expand_scalar_variables_stmt (stmt, gbb, scop, old_loop_father, - ivstack); + expand_scalar_variables_stmt (stmt, bb, scop, old_loop_father, map); gsi_next (&gsi); } } -/* Rename all the SSA_NAMEs from block GBB that appear in IVSTACK in - terms of new induction variables. OLD_LOOP_FATHER is the original - loop that contained GBB. */ +/* Rename all the SSA_NAMEs from block BB that appear in IVSTACK in + terms of new induction variables. OLD is the original loop that + contained BB. */ static void -graphite_rename_ivs (graphite_bb_p gbb, scop_p scop, loop_p old_loop_father, - loop_iv_stack ivstack) +rename_variables (basic_block bb, htab_t map) { - basic_block bb = GBB_BB (gbb); gimple_stmt_iterator gsi; - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);) - { - gimple stmt = gsi_stmt (gsi); - - if (gimple_get_lhs (stmt) - && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME - && get_old_iv_from_ssa_name (scop, old_loop_father, - gimple_get_lhs (stmt))) - gsi_remove (&gsi, false); - else - { - graphite_rename_ivs_stmt (stmt, gbb, scop, old_loop_father, ivstack); - gsi_next (&gsi); - } - } -} - -/* Move all the PHI nodes from block FROM to block TO. - OLD_LOOP_FATHER is the original loop that contained FROM. */ - -static void -move_phi_nodes (scop_p scop, loop_p old_loop_father, basic_block from, - basic_block to) -{ - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_phis (from); !gsi_end_p (gsi);) - { - gimple phi = gsi_stmt (gsi); - tree op = gimple_phi_result (phi); - - if (get_old_iv_from_ssa_name (scop, old_loop_father, op) == NULL) - { - gimple new_phi = make_phi_node (op, 0); - add_phi_node_to_bb (new_phi, to); - } - remove_phi_node (&gsi, false); - } + for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + rename_variables_in_stmt (gsi_stmt (gsi), map); } /* Remove condition from BB. */ @@ -3727,6 +3829,131 @@ get_true_edge_from_guard_bb (basic_block bb) return NULL; } +/* Returns the first successor edge of BB with EDGE_TRUE_VALUE flag cleared. */ + +static edge +get_false_edge_from_guard_bb (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if (!(e->flags & EDGE_TRUE_VALUE)) + return e; + + gcc_unreachable (); + return NULL; +} + +/* Inserts in MAP a tuple (OLD_NAME, NEW_NAME) for the induction + variables of the loops around GBB in SCOP, i.e. GBB_LOOPS. + NEW_NAME is obtained from IVSTACK. IVSTACK has the same stack + ordering as GBB_LOOPS. */ + +static void +build_iv_mapping (loop_iv_stack ivstack, htab_t map, gbb_p gbb, scop_p scop) +{ + int i; + name_tree iv; + PTR *slot; + + for (i = 0; VEC_iterate (name_tree, SCOP_OLDIVS (scop), i, iv); i++) + { + struct rename_map_elt tmp; + + if (!flow_bb_inside_loop_p (iv->loop, GBB_BB (gbb))) + continue; + + tmp.old_name = iv->t; + slot = htab_find_slot (map, &tmp, INSERT); + + if (!*slot) + { + tree new_name = loop_iv_stack_get_iv (ivstack, + gbb_loop_index (gbb, iv->loop)); + *slot = new_rename_map_elt (iv->t, new_name); + } + } +} + +/* Register in MAP the tuple (old_name, new_name). */ + +static void +register_old_new_names (htab_t map, tree old_name, tree new_name) +{ + struct rename_map_elt tmp; + PTR *slot; + + tmp.old_name = old_name; + slot = htab_find_slot (map, &tmp, INSERT); + + if (!*slot) + *slot = new_rename_map_elt (old_name, new_name); +} + +/* Create a duplicate of the basic block BB. NOTE: This does not + preserve SSA form. */ + +static void +graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb, htab_t map) +{ + gimple_stmt_iterator gsi, gsi_tgt; + + gsi_tgt = gsi_start_bb (new_bb); + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + def_operand_p def_p; + ssa_op_iter op_iter; + int region; + gimple stmt = gsi_stmt (gsi); + gimple copy; + + if (gimple_code (stmt) == GIMPLE_LABEL) + continue; + + /* Create a new copy of STMT and duplicate STMT's virtual + operands. */ + copy = gimple_copy (stmt); + gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT); + mark_symbols_for_renaming (copy); + + region = lookup_stmt_eh_region (stmt); + if (region >= 0) + add_stmt_to_eh_region (copy, region); + gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt); + + /* Create new names for all the definitions created by COPY and + add replacement mappings for each new name. */ + FOR_EACH_SSA_DEF_OPERAND (def_p, copy, op_iter, SSA_OP_DEF) + { + tree old_name = DEF_FROM_PTR (def_p); + tree new_name = create_new_def_for (old_name, copy, def_p); + register_old_new_names (map, old_name, new_name); + } + } +} + +/* Copies BB and includes in the copied BB all the statements that can + be reached following the use-def chains from the memory accesses, + and returns the next edge following this new block. */ + +static edge +copy_bb_and_scalar_dependences (basic_block bb, scop_p scop, + loop_p context_loop, + edge next_e, htab_t map) +{ + basic_block new_bb = split_edge (next_e); + + next_e = single_succ_edge (new_bb); + graphite_copy_stmts_from_block (bb, new_bb, map); + remove_condition (new_bb); + rename_variables (new_bb, map); + remove_phi_nodes (new_bb); + expand_scalar_variables (new_bb, scop, context_loop, map); + + return next_e; +} + /* Translates a CLAST statement STMT to GCC representation. NEXT_E is the edge where new generated code should be attached. BB_EXIT is the last basic block that defines the scope of code generation. CONTEXT_LOOP is the @@ -3744,35 +3971,23 @@ translate_clast (scop_p scop, struct loop *context_loop, if (CLAST_STMT_IS_A (stmt, stmt_user)) { + htab_t map; CloogStatement *cs = ((struct clast_user_stmt *) stmt)->statement; graphite_bb_p gbb = (graphite_bb_p) cloog_statement_usr (cs); - basic_block bb = gbb->bb; - loop_p old_loop_father = bb->loop_father; - if (bb == ENTRY_BLOCK_PTR) + if (GBB_BB (gbb) == ENTRY_BLOCK_PTR) return next_e; - remove_condition (bb); - expand_scalar_variables (gbb, scop, old_loop_father, ivstack); - remove_all_edges (bb, next_e); - move_phi_nodes (scop, old_loop_father, bb, next_e->src); - redirect_edge_succ_nodup (next_e, bb); - - if (context_loop) - { - remove_bb_from_loops (bb); - add_bb_to_loop (bb, context_loop); - } - - set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src); - mark_virtual_ops_in_bb (bb); - next_e = make_edge (bb, - context_loop ? context_loop->latch : EXIT_BLOCK_PTR, - EDGE_FALLTHRU); - loop_iv_stack_patch_for_consts (ivstack, - (struct clast_user_stmt *) stmt); - graphite_rename_ivs (gbb, scop, old_loop_father, ivstack); + map = htab_create (10, rename_map_elt_info, eq_rename_map_elts, free); + loop_iv_stack_patch_for_consts (ivstack, (struct clast_user_stmt *) stmt); + build_iv_mapping (ivstack, map, gbb, scop); + next_e = copy_bb_and_scalar_dependences (GBB_BB (gbb), scop, + context_loop, next_e, map); + htab_delete (map); loop_iv_stack_remove_constants (ivstack); + update_ssa (TODO_update_ssa); + recompute_all_dominators (); + graphite_verify (); return translate_clast (scop, context_loop, stmt->next, next_e, ivstack); } @@ -3790,7 +4005,9 @@ translate_clast (scop_p scop, struct loop *context_loop, set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src); loop_iv_stack_pop (ivstack); - + last_e = single_succ_edge (split_edge (last_e)); + recompute_all_dominators (); + graphite_verify (); return translate_clast (scop, context_loop, stmt->next, last_e, ivstack); } @@ -3803,7 +4020,7 @@ translate_clast (scop_p scop, struct loop *context_loop, next_e = translate_clast (scop, context_loop, ((struct clast_guard *) stmt)->then, true_e, ivstack); - redirect_edge_succ_nodup (next_e, last_e->src); + graphite_verify (); return translate_clast (scop, context_loop, stmt->next, last_e, ivstack); } @@ -3812,6 +4029,7 @@ translate_clast (scop_p scop, struct loop *context_loop, next_e = translate_clast (scop, context_loop, ((struct clast_block *) stmt)->body, next_e, ivstack); + graphite_verify (); return translate_clast (scop, context_loop, stmt->next, next_e, ivstack); } @@ -4026,183 +4244,6 @@ find_transform (scop_p scop) return stmt; } -/* Return a vector of all the virtual phi nodes in the current - function. */ - -static VEC (gimple, heap) * -collect_virtual_phis (void) -{ - gimple_stmt_iterator si; - gimple_vec phis = VEC_alloc (gimple, heap, 3); - basic_block bb; - - FOR_EACH_BB (bb) - for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) - /* The phis we moved will have 0 arguments because the - original edges were removed. */ - if (gimple_phi_num_args (gsi_stmt (si)) == 0) - VEC_safe_push (gimple, heap, phis, gsi_stmt (si)); - - /* Deallocate if we did not find any. */ - if (VEC_length (gimple, phis) == 0) - { - VEC_free (gimple, heap, phis); - phis = NULL; - } - - return phis; -} - -/* Find a virtual definition for variable VAR in BB. */ - -static tree -find_vdef_for_var_in_bb (basic_block bb, tree var) -{ - gimple_stmt_iterator gsi; - gimple phi; - def_operand_p def_var; - vuse_vec_p vv; - ssa_op_iter op_iter; - - for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) - FOR_EACH_SSA_VDEF_OPERAND (def_var, vv, gsi_stmt (gsi), op_iter) - if (SSA_NAME_VAR (*def_var) == var) - return *def_var; - - for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) - FOR_EACH_SSA_DEF_OPERAND (def_var, gsi_stmt (gsi), op_iter, SSA_OP_DEF) - if (SSA_NAME_VAR (*def_var) == var) - return *def_var; - - for (gsi = gsi_start_phis (bb); !gsi_end_p(gsi); gsi_next (&gsi)) - { - phi = gsi_stmt (gsi); - if (SSA_NAME_VAR (PHI_RESULT (phi)) == var) - return PHI_RESULT (phi); - } - - return NULL; -} - -/* Recursive helper. */ - -static tree -find_vdef_for_var_1 (basic_block bb, struct pointer_set_t *visited, tree var) -{ - tree result = NULL; - edge_iterator ei; - edge pred_edge; - - if (pointer_set_contains (visited, bb)) - return NULL; - - pointer_set_insert (visited, bb); - result = find_vdef_for_var_in_bb (bb, var); - - if (!result) - FOR_EACH_EDGE (pred_edge, ei, bb->preds) - if (!result) - result = find_vdef_for_var_1 (pred_edge->src, visited, var); - - return result; -} - -/* Finds a virtual definition for variable VAR. */ - -static tree -find_vdef_for_var (basic_block bb, tree var) -{ - struct pointer_set_t *visited = pointer_set_create (); - tree def = find_vdef_for_var_1 (bb, visited, var); - - pointer_set_destroy (visited); - return def; -} - -/* Update the virtual phis after loop bodies are moved to new - loops. */ - -static void -patch_phis_for_virtual_defs (void) -{ - int i; - gimple phi; - VEC (gimple, heap) *virtual_phis = collect_virtual_phis (); - - for (i = 0; VEC_iterate (gimple, virtual_phis, i, phi); i++) - { - basic_block bb = gimple_bb (phi); - edge_iterator ei; - edge pred_edge; - gimple_stmt_iterator gsi; - gimple new_phi; - tree phi_result = PHI_RESULT (phi); - tree var = SSA_NAME_VAR (phi_result); - - new_phi = create_phi_node (phi_result, bb); - SSA_NAME_DEF_STMT (phi_result) = new_phi; - - FOR_EACH_EDGE (pred_edge, ei, bb->preds) - { - tree def = find_vdef_for_var (pred_edge->src, var); - - if (def) - add_phi_arg (new_phi, def, pred_edge); - else - add_phi_arg (new_phi, gimple_default_def (cfun, var), pred_edge); - } - - gsi = gsi_for_stmt (phi); - remove_phi_node (&gsi, false); - } - - VEC_free (gimple, heap, virtual_phis); -} - -/* Mark the original loops of SCOP for removal, replacing their header - field with NULL. */ - -static void -mark_old_loops (scop_p scop) -{ - int i; - struct loop *loop; - - for (i = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), i, loop); i++) - { - loop->header = NULL; - loop->latch = NULL; - } -} - -/* Scan the loops and remove the ones that have been marked for - removal. */ - -static void -remove_dead_loops (void) -{ - struct loop *loop, *ploop; - loop_iterator li; - - FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST) - { - /* Remove only those loops that we marked to be removed with - mark_old_loops. */ - if (loop->header) - continue; - - while (loop->inner) - { - ploop = loop->inner; - flow_loop_tree_node_remove (ploop); - flow_loop_tree_node_add (loop_outer (loop), ploop); - } - - /* Remove the loop and free its data. */ - delete_loop (loop); - } -} - /* Returns true when it is possible to generate code for this STMT. For the moment we cannot generate code when Cloog decides to duplicate a statement, as we do not do a copy, but a move. @@ -4261,230 +4302,326 @@ can_generate_code (struct clast_stmt *stmt) return result; } -/* Skip any definition that is a phi node with a single phi def. */ +/* Remove from the CFG the REGION. */ -static tree -skip_phi_defs (tree ssa_name) +static inline void +remove_sese_region (sese region) { - tree result = ssa_name; - gimple def_stmt = SSA_NAME_DEF_STMT (ssa_name); + VEC (basic_block, heap) *bbs = NULL; + basic_block entry_bb = SESE_ENTRY (region)->dest; + basic_block exit_bb = SESE_EXIT (region)->dest; + basic_block bb; + int i; - if (gimple_code (def_stmt) == GIMPLE_PHI - && gimple_phi_num_args (def_stmt) == 1) - result = skip_phi_defs (gimple_phi_arg(def_stmt,0)->def); + VEC_safe_push (basic_block, heap, bbs, entry_bb); + gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs); - return result; + for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + delete_basic_block (bb); + + VEC_free (basic_block, heap, bbs); } -/* Returns a VEC containing the phi-arg defs coming from SCOP_EXIT in - the destination block of SCOP_EXIT. */ +typedef struct ifsese { + sese region; + sese true_region; + sese false_region; +} *ifsese; -static VEC (tree, heap) * -collect_scop_exit_phi_args (edge scop_exit) +static inline edge +if_region_entry (ifsese if_region) { - VEC (tree, heap) *phi_args = VEC_alloc (tree, heap, 1); - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_phis (scop_exit->dest); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple phi = gsi_stmt (gsi); - tree phi_arg = skip_phi_defs(PHI_ARG_DEF_FROM_EDGE (phi, scop_exit)); - - VEC_safe_push (tree, heap, phi_args, phi_arg); - } + return SESE_ENTRY (if_region->region); +} - return phi_args; +static inline edge +if_region_exit (ifsese if_region) +{ + return SESE_EXIT (if_region->region); } -/* Patches (adds) PHI_ARGS to the phi nodes in SCOP_EXIT destination. */ +static inline basic_block +if_region_get_condition_block (ifsese if_region) +{ + return if_region_entry (if_region)->dest; +} -static void -patch_scop_exit_phi_args (edge scop_exit, - VEC (tree, heap) *phi_args) +static inline void +if_region_set_false_region (ifsese if_region, sese region) { - int i = 0; - gimple_stmt_iterator gsi; + basic_block condition = if_region_get_condition_block (if_region); + edge false_edge = get_false_edge_from_guard_bb (condition); + edge entry_region = SESE_ENTRY (region); + edge exit_region = SESE_EXIT (region); + basic_block before_region = entry_region->src; + basic_block last_in_region = exit_region->src; + void **slot = htab_find_slot_with_hash (current_loops->exits, exit_region, + htab_hash_pointer (exit_region), + NO_INSERT); + + entry_region->flags = false_edge->flags; + false_edge->flags = exit_region->flags; + + redirect_edge_pred (entry_region, condition); + redirect_edge_pred (exit_region, before_region); + redirect_edge_pred (false_edge, last_in_region); + + exit_region->flags = EDGE_FALLTHRU; + recompute_all_dominators (); - for (gsi = gsi_start_phis (scop_exit->dest); !gsi_end_p (gsi); - gsi_next (&gsi), i++) + SESE_EXIT (region) = single_succ_edge (false_edge->dest); + if_region->false_region = region; + + if (slot) { - tree def = VEC_index (tree, phi_args, i); - gimple phi = gsi_stmt (gsi); + struct loop_exit *loop_exit = GGC_CNEW (struct loop_exit); - gcc_assert (PHI_ARG_DEF_FROM_EDGE (phi, scop_exit) == NULL); + memcpy (loop_exit, *((struct loop_exit **) slot), sizeof (struct loop_exit)); + htab_clear_slot (current_loops->exits, slot); - add_phi_arg (phi, def, scop_exit); + slot = htab_find_slot_with_hash (current_loops->exits, false_edge, + htab_hash_pointer (false_edge), + INSERT); + loop_exit->e = false_edge; + *slot = loop_exit; + false_edge->src->loop_father->exits->next = loop_exit; } } -/* GIMPLE Loop Generator: generates loops from STMT in GIMPLE form for - the given SCOP. */ - -static void -gloog (scop_p scop, struct clast_stmt *stmt) +static ifsese +create_if_region_on_edge (edge entry, tree condition) { - edge new_scop_exit_edge = NULL; - basic_block scop_exit = SCOP_EXIT (scop); - VEC (tree, heap) *phi_args = - collect_scop_exit_phi_args (SESE_EXIT (SCOP_REGION (scop))); - VEC (iv_stack_entry_p, heap) *ivstack = - VEC_alloc (iv_stack_entry_p, heap, 10); - edge construction_edge = SESE_ENTRY (SCOP_REGION (scop)); - basic_block old_scop_exit_idom = get_immediate_dominator (CDI_DOMINATORS, - scop_exit); + edge e; + edge_iterator ei; + sese sese_region = GGC_NEW (struct sese); + sese true_region = GGC_NEW (struct sese); + sese false_region = GGC_NEW (struct sese); + ifsese if_region = GGC_NEW (struct ifsese); + edge exit = create_empty_if_region_on_edge (entry, condition); - if (!can_generate_code (stmt)) + if_region->region = sese_region; + if_region->region->entry = entry; + if_region->region->exit = exit; + + FOR_EACH_EDGE (e, ei, entry->dest->succs) { - cloog_clast_free (stmt); - return; + if (e->flags & EDGE_TRUE_VALUE) + { + true_region->entry = e; + true_region->exit = single_succ_edge (e->dest); + if_region->true_region = true_region; + } + else if (e->flags & EDGE_FALSE_VALUE) + { + false_region->entry = e; + false_region->exit = single_succ_edge (e->dest); + if_region->false_region = false_region; + } } - redirect_edge_succ_nodup (construction_edge, EXIT_BLOCK_PTR); - new_scop_exit_edge = translate_clast (scop, - construction_edge->src->loop_father, - stmt, construction_edge, &ivstack); - free_loop_iv_stack (&ivstack); - redirect_edge_succ (new_scop_exit_edge, scop_exit); + return if_region; +} - if (!old_scop_exit_idom - || !dominated_by_p (CDI_DOMINATORS, SCOP_ENTRY (scop), - old_scop_exit_idom) - || SCOP_ENTRY (scop) == old_scop_exit_idom) - set_immediate_dominator (CDI_DOMINATORS, - new_scop_exit_edge->dest, - new_scop_exit_edge->src); +/* Moves REGION in a condition expression: + | if (1) + | ; + | else + | REGION; +*/ - cloog_clast_free (stmt); +static ifsese +move_sese_in_condition (sese region) +{ + basic_block pred_block = split_edge (SESE_ENTRY (region)); + ifsese if_region = NULL; - if (new_scop_exit_edge->dest == EXIT_BLOCK_PTR) - new_scop_exit_edge->flags = 0; - - delete_unreachable_blocks (); - patch_phis_for_virtual_defs (); - patch_scop_exit_phi_args (new_scop_exit_edge, phi_args); - VEC_free (tree, heap, phi_args); - mark_old_loops (scop); - remove_dead_loops (); - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); + SESE_ENTRY (region) = single_succ_edge (pred_block); + if_region = create_if_region_on_edge (single_pred_edge (pred_block), integer_one_node); + if_region_set_false_region (if_region, region); -#ifdef ENABLE_CHECKING - verify_loop_structure (); - verify_dominators (CDI_DOMINATORS); - verify_ssa (false); -#endif + return if_region; } -/* Returns the number of data references in SCOP. */ +/* Returns true when BB is in REGION. */ -static int -nb_data_refs_in_scop (scop_p scop) +static bool +bb_in_sese_p (basic_block bb, sese region) { - int i; - graphite_bb_p gbb; - int res = 0; + return (dominated_by_p (CDI_DOMINATORS, bb, SESE_ENTRY (region)->src) + && dominated_by_p (CDI_POST_DOMINATORS, bb, SESE_EXIT (region)->dest)); +} - for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gbb); i++) - res += VEC_length (data_reference_p, GBB_DATA_REFS (gbb)); +/* For USE in BB, if it is used outside of the REGION it is defined in, + mark it for rewrite. Record basic block BB where it is used + to USE_BLOCKS. Record the ssa name index to NEED_PHIS bitmap. */ - return res; +static void +sese_find_uses_to_rename_use (sese region, basic_block bb, tree use, + bitmap *use_blocks, bitmap need_phis) +{ + unsigned ver; + basic_block def_bb; + + if (TREE_CODE (use) != SSA_NAME) + return; + + ver = SSA_NAME_VERSION (use); + def_bb = gimple_bb (SSA_NAME_DEF_STMT (use)); + if (!def_bb + || !bb_in_sese_p (def_bb, region) + || bb_in_sese_p (bb, region)) + return; + + if (!use_blocks[ver]) + use_blocks[ver] = BITMAP_ALLOC (NULL); + bitmap_set_bit (use_blocks[ver], bb->index); + + bitmap_set_bit (need_phis, ver); } -/* Check if a graphite bb can be ignored in graphite. We ignore all - bbs, that only contain code, that will be eliminated later. +/* Marks names that are used in BB and outside of the loop they are + defined in for rewrite. Records the set of blocks in that the ssa + names are defined to USE_BLOCKS. Record the SSA names that will + need exit PHIs in NEED_PHIS. */ + +static void +sese_find_uses_to_rename_bb (sese region, basic_block bb, + bitmap *use_blocks, bitmap need_phis) +{ + gimple_stmt_iterator bsi; + edge e; + edge_iterator ei; + ssa_op_iter iter; + tree var; + + FOR_EACH_EDGE (e, ei, bb->succs) + for (bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi); gsi_next (&bsi)) + sese_find_uses_to_rename_use (region, bb, + PHI_ARG_DEF_FROM_EDGE (gsi_stmt (bsi), e), + use_blocks, need_phis); - TODO: - Move PHI nodes and scalar variables out of these bbs, that only - remain conditions and induction variables. */ + for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) + FOR_EACH_SSA_TREE_OPERAND (var, gsi_stmt (bsi), iter, SSA_OP_ALL_USES) + sese_find_uses_to_rename_use (region, bb, var, use_blocks, need_phis); +} -static bool -gbb_can_be_ignored (graphite_bb_p gb) +/* Add exit phis for the USE on EXIT. */ + +static void +sese_add_exit_phis_edge (basic_block exit, tree use, edge false_e, edge true_e) { - gimple_stmt_iterator gsi; - scop_p scop = GBB_SCOP (gb); - loop_p loop = GBB_BB (gb)->loop_father; + gimple phi = create_phi_node (use, exit); - if (VEC_length (data_reference_p, GBB_DATA_REFS(gb))) - return false; + create_new_def_for (gimple_phi_result (phi), phi, + gimple_phi_result_ptr (phi)); + add_phi_arg (phi, use, false_e); + add_phi_arg (phi, integer_zero_node, true_e); +} - /* Check statements. */ - for (gsi = gsi_start_bb (GBB_BB (gb)); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); - switch (gimple_code (stmt)) - { - /* Control flow expressions can be ignored, as they are - represented in the iteration domains and will be - regenerated by graphite. */ - case GIMPLE_COND: - case GIMPLE_GOTO: - case GIMPLE_SWITCH: - break; +/* Add phi nodes for VAR that is used in LIVEIN. Phi nodes are + inserted in block WHERE. */ - /* Scalar variables can be ignored, if we can regenerate - them later using their scalar evolution function. - XXX: Just a heuristic, that needs further investigation. */ - case GIMPLE_ASSIGN: - { - tree var = gimple_assign_lhs (stmt); - var = analyze_scalar_evolution (loop, var); - var = instantiate_scev (block_before_scop (scop), loop, var); +static void +sese_add_exit_phis_var (basic_block where, tree var, bitmap livein, + edge false_e, edge true_e) +{ + bitmap def; + basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (var)); - if (TREE_CODE (var) == SCEV_NOT_KNOWN) - return false; + if (is_gimple_reg (var)) + bitmap_clear_bit (livein, def_bb->index); + else + bitmap_set_bit (livein, def_bb->index); - break; - } - /* Otherwise not ignoreable. */ - default: - return false; - } - } + def = BITMAP_ALLOC (NULL); + bitmap_set_bit (def, def_bb->index); + compute_global_livein (livein, def); + BITMAP_FREE (def); - return true; + sese_add_exit_phis_edge (where, var, false_e, true_e); } -/* Remove all ignoreable gbbs from SCOP. */ +/* Insert in the block WHERE phi nodes for variables defined in REGION + and used outside the REGION. */ static void -scop_remove_ignoreable_gbbs (scop_p scop) +rewrite_into_sese_closed_ssa (sese region, basic_block where, + edge false_e, edge true_e) { - graphite_bb_p gb; - int i; + unsigned i; + basic_block bb; + bitmap_iterator bi; + bitmap names_to_rename = BITMAP_ALLOC (NULL); + unsigned old_num_ssa_names = num_ssa_names; + bitmap *use_blocks = XCNEWVEC (bitmap, old_num_ssa_names); - int max_schedule = scop_max_loop_depth (scop) + 1; - lambda_vector last_schedule = lambda_vector_new (max_schedule); - lambda_vector_clear (last_schedule, max_schedule); + update_ssa (TODO_update_ssa); - /* Update schedules. */ - for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) - { - int nb_loops = gbb_nb_loops (gb); + FOR_EACH_BB (bb) + sese_find_uses_to_rename_bb (region, bb, use_blocks, names_to_rename); - if (GBB_STATIC_SCHEDULE (gb) [nb_loops] == 0) - last_schedule [nb_loops] = 0; + EXECUTE_IF_SET_IN_BITMAP (names_to_rename, 0, i, bi) + sese_add_exit_phis_var (where, ssa_name (i), use_blocks[i], + false_e, true_e); - if (gbb_can_be_ignored (gb)) - { - /* Mark gbb for remove. */ - bitmap_clear_bit (SCOP_BBS_B (scop), gb->bb->index); - GBB_SCOP (gb) = NULL; - last_schedule [nb_loops]--; - } - else - lambda_vector_add (GBB_STATIC_SCHEDULE (gb), last_schedule, - GBB_STATIC_SCHEDULE (gb), nb_loops + 1); + update_ssa (TODO_update_ssa); + + for (i = 0; i < old_num_ssa_names; i++) + BITMAP_FREE (use_blocks[i]); + + free (use_blocks); + BITMAP_FREE (names_to_rename); +} + +/* GIMPLE Loop Generator: generates loops from STMT in GIMPLE form for + the given SCOP. */ + +static void +gloog (scop_p scop, struct clast_stmt *stmt) +{ + edge new_scop_exit_edge = NULL; + VEC (iv_stack_entry_p, heap) *ivstack = VEC_alloc (iv_stack_entry_p, heap, + 10); + loop_p context_loop; + ifsese if_region = NULL; + + if (!can_generate_code (stmt)) + { + cloog_clast_free (stmt); + return; } - /* Remove gbbs. */ - for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gb); i++) - if (GBB_SCOP (gb) == NULL) - { - VEC_unordered_remove (graphite_bb_p, SCOP_BBS (scop), i); - free_graphite_bb (gb); - /* XXX: Hackish? But working. */ - i--; - } + if_region = move_sese_in_condition (SCOP_REGION (scop)); + rewrite_into_sese_closed_ssa (SCOP_REGION (scop), + if_region->region->exit->src, + if_region->false_region->exit, + if_region->true_region->exit); + graphite_verify (); + context_loop = SESE_ENTRY (SCOP_REGION (scop))->src->loop_father; + new_scop_exit_edge = translate_clast (scop, context_loop, + stmt, if_region->true_region->entry, + &ivstack); + graphite_verify (); + cleanup_tree_cfg (); + recompute_all_dominators (); + graphite_verify (); + free_loop_iv_stack (&ivstack); + cloog_clast_free (stmt); +} - graphite_sort_gbbs (scop); +/* Returns the number of data references in SCOP. */ + +static int +nb_data_refs_in_scop (scop_p scop) +{ + int i; + graphite_bb_p gbb; + int res = 0; + + for (i = 0; VEC_iterate (graphite_bb_p, SCOP_BBS (scop), i, gbb); i++) + res += VEC_length (data_reference_p, GBB_DATA_REFS (gbb)); + + return res; } /* Move the loop at index LOOP and insert it before index NEW_LOOP_POS. @@ -4962,11 +5099,6 @@ graphite_trans_loop_block (VEC (graphite_bb_p, heap) *bbs, int loops) /* TODO: - Calculate the stride size automatically. */ int stride_size = 64; - /* It makes no sense to block a single loop. */ - for (i = 0; VEC_iterate (graphite_bb_p, bbs, i, gb); i++) - if (gbb_nb_loops (gb) < 2) - return false; - for (i = 0; VEC_iterate (graphite_bb_p, bbs, i, gb); i++) transform_done |= graphite_trans_bb_block (gb, stride_size, loops); @@ -5049,7 +5181,7 @@ graphite_trans_scop_block (scop_p scop) j++; /* Found perfect loop nest. */ - if (perfect && last_nb_loops - j > 0) + if (perfect && last_nb_loops - j >= 2) transform_done |= graphite_trans_loop_block (bbs, last_nb_loops - j); /* Check if we start with a new loop. @@ -5108,7 +5240,6 @@ graphite_apply_transformations (scop_p scop) /* Sort the list of bbs. Keep them always sorted. */ graphite_sort_gbbs (scop); - scop_remove_ignoreable_gbbs (scop); if (flag_loop_block) transform_done = graphite_trans_scop_block (scop); @@ -5157,13 +5288,15 @@ limit_scops (void) int j; loop_p loop; build_scop_bbs (scop); - build_scop_loop_nests (scop); + + if (!build_scop_loop_nests (scop)) + continue; for (j = 0; VEC_iterate (loop_p, SCOP_LOOP_NEST (scop), j, loop); j++) if (!loop_in_scop_p (loop_outer (loop), scop)) { sd_region open_scop; - open_scop.entry = loop_preheader_edge (loop)->dest; + open_scop.entry = loop->header; open_scop.exit = single_exit (loop)->dest; VEC_safe_push (sd_region, heap, tmp_scops, &open_scop); } @@ -5190,13 +5323,12 @@ graphite_transform_loops (void) return; current_scops = VEC_alloc (scop_p, heap, 3); - - calculate_dominance_info (CDI_DOMINATORS); - calculate_dominance_info (CDI_POST_DOMINATORS); + recompute_all_dominators (); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Graphite loop transformations \n"); + initialize_original_copy_tables (); cloog_initialize (); build_scops (); limit_scops (); @@ -5208,9 +5340,12 @@ graphite_transform_loops (void) for (i = 0; VEC_iterate (scop_p, current_scops, i, scop); i++) { build_scop_bbs (scop); - build_scop_loop_nests (scop); + if (!build_scop_loop_nests (scop)) + continue; + build_scop_canonical_schedules (scop); build_bb_loops (scop); + build_scop_conditions (scop); find_scop_parameters (scop); build_scop_context (scop); @@ -5226,8 +5361,8 @@ graphite_transform_loops (void) if (!build_scop_iteration_domain (scop)) continue; - build_scop_conditions (scop); build_scop_data_accesses (scop); + build_scop_dynamic_schedules (scop); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -5249,6 +5384,7 @@ graphite_transform_loops (void) /* Cleanup. */ free_scops (current_scops); cloog_finalize (); + free_original_copy_tables (); } #else /* If Cloog is not available: #ifndef HAVE_cloog. */ diff --git a/gcc/graphite.h b/gcc/graphite.h index 2e2904a6abf..faae00950d6 100644 --- a/gcc/graphite.h +++ b/gcc/graphite.h @@ -18,6 +18,9 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ +#ifndef GCC_GRAPHITE_H +#define GCC_GRAPHITE_H + #include "tree-data-ref.h" typedef struct graphite_bb *graphite_bb_p; @@ -31,7 +34,7 @@ static inline int scop_nb_loops (scop_p scop); static inline unsigned scop_nb_params (scop_p scop); static inline bool scop_contains_loop (scop_p scop, struct loop *loop); -struct graphite_bb +typedef struct graphite_bb { basic_block bb; scop_p scop; @@ -116,7 +119,7 @@ struct graphite_bb CloogMatrix *domain; /* Lists containing the restrictions of the conditional statements - dominating this bb. This bb can only be executed, if all conditions + dominating this bb. This bb can only be executed, if all conditions are true. Example: @@ -129,13 +132,13 @@ struct graphite_bb B } - So for B there is a additional condition (2i <= 8). + So for B there is an additional condition (2i <= 8). - TODO: Add this restrictions to the domain matrix. + TODO: Add these restrictions to the domain matrix. - List of COND_EXPR and SWITCH_EXPR. A COND_EXPR is true only if the - corresponding element in CONDITION_CASES is not NULL_TREE. For a - SWITCH_EXPR the corresponding element in CONDITION_CASES is a + List of COND_EXPR and SWITCH_EXPR. A COND_EXPR is true only if the + corresponding element in CONDITION_CASES is not NULL_TREE. For a + SWITCH_EXPR the corresponding element in CONDITION_CASES is a CASE_LABEL_EXPR. */ VEC (gimple, heap) *conditions; VEC (gimple, heap) *condition_cases; @@ -190,7 +193,7 @@ struct graphite_bb lambda_vector compressed_alpha_matrix; CloogMatrix *dynamic_schedule; VEC (data_reference_p, heap) *data_refs; -}; +} *gbb_p; #define GBB_BB(GBB) GBB->bb #define GBB_SCOP(GBB) GBB->scop @@ -234,7 +237,7 @@ gbb_loop_at_index (graphite_bb_p gb, int index) return VEC_index (loop_p, GBB_LOOPS (gb), index); } -/* Returns the corresponding loop iterator index for a gimple loop. */ +/* Returns the index of LOOP in the loop nest around GB. */ static inline int gbb_loop_index (graphite_bb_p gb, loop_p loop) @@ -305,8 +308,13 @@ struct scop /* ??? It looks like a global mapping loop_id -> cloog_loop would work. */ htab_t loop2cloog_loop; - /* CLooG representation of this SCOP. */ + /* Cloog representation of this scop. */ CloogProgram *program; + + /* Are we allowed to add more params? This is for debugging purpose. We + can only add new params before generating the bb domains, otherwise they + become invalid. */ + bool add_params; }; #define SCOP_BBS(S) S->bbs @@ -322,6 +330,7 @@ struct scop #define SCOP_STATIC_SCHEDULE(S) S->static_schedule #define SCOP_LOOPS(S) S->loops #define SCOP_LOOP_NEST(S) S->loop_nest +#define SCOP_ADD_PARAMS(S) S->add_params #define SCOP_PARAMS(S) S->params #define SCOP_OLDIVS(S) S->old_ivs #define SCOP_PROG(S) S->program @@ -335,8 +344,7 @@ extern void debug_gbb (graphite_bb_p, int); extern void dot_scop (scop_p); extern void dot_all_scops (void); extern void debug_clast_stmt (struct clast_stmt *); - - +extern void debug_rename_map (htab_t); extern void debug_loop_vec (graphite_bb_p gb); extern void debug_oldivs (scop_p); @@ -369,7 +377,6 @@ DEF_VEC_ALLOC_P(iv_stack_entry_p,heap); typedef VEC(iv_stack_entry_p, heap) **loop_iv_stack; extern void debug_loop_iv_stack (loop_iv_stack); - /* Return the number of gimple loops contained in SCOP. */ static inline int @@ -422,15 +429,6 @@ loop_domain_dim (unsigned int loop_num, scop_p scop) return cloog_domain_dim (cloog_loop_domain (slot->cloog_loop)) + 2; } -/* Returns the dimensionality of an enclosing loop iteration domain - with respect to enclosing SCoP for a given data reference REF. */ - -static inline int -ref_nb_loops (data_reference_p ref) -{ - return loop_domain_dim (loop_containing_stmt (DR_STMT (ref))->num, DR_SCOP (ref)); -} - /* Returns the dimensionality of a loop iteration vector in a loop iteration domain for a given loop (identified by LOOP_NUM) with respect to SCOP. */ @@ -521,22 +519,59 @@ scop_gimple_loop_depth (scop_p scop, loop_p loop) return depth; } -/* Associate a POLYHEDRON dependence description to two data - references A and B. */ -struct data_dependence_polyhedron +/* Static inline function prototypes. */ + +static inline unsigned scop_nb_params (scop_p scop); + +/* Returns true when BB is in SCOP. */ + +static inline bool +bb_in_scop_p (basic_block bb, scop_p scop) { - struct data_reference *a; - struct data_reference *b; - bool reversed_p; - bool loop_carried; /*TODO:konrad get rid of this, make level signed */ - signed level; - CloogDomain *polyhedron; -}; + return bitmap_bit_p (SCOP_BBS_B (scop), bb->index); +} -#define RDGE_DDP(E) ((struct data_dependence_polyhedron*) ((E)->data)) +/* Returns true when LOOP is in SCOP. */ -typedef struct data_dependence_polyhedron *ddp_p; +static inline bool +loop_in_scop_p (struct loop *loop, scop_p scop) +{ + return (bb_in_scop_p (loop->header, scop) + && bb_in_scop_p (loop->latch, scop)); +} + +/* Calculate the number of loops around LOOP in the SCOP. */ + +static inline int +nb_loops_around_loop_in_scop (struct loop *l, scop_p scop) +{ + int d = 0; + + for (; loop_in_scop_p (l, scop); d++, l = loop_outer (l)); + + return d; +} + +/* Calculate the number of loops around GB in the current SCOP. */ + +static inline int +nb_loops_around_gb (graphite_bb_p gb) +{ + return nb_loops_around_loop_in_scop (gbb_loop (gb), GBB_SCOP (gb)); +} + +/* Returns the dimensionality of an enclosing loop iteration domain + with respect to enclosing SCoP for a given data reference REF. The + returned dimensionality is homogeneous (depth of loop nest + number + of SCoP parameters + const). */ -DEF_VEC_P(ddp_p); -DEF_VEC_ALLOC_P(ddp_p,heap); +static inline int +ref_nb_loops (data_reference_p ref) +{ + loop_p loop = loop_containing_stmt (DR_STMT (ref)); + scop_p scop = DR_SCOP (ref); + + return nb_loops_around_loop_in_scop (loop, scop) + scop_nb_params (scop) + 2; +} +#endif /* GCC_GRAPHITE_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 20881212bd5..207da42eda5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,30 @@ +2008-12-11 Sebastian Pop + + PR middle-end/37852 + PR middle-end/37883 + PR middle-end/37928 + PR middle-end/37980 + PR middle-end/38038 + PR middle-end/38039 + PR middle-end/38073 + PR middle-end/38083 + PR middle-end/38125 + * gcc.dg/graphite/pr37928.c: New. + * gcc.dg/graphite/pr37883.c: New. + * gcc.dg/graphite/pr38073.c: New. + * gcc.dg/graphite/pr38125.c: New. + * gfortran.dg/graphite/pr38083.f90: New. + * gfortran.dg/graphite/pr37852.f90: New. + * gfortran.dg/graphite/pr37980.f90: New. + * gfortran.dg/graphite/id-2.f90: New. + * gfortran.dg/graphite/id-4.f90: New. + + * gcc.dg/graphite/scop-18.c: Remove reduction, test for + the number of detected scops. Copy exact same test for loop blocking... + * gcc.dg/graphite/block-1.c: Fix the number of expected loops + to be blocked as reductions are not handled. + * gcc.dg/graphite/block-4.c: ...here. New. + 2008-12-11 Ira Rosen PR tree-optimization/38464 @@ -95,6 +122,12 @@ PR c++/38410 * gcc.dg/ctor1.c: New test. +2008-12-09 Tobias Grosser + + PR middle-end/38084 + * gfortran.dg/graphite/id-3.f90: New. + * gcc.dg/graphite/pr38084.c: New. + 2008-12-08 Uros Bizjak * gcc.target/mips/fix-r10000-6.c: Add dg-message to look for diff --git a/gcc/testsuite/gcc.dg/graphite/block-1.c b/gcc/testsuite/gcc.dg/graphite/block-1.c index 039b974fdae..857f8d54e8e 100644 --- a/gcc/testsuite/gcc.dg/graphite/block-1.c +++ b/gcc/testsuite/gcc.dg/graphite/block-1.c @@ -2,6 +2,8 @@ #define MAX 8192 +void bar (void); + int main() { int i, j; @@ -9,6 +11,8 @@ int main() int A[MAX * MAX]; int B[MAX * MAX]; + bar (); + for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { @@ -20,6 +24,11 @@ int main() for (j = 0; j < MAX; j++) A[i*MAX + j] += B[j*MAX + i]; + bar (); + + /* FIXME: For now, reductions are not handled by the code generation + of graphite. We have to bound the scop to the above loops. */ + for(i = 0; i < MAX; i++) for(j = 0; j < MAX; j++) sum += A[i*MAX + j]; @@ -27,5 +36,5 @@ int main() return sum; } -/* { dg-final { scan-tree-dump-times "Loop blocked" 3 "graphite"} } */ +/* { dg-final { scan-tree-dump-times "Loop blocked" 2 "graphite"} } */ /* { dg-final { cleanup-tree-dump "graphite" } } */ diff --git a/gcc/testsuite/gcc.dg/graphite/block-4.c b/gcc/testsuite/gcc.dg/graphite/block-4.c new file mode 100644 index 00000000000..4b550b4e472 --- /dev/null +++ b/gcc/testsuite/gcc.dg/graphite/block-4.c @@ -0,0 +1,26 @@ +/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */ + +#define N 24 +#define M 1000 + +float A[1000][1000], B[1000][1000], C[1000][1000]; + +void test (void) +{ + int i, j, k; + + /* These loops contain too few iterations for being strip-mined by 64. */ + for (i = 0; i < 24; i++) + for (j = 0; j < 24; j++) + for (k = 0; k < 24; k++) + A[i][j] = B[i][k] * C[k][j]; + + /* These loops should still be strip mined. */ + for (i = 0; i < 1000; i++) + for (j = 0; j < 1000; j++) + for (k = 0; k < 1000; k++) + A[i][j] = B[i][k] * C[k][j]; +} + +/* { dg-final { scan-tree-dump-times "Strip Mining is not profitable" 2 "graphite" } } */ +/* { dg-final { cleanup-tree-dump "graphite" } } */ diff --git a/gcc/testsuite/gcc.dg/graphite/pr37883.c b/gcc/testsuite/gcc.dg/graphite/pr37883.c new file mode 100644 index 00000000000..2ab043adce1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/graphite/pr37883.c @@ -0,0 +1,11 @@ +/* { dg-options "-O3 -floop-block" } */ + +void test_sort() +{ + char *base; + register char c, *i, *hi; + + for (i = base; i < hi; i++) + *i++ = c; +} + diff --git a/gcc/testsuite/gcc.dg/graphite/pr37928.c b/gcc/testsuite/gcc.dg/graphite/pr37928.c new file mode 100644 index 00000000000..47ad5bce0bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/graphite/pr37928.c @@ -0,0 +1,33 @@ +/* { dg-options "-O3 -floop-block" } */ + +int get_state(int size, int *node, int *hash) +{ + int i=0; + while(hash[i]) + { + if(node[hash[i]] == 0) + return hash[i]-1; + i++; + if(i==5) + i=0; + } + return -1; +} + +void foo (int); + +int gate1(int size, int *node, int *hash) +{ + int i, j ; + int add_size=0; + for(i=0; isv_any)->xav_fill; + TEST_SV** ary = ((TEST_SV**)((TEST_XPVAV*) (av)->sv_any)->xav_array); + while (key < fill) + ary[++key] = &PL_sv_undef; +} diff --git a/gcc/testsuite/gcc.dg/graphite/scop-18.c b/gcc/testsuite/gcc.dg/graphite/scop-18.c index fe2d5f4a412..6264116e114 100644 --- a/gcc/testsuite/gcc.dg/graphite/scop-18.c +++ b/gcc/testsuite/gcc.dg/graphite/scop-18.c @@ -1,4 +1,4 @@ -/* { dg-options "-O2 -floop-block -fdump-tree-graphite-all" } */ +/* { dg-options "-O2 -fgraphite -fdump-tree-graphite-all" } */ #define N 24 #define M 1000 @@ -13,14 +13,14 @@ void test (void) for (i = 0; i < 24; i++) for (j = 0; j < 24; j++) for (k = 0; k < 24; k++) - A[i][j] += B[i][k] * C[k][j]; + A[i][j] = B[i][k] * C[k][j]; /* These loops should still be strip mined. */ for (i = 0; i < 1000; i++) for (j = 0; j < 1000; j++) for (k = 0; k < 1000; k++) - A[i][j] += B[i][k] * C[k][j]; + A[i][j] = B[i][k] * C[k][j]; } -/* { dg-final { scan-tree-dump-times "Strip Mining is not profitable" 3 "graphite" } } */ +/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */ /* { dg-final { cleanup-tree-dump "graphite" } } */ diff --git a/gcc/testsuite/gfortran.dg/graphite/id-2.f90 b/gcc/testsuite/gfortran.dg/graphite/id-2.f90 new file mode 100644 index 00000000000..0c9f54bb979 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/id-2.f90 @@ -0,0 +1,15 @@ +! { dg-options "-O2 -fgraphite-identity" } + +module solv_cap + integer, parameter, public :: dp = selected_real_kind(5) +contains + subroutine prod0( G, X ) + real(kind=dp), intent(in out), dimension(:,:) :: X + real(kind=dp), dimension(size(X,1),size(X,2)) :: Y + X = Y + end subroutine prod0 + function Ginteg(xq1,yq1, xq2,yq2, xp,yp) result(G) + end function Ginteg + subroutine fourir(A,ntot,kconjg, E,useold) + end subroutine fourir +end module solv_cap diff --git a/gcc/testsuite/gfortran.dg/graphite/id-4.f90 b/gcc/testsuite/gfortran.dg/graphite/id-4.f90 new file mode 100644 index 00000000000..896d608777e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/id-4.f90 @@ -0,0 +1,34 @@ +! { dg-options "-O2 -fgraphite-identity" } + +MODULE Vcimage + CHARACTER (LEN=80), SAVE :: CARD, FIELD +END MODULE Vcimage +MODULE Vimage + LOGICAL, SAVE :: EOFF +END MODULE Vimage +SUBROUTINE READIN(PROB, TITLE, CSTOP, FCYCLE, DCYCLE, DHIST, VHIST& + & , IMAX, PHIST, DEBUG, NSTAT, STATS, MAXSTA, NCORE, PPLOT, & + & DPLOT, VPLOT, TPLOT, SLIST, D0, E0, NODES, SHEAT, GAMMA, COLD & + & , THIST, NVISC, SCREEN, WEIGHT, TSTOP, STABF) + USE Vcimage + USE Vimage + INTEGER, DIMENSION(MAXSTA) :: STATS + IF (.NOT.EOFF) THEN + IF (FIELD=='PROB' .OR. FIELD=='PROBLEM_NUMBER') THEN + CALL QSORT (STATS(1:NSTAT)) + WRITE (16, & + &'(//'' YOU HAVE REQUESTED A PRINTOUT OF THE STATION'', & + & '' ABORT''//)') + ENDIF + ENDIF +CONTAINS + RECURSIVE SUBROUTINE QSORT (LIST) + INTEGER, DIMENSION(:), INTENT(INOUT) :: LIST + INTEGER, DIMENSION(SIZE(LIST)) :: SMALLER,LARGER + IF (SIZE(LIST) > 1) THEN + LIST(NUMBER_SMALLER+1:NUMBER_SMALLER+NUMBER_EQUAL) = CHOSEN + CALL QSORT (LARGER(1:NUMBER_LARGER)) + LIST(NUMBER_SMALLER+NUMBER_EQUAL+1:) = LARGER(1:NUMBER_LARGER) + END IF + END SUBROUTINE QSORT +END SUBROUTINE READIN diff --git a/gcc/testsuite/gfortran.dg/graphite/pr37852.f90 b/gcc/testsuite/gfortran.dg/graphite/pr37852.f90 new file mode 100644 index 00000000000..50e23428f82 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/pr37852.f90 @@ -0,0 +1,13 @@ +! { dg-options "-O2 -floop-block" } + +PROGRAM TEST_FPU +CHARACTER (LEN=36) :: invert_id(1) = & + (/ 'Test1 - Gauss 2000 (101x101) inverts'/) +END PROGRAM TEST_FPU + +SUBROUTINE Gauss (a,n) +INTEGER, PARAMETER :: RK8 = SELECTED_REAL_KIND(15, 300) +REAL(RK8) :: a(n,n) +INTEGER :: ipvt(n) +a(:,ipvt) = b +END SUBROUTINE Gauss diff --git a/gcc/testsuite/gfortran.dg/graphite/pr37980.f90 b/gcc/testsuite/gfortran.dg/graphite/pr37980.f90 new file mode 100644 index 00000000000..5306aa84c92 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/pr37980.f90 @@ -0,0 +1,11 @@ +! { dg-options "-O2 -floop-block" } + +module INT_MODULE +contains + pure function spher_cartesians(in1) result(out1) + integer(kind=kind(1)) :: in1 + intent(in) :: in1 + real(kind=kind(1.0d0)), dimension(0:in1,0:in1,0:in1) :: mat0 + mat0 = 0.0d0 + end function spher_cartesians +end module INT_MODULE diff --git a/gcc/testsuite/gfortran.dg/graphite/pr38083.f90 b/gcc/testsuite/gfortran.dg/graphite/pr38083.f90 new file mode 100644 index 00000000000..834d33ab833 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/pr38083.f90 @@ -0,0 +1,16 @@ +! { dg-options "-O3 -floop-block" } + +SUBROUTINE IVSORT (IL,IH,NSEGS,IOUNIT) + INTEGER IOUNIT + + INTEGER, PARAMETER :: MAXGS = 32 + +10 IF (IL .GE. IH) GO TO 80 +20 NSEGS = (IH + IL) / 2 + IF (NSEGS .GT. MAXSGS) THEN + WRITE (IOUNIT),MAXSGS + ENDIF +80 NSEGS = NSEGS - 1 +90 IF (IH - IL .GE. 11) GO TO 20 +110 IF (IL .EQ. IH) GO TO 80 +END SUBROUTINE IVSORT diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 28ee8ef40c4..89621f0a80a 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -2072,14 +2072,9 @@ struct gimple_opt_pass pass_remove_useless_stmts = static void remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb) { - gimple_stmt_iterator gsi; - /* Since this block is no longer reachable, we can just delete all of its PHI nodes. */ - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); ) - remove_phi_node (&gsi, true); - - set_phi_nodes (bb, NULL); + remove_phi_nodes (bb); /* Remove edges to BB's successors. */ while (EDGE_COUNT (bb->succs) > 0) diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 6004978416b..d4e0004d834 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -787,6 +787,7 @@ extern gimple create_phi_node (tree, basic_block); extern void add_phi_arg (gimple, tree, edge); extern void remove_phi_args (edge); extern void remove_phi_node (gimple_stmt_iterator *, bool); +extern void remove_phi_nodes (basic_block); extern void init_phinodes (void); extern void fini_phinodes (void); extern void release_phi_node (gimple); @@ -988,6 +989,7 @@ unsigned int tree_ssa_prefetch_arrays (void); unsigned int remove_empty_loops (void); void tree_ssa_iv_optimize (void); unsigned tree_predictive_commoning (void); +tree canonicalize_loop_ivs (struct loop *, htab_t, tree); bool parallelize_loops (void); bool loop_only_exit_p (const struct loop *, const_edge); diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index d6e94b3c6a5..91ce890755f 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -1325,9 +1325,10 @@ create_loop_fn (void) /* Bases all the induction variables in LOOP on a single induction variable (unsigned with base 0 and step 1), whose final value is compared with NIT. The induction variable is incremented in the loop latch. - REDUCTION_LIST describes the reductions in LOOP. */ + REDUCTION_LIST describes the reductions in LOOP. Return the induction + variable that was created. */ -static void +tree canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit) { unsigned precision = TYPE_PRECISION (TREE_TYPE (nit)); @@ -1368,7 +1369,12 @@ canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit) } ok = simple_iv (loop, phi, res, &iv, true); - red = reduction_phi (reduction_list, phi); + + if (reduction_list) + red = reduction_phi (reduction_list, phi); + else + red = NULL; + /* We preserve the reduction phi nodes. */ if (!ok && red) { @@ -1406,6 +1412,9 @@ canonicalize_loop_ivs (struct loop *loop, htab_t reduction_list, tree nit) gimple_cond_set_code (stmt, LT_EXPR); gimple_cond_set_lhs (stmt, var_before); gimple_cond_set_rhs (stmt, nit); + update_stmt (stmt); + + return var_before; } /* Moves the exit condition of LOOP to the beginning of its header, and diff --git a/gcc/tree-phinodes.c b/gcc/tree-phinodes.c index 7fd5a8f30cc..fd6ac3a511b 100644 --- a/gcc/tree-phinodes.c +++ b/gcc/tree-phinodes.c @@ -474,4 +474,17 @@ remove_phi_node (gimple_stmt_iterator *gsi, bool release_lhs_p) release_ssa_name (gimple_phi_result (phi)); } +/* Remove all the phi nodes from BB. */ + +void +remove_phi_nodes (basic_block bb) +{ + gimple_stmt_iterator gsi; + + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); ) + remove_phi_node (&gsi, true); + + set_phi_nodes (bb, NULL); +} + #include "gt-tree-phinodes.h"