* tree-cfgcleanup. (cleanup_control_expr_graph) <GIMPLE_COND>: Remove
code doing propagation from degenerate PHI nodes. * tree-ssa-loop-ivcanon.c (propagate_into_all_uses): New function. (propagate_constants_for_unrolling): Likewise. (tree_unroll_loops_completely): If the current loop has been unrolled and its father isn't the entire function, propagate constants within the new basic blocks by means of propagate_constants_for_unrolling. From-SVN: r191387
This commit is contained in:
parent
9bf714c23f
commit
fea4ea737f
@ -1,3 +1,13 @@
|
||||
2012-09-17 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* tree-cfgcleanup. (cleanup_control_expr_graph) <GIMPLE_COND>: Remove
|
||||
code doing propagation from degenerate PHI nodes.
|
||||
* tree-ssa-loop-ivcanon.c (propagate_into_all_uses): New function.
|
||||
(propagate_constants_for_unrolling): Likewise.
|
||||
(tree_unroll_loops_completely): If the current loop has been unrolled
|
||||
and its father isn't the entire function, propagate constants within
|
||||
the new basic blocks by means of propagate_constants_for_unrolling.
|
||||
|
||||
2012-09-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/54563
|
||||
|
@ -1,3 +1,7 @@
|
||||
2012-09-17 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* gnat.dg/loop_optimization12.ad[sb]: New test.
|
||||
|
||||
2012-09-17 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/54285
|
||||
|
22
gcc/testsuite/gnat.dg/loop_optimization12.adb
Normal file
22
gcc/testsuite/gnat.dg/loop_optimization12.adb
Normal file
@ -0,0 +1,22 @@
|
||||
-- { dg-do compile }
|
||||
-- { dg-options "-O2" }
|
||||
|
||||
package body Loop_Optimization12 is
|
||||
|
||||
procedure Reset (S : Rec_Ptr) is
|
||||
begin
|
||||
for I in Enum1 loop
|
||||
S.F (I).all := (others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others =>
|
||||
(others => 0))))))))));
|
||||
end loop;
|
||||
end;
|
||||
|
||||
end Loop_Optimization12;
|
27
gcc/testsuite/gnat.dg/loop_optimization12.ads
Normal file
27
gcc/testsuite/gnat.dg/loop_optimization12.ads
Normal file
@ -0,0 +1,27 @@
|
||||
package Loop_Optimization12 is
|
||||
|
||||
type Enum1 is (A, B, C, D, E, F, G, H, I, J);
|
||||
|
||||
type Enum2 is (A, B, C);
|
||||
|
||||
type Enum3 is (A, B, C, D, E, F);
|
||||
|
||||
type Enum4 is (A, B, C, D);
|
||||
|
||||
type Enum5 is (A, B, C, D, E);
|
||||
|
||||
type Arr is array (Enum3, Enum4, Enum4, Enum5, Enum5, Enum3,
|
||||
Enum2, Enum3, Enum5, Enum3) of Natural;
|
||||
|
||||
type Arr_Ptr is access Arr;
|
||||
type Ext_Arr is array (Enum1) of Arr_Ptr;
|
||||
|
||||
type Rec is record
|
||||
F : Ext_Arr;
|
||||
end record;
|
||||
|
||||
type Rec_Ptr is access Rec;
|
||||
|
||||
procedure Reset (S : Rec_Ptr);
|
||||
|
||||
end Loop_Optimization12;
|
@ -88,40 +88,11 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi)
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
case GIMPLE_COND:
|
||||
{
|
||||
tree lhs = gimple_cond_lhs (stmt);
|
||||
tree rhs = gimple_cond_rhs (stmt);
|
||||
/* For conditions try harder and lookup single-argument
|
||||
PHI nodes. Only do so from the same basic-block though
|
||||
as other basic-blocks may be dead already. */
|
||||
if (TREE_CODE (lhs) == SSA_NAME
|
||||
&& !name_registered_for_update_p (lhs))
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (lhs);
|
||||
if (gimple_code (def_stmt) == GIMPLE_PHI
|
||||
&& gimple_phi_num_args (def_stmt) == 1
|
||||
&& gimple_bb (def_stmt) == gimple_bb (stmt)
|
||||
&& (TREE_CODE (PHI_ARG_DEF (def_stmt, 0)) != SSA_NAME
|
||||
|| !name_registered_for_update_p (PHI_ARG_DEF (def_stmt,
|
||||
0))))
|
||||
lhs = PHI_ARG_DEF (def_stmt, 0);
|
||||
}
|
||||
if (TREE_CODE (rhs) == SSA_NAME
|
||||
&& !name_registered_for_update_p (rhs))
|
||||
{
|
||||
gimple def_stmt = SSA_NAME_DEF_STMT (rhs);
|
||||
if (gimple_code (def_stmt) == GIMPLE_PHI
|
||||
&& gimple_phi_num_args (def_stmt) == 1
|
||||
&& gimple_bb (def_stmt) == gimple_bb (stmt)
|
||||
&& (TREE_CODE (PHI_ARG_DEF (def_stmt, 0)) != SSA_NAME
|
||||
|| !name_registered_for_update_p (PHI_ARG_DEF (def_stmt,
|
||||
0))))
|
||||
rhs = PHI_ARG_DEF (def_stmt, 0);
|
||||
}
|
||||
val = fold_binary_loc (loc, gimple_cond_code (stmt),
|
||||
boolean_type_node, lhs, rhs);
|
||||
break;
|
||||
}
|
||||
val = fold_binary_loc (loc, gimple_cond_code (stmt),
|
||||
boolean_type_node,
|
||||
gimple_cond_lhs (stmt),
|
||||
gimple_cond_rhs (stmt));
|
||||
break;
|
||||
|
||||
case GIMPLE_SWITCH:
|
||||
val = gimple_switch_index (stmt);
|
||||
|
@ -503,6 +503,80 @@ canonicalize_induction_variables (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Propagate VAL into all uses of SSA_NAME. */
|
||||
|
||||
static void
|
||||
propagate_into_all_uses (tree ssa_name, tree val)
|
||||
{
|
||||
imm_use_iterator iter;
|
||||
gimple use_stmt;
|
||||
|
||||
FOR_EACH_IMM_USE_STMT (use_stmt, iter, ssa_name)
|
||||
{
|
||||
gimple_stmt_iterator use_stmt_gsi = gsi_for_stmt (use_stmt);
|
||||
use_operand_p use;
|
||||
|
||||
FOR_EACH_IMM_USE_ON_STMT (use, iter)
|
||||
SET_USE (use, val);
|
||||
|
||||
if (is_gimple_assign (use_stmt)
|
||||
&& get_gimple_rhs_class (gimple_assign_rhs_code (use_stmt))
|
||||
== GIMPLE_SINGLE_RHS)
|
||||
{
|
||||
tree rhs = gimple_assign_rhs1 (use_stmt);
|
||||
|
||||
if (TREE_CODE (rhs) == ADDR_EXPR)
|
||||
recompute_tree_invariant_for_addr_expr (rhs);
|
||||
}
|
||||
|
||||
fold_stmt_inplace (&use_stmt_gsi);
|
||||
update_stmt (use_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Propagate constant SSA_NAMEs defined in basic block BB. */
|
||||
|
||||
static void
|
||||
propagate_constants_for_unrolling (basic_block bb)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
|
||||
/* Look for degenerate PHI nodes with constant argument. */
|
||||
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
|
||||
{
|
||||
gimple phi = gsi_stmt (gsi);
|
||||
tree result = gimple_phi_result (phi);
|
||||
tree arg = gimple_phi_arg_def (phi, 0);
|
||||
|
||||
if (gimple_phi_num_args (phi) == 1 && TREE_CODE (arg) == INTEGER_CST)
|
||||
{
|
||||
propagate_into_all_uses (result, arg);
|
||||
gsi_remove (&gsi, true);
|
||||
release_ssa_name (result);
|
||||
}
|
||||
else
|
||||
gsi_next (&gsi);
|
||||
}
|
||||
|
||||
/* Look for assignments to SSA names with constant RHS. */
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
|
||||
{
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
tree lhs;
|
||||
|
||||
if (is_gimple_assign (stmt)
|
||||
&& (lhs = gimple_assign_lhs (stmt), TREE_CODE (lhs) == SSA_NAME)
|
||||
&& gimple_assign_rhs_code (stmt) == INTEGER_CST)
|
||||
{
|
||||
propagate_into_all_uses (lhs, gimple_assign_rhs1 (stmt));
|
||||
gsi_remove (&gsi, true);
|
||||
release_ssa_name (lhs);
|
||||
}
|
||||
else
|
||||
gsi_next (&gsi);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unroll LOOPS completely if they iterate just few times. Unless
|
||||
MAY_INCREASE_SIZE is true, perform the unrolling only if the
|
||||
size of the code does not increase. */
|
||||
@ -510,6 +584,7 @@ canonicalize_induction_variables (void)
|
||||
unsigned int
|
||||
tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
||||
{
|
||||
VEC(loop_p,stack) *father_stack = VEC_alloc (loop_p, stack, 16);
|
||||
loop_iterator li;
|
||||
struct loop *loop;
|
||||
bool changed;
|
||||
@ -522,22 +597,51 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
||||
|
||||
FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
|
||||
{
|
||||
struct loop *loop_father = loop_outer (loop);
|
||||
|
||||
if (may_increase_size && optimize_loop_for_speed_p (loop)
|
||||
/* Unroll outermost loops only if asked to do so or they do
|
||||
not cause code growth. */
|
||||
&& (unroll_outer
|
||||
|| loop_outer (loop_outer (loop))))
|
||||
&& (unroll_outer || loop_outer (loop_father)))
|
||||
ul = UL_ALL;
|
||||
else
|
||||
ul = UL_NO_GROWTH;
|
||||
changed |= canonicalize_loop_induction_variables
|
||||
(loop, false, ul, !flag_tree_loop_ivcanon);
|
||||
|
||||
if (canonicalize_loop_induction_variables (loop, false, ul,
|
||||
!flag_tree_loop_ivcanon))
|
||||
{
|
||||
changed = true;
|
||||
/* If we'll continue unrolling, we need to propagate constants
|
||||
within the new basic blocks to fold away induction variable
|
||||
computations; otherwise, the size might blow up before the
|
||||
iteration is complete and the IR eventually cleaned up. */
|
||||
if (loop_outer (loop_father) && !loop_father->aux)
|
||||
{
|
||||
VEC_safe_push (loop_p, stack, father_stack, loop_father);
|
||||
loop_father->aux = loop_father;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
struct loop **iter;
|
||||
unsigned i;
|
||||
|
||||
update_ssa (TODO_update_ssa);
|
||||
|
||||
/* Propagate the constants within the new basic blocks. */
|
||||
FOR_EACH_VEC_ELT (loop_p, father_stack, i, iter)
|
||||
{
|
||||
unsigned j;
|
||||
basic_block *body = get_loop_body_in_dom_order (*iter);
|
||||
for (j = 0; j < (*iter)->num_nodes; j++)
|
||||
propagate_constants_for_unrolling (body[j]);
|
||||
free (body);
|
||||
(*iter)->aux = NULL;
|
||||
}
|
||||
VEC_truncate (loop_p, father_stack, 0);
|
||||
|
||||
/* This will take care of removing completely unrolled loops
|
||||
from the loop structures so we can continue unrolling now
|
||||
innermost loops. */
|
||||
@ -552,5 +656,7 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
|
||||
while (changed
|
||||
&& ++iteration <= PARAM_VALUE (PARAM_MAX_UNROLL_ITERATIONS));
|
||||
|
||||
VEC_free (loop_p, stack, father_stack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user