[tree-ssa] Improve removal of statements when removing blocks
law@redhat.com
law@redhat.com
Thu Jul 17 01:12:00 GMT 2003
When we delete a basic block, we (correctly) call bsi_remove on each
statement in the block to remove the statements.
bsi_remove has some code which removes the containing COMPOUND_EXPR
if we're removing it's 0th operand and its 1st operand is already
an empty statement.
That's all fine and good, except that when deleting a block we remove
statements from first to last. Meaning that it's exceedingly rare
that the 1st operand is already an empty statement when we call
bsi_remove on the 0th operand.
Believe it or not, this can cause the optimizers to miss optimization
opportunities. Consider 20030709-2.c which generates the following
gimple code:
get_alias_set (t)
{
struct rtx_def * T.1;
void * iftmp.2;
struct mem_attrs * T.3;
struct rtx_def * iftmp.4;
struct mem_attrs * T.5;
long int set;
extern make_decl_rtl;
T.1 = t->decl.rtl;
if (T.1 != 0B)
{
T.1 = t->decl.rtl;
T.3 = T.1->fld[1].rtmem;
if (T.3 == 0B)
{
T.1 = t->decl.rtl;
if (T.1 != 0B)
{
iftmp.4 = t->decl.rtl
}
else
{
make_decl_rtl (t, 0);
iftmp.4 = t->decl.rtl
};
T.5 = iftmp.4->fld[1].rtmem;
iftmp.2 = (void *)T.5
}
else
{
iftmp.2 = 0B
};
(void)0;
return iftmp.2;
}
else
{
(void)0
}
}
The dominator optimizations correctly determine that the second test of
T.1 != 0b is always true. That in turn causes the ELSE block to become
unreachable and we get the following code:
get_alias_set (t)
{
struct rtx_def * T.1;
void * iftmp.2;
struct mem_attrs * T.3;
struct rtx_def * iftmp.4;
struct mem_attrs * T.5;
long int set;
extern make_decl_rtl;
T.1_8 = t_6->decl.rtl;
if (T.1_8 != 0B)
{
T.1_9 = T.1_8;
T.3_10 = T.1_8->fld[1].rtmem;
if (T.3_10 == 0B)
{
T.1_11 = T.1_8;
if (1)
{
iftmp.4_12 = T.1_8
}
else
{
(void)0;
(void)0
};
T.5_15 = iftmp.4_1->fld[1].rtmem;
iftmp.2_16 = (void *)T.5_15
}
else
{
iftmp.2_17 = 0B
};
(void)0;
return iftmp.2_5;
}
else
{
(void)0
}
}
Unfortunately, the code which linearizes a COND_EXPR which is always
true requires an ELSE clause which is empty -- a COMPOUND_EXPR with
both operands being empty statements does not qualify as empty, nor does
a chain of COMPOUND_EXPRs where all the leafs are empty statements.
[ Similar problems occur for linearizing an COND_EXPR which is always
false -- we require the THEN arm to be empty. ]
Anyway, so we fail to linearize the COND_EXPR, which causes us to leave
a useless COND_EXPR in the IL.
Luckily the solution is pretty simple. When we're removing all the
statements in a basic block, remove them in reverse order. This
ensures that the 1st operand of a COMPOUND_EXPR is removed before
the 0th operand is removed. And thus when the 0th operand is removed
we recognize that the entire COMPOUND_EXPR can be removed. Resulting
in the following code:
get_alias_set (t)
{
struct rtx_def * T.1;
void * iftmp.2;
struct mem_attrs * T.3;
struct rtx_def * iftmp.4;
struct mem_attrs * T.5;
long int set;
extern make_decl_rtl;
T.1_8 = t_6->decl.rtl;
if (T.1_8 != 0B)
{
T.1_9 = T.1_8;
T.3_10 = T.1_8->fld[1].rtmem;
if (T.3_10 == 0B)
{
T.1_11 = T.1_8;
iftmp.4_12 = T.1_8;
T.5_15 = iftmp.4_1->fld[1].rtmem;
iftmp.2_16 = (void *)T.5_15
}
else
{
iftmp.2_17 = 0B
};
(void)0;
return iftmp.2_5;
}
else
{
(void)0
}
}
Note this is still not fully optimized -- once we start optimizing
PHIs with a single argument we'll realize that the second load of
fld[1].rtmem is redundant. Even so this is still an improvement
and fixes one of the failures in the recently added tree-ssa tests.
This also happens to slightly simplify the logic in remove_bb to deal
with warnings for unreachable code.
Bootstrapped, regression tested. Whee.
* tree-cfg.c (remove_bb): Remove statements in reverse order.
Simplify code to issue warnings for unreachable code.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.128
diff -c -3 -p -r1.1.4.128 tree-cfg.c
*** tree-cfg.c 15 Jul 2003 23:56:23 -0000 1.1.4.128
--- tree-cfg.c 17 Jul 2003 01:10:37 -0000
*************** static void
*** 1777,1783 ****
remove_bb (basic_block bb, int remove_stmts)
{
block_stmt_iterator i;
! int already_warned;
dump_file = dump_begin (TDI_cfg, &dump_flags);
if (dump_file)
--- 1777,1784 ----
remove_bb (basic_block bb, int remove_stmts)
{
block_stmt_iterator i;
! bsi_list_p stack;
! location_t loc;
dump_file = dump_begin (TDI_cfg, &dump_flags);
if (dump_file)
*************** remove_bb (basic_block bb, int remove_st
*** 1789,1816 ****
dump_file = NULL;
}
! /* Remove all the instructions in the block. */
! already_warned = 0;
! for (i = bsi_start (bb); !bsi_end_p (i); )
{
tree stmt = bsi_stmt (i);
set_bb_for_stmt (stmt, NULL);
if (remove_stmts)
{
! if (! already_warned && warn_notreached)
! {
! location_t loc;
! loc.file = get_filename (stmt);
! loc.line = get_lineno (stmt);
! warning ("%Hwill never be executed", &loc);
! already_warned = 1;
! }
bsi_remove (&i);
}
else
! bsi_next (&i);
}
if (bb->head_tree_p)
set_bb_for_stmt (*bb->head_tree_p, NULL);
--- 1790,1818 ----
dump_file = NULL;
}
! /* Remove all the instructions in the block. Do so in reverse order
! so that we remove all the containing COMPOUND_EXPRs as well. */
! FOR_EACH_BSI_IN_REVERSE (stack, bb, i)
{
tree stmt = bsi_stmt (i);
set_bb_for_stmt (stmt, NULL);
if (remove_stmts)
{
! loc.file = get_filename (stmt);
! loc.line = get_lineno (stmt);
bsi_remove (&i);
}
else
! bsi_next (&i);
}
+
+ /* If requested, give a warning that the first statement in the
+ block is unreachable. We walk statements backwards in the
+ loop above, so the last statement we process is the first statement
+ in the block. */
+ if (remove_stmts && warn_notreached)
+ warning ("%Hwill never be executed", &loc);
if (bb->head_tree_p)
set_bb_for_stmt (*bb->head_tree_p, NULL);
More information about the Gcc-patches
mailing list