This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Fix ICE with dangling abnormal call edges
- From: Eric Botcazou <ebotcazou at adacore dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 17 Oct 2010 23:00:10 +0200
- Subject: [patch] Fix ICE with dangling abnormal call edges
Hi,
bootstrapping the Ada compiler with -gnatn (inlining enabled) yields an ICE
during CDDCE. I've attached a reduced testcase, but it needs to be compiled
within the build tree as the problem is related to __builtin_setjmp/longjmp.
The sequence of events is as follows: FRE replaces
D.3227_33 = sinfo.entity (pref_1(ab));
[...]
<bb 25>:
if (D.3228_35 == 2)
goto <bb 26>;
else
goto <bb 30>;
<bb 26>:
D.3231_37 = sinfo.entity (pref_1(ab));
[...]
<bb 30>:
D.3235_43 = sinfo.entity (pref_1(ab));
with
<bb 25>:
if (D.3228_35 == 2)
goto <bb 26>;
else
goto <bb 30>;
<bb 26>:
D.3231_37 = D.3227_33;
[...]
<bb 30>:
D.3235_43 = D.3227_33;
leaving dangling outgoing abnormal edges in BB 26 and BB 30.
Later DCE removes the assignments:
<bb 23>:
if (D.3228_35 == 2)
goto <bb 24>;
else
goto <bb 28>;
<bb 24>:
[...]
<bb 28>:
leaving dangling empty BB 24 and 28, which confuses the CDDCE pass:
Eliminating unnecessary statements:
Deleting : if (D.3228_35 == 2)
as the statement isn't dead at all.
Fixed by purging the dead abnormal call edges at the end of PRE, similarly to
what is done for dead EH edges. I took this opportunity to clean up the
existing gimple_purge_dead_abnormal_call_edges, as EH edges aren't abnormal
edges any longer.
Bootstrapped/regtested on i586-suse-linux, OK for mainline?
2010-10-17 Eric Botcazou <ebotcazou@adacore.com>
* tree-flow.h (gimple_purge_all_dead_abnormal_call_edges): Declare.
* tree-cfg.c (gimple_purge_dead_abnormal_call_edges): Move around.
Rewrite modelled on gimple_purge_dead_eh_edges.
(gimple_purge_all_dead_abnormal_call_edges): New function.
* tree-inline.c (expand_call_inline): Call gimple_purge_dead_eh_edges
directly instead of through gimple_purge_dead_abnormal_call_edges.
* tree-ssa-pre.c (need_ab_cleanup): New static variable.
(eliminate): Set bit in need_ab_cleanup for the basic block if we
removed AB side-effects from one of its statements.
(init_pre): Initialize need_ab_cleanup.
(fini_pre): Purge dead abnormal call edges and clean up the CFG if
some bits are set in need_ab_cleanup. Free need_ab_cleanup.
--
Eric Botcazou
Index: tree-flow.h
===================================================================
--- tree-flow.h (revision 165574)
+++ tree-flow.h (working copy)
@@ -450,9 +450,10 @@ extern void gather_blocks_in_sese_region
VEC(basic_block,heap) **bbs_p);
extern void add_phi_args_after_copy_bb (basic_block);
extern void add_phi_args_after_copy (basic_block *, unsigned, edge);
-extern bool gimple_purge_dead_abnormal_call_edges (basic_block);
extern bool gimple_purge_dead_eh_edges (basic_block);
extern bool gimple_purge_all_dead_eh_edges (const_bitmap);
+extern bool gimple_purge_dead_abnormal_call_edges (basic_block);
+extern bool gimple_purge_all_dead_abnormal_call_edges (const_bitmap);
extern tree gimplify_build1 (gimple_stmt_iterator *, enum tree_code,
tree, tree);
extern tree gimplify_build2 (gimple_stmt_iterator *, enum tree_code,
Index: tree-cfg.c
===================================================================
--- tree-cfg.c (revision 165574)
+++ tree-cfg.c (working copy)
@@ -6824,39 +6824,6 @@ gimple_flow_call_edges_add (sbitmap bloc
return blocks_split;
}
-/* Purge dead abnormal call edges from basic block BB. */
-
-bool
-gimple_purge_dead_abnormal_call_edges (basic_block bb)
-{
- bool changed = gimple_purge_dead_eh_edges (bb);
-
- if (cfun->has_nonlocal_label)
- {
- gimple stmt = last_stmt (bb);
- edge_iterator ei;
- edge e;
-
- if (!(stmt && stmt_can_make_abnormal_goto (stmt)))
- for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
- {
- if (e->flags & EDGE_ABNORMAL)
- {
- remove_edge (e);
- changed = true;
- }
- else
- ei_next (&ei);
- }
-
- /* See gimple_purge_dead_eh_edges below. */
- if (changed)
- free_dominance_info (CDI_DOMINATORS);
- }
-
- return changed;
-}
-
/* Removes edge E and all the blocks dominated by it, and updates dominance
information. The IL in E->src needs to be updated separately.
If dominance info is not available, only the edge E is removed.*/
@@ -7010,6 +6977,8 @@ gimple_purge_dead_eh_edges (basic_block
return changed;
}
+/* Purge dead EH edges from basic block listed in BLOCKS. */
+
bool
gimple_purge_all_dead_eh_edges (const_bitmap blocks)
{
@@ -7029,6 +6998,59 @@ gimple_purge_all_dead_eh_edges (const_bi
}
return changed;
+}
+
+/* Purge dead abnormal call edges from basic block BB. */
+
+bool
+gimple_purge_dead_abnormal_call_edges (basic_block bb)
+{
+ bool changed = false;
+ edge e;
+ edge_iterator ei;
+ gimple stmt = last_stmt (bb);
+
+ if (!cfun->has_nonlocal_label)
+ return false;
+
+ if (stmt && stmt_can_make_abnormal_goto (stmt))
+ return false;
+
+ for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+ {
+ if (e->flags & EDGE_ABNORMAL)
+ {
+ remove_edge_and_dominated_blocks (e);
+ changed = true;
+ }
+ else
+ ei_next (&ei);
+ }
+
+ return changed;
+}
+
+/* Purge dead abnormal call edges from basic block listed in BLOCKS. */
+
+bool
+gimple_purge_all_dead_abnormal_call_edges (const_bitmap blocks)
+{
+ bool changed = false;
+ unsigned i;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+ {
+ basic_block bb = BASIC_BLOCK (i);
+
+ /* Earlier gimple_purge_dead_abnormal_call_edges could have removed
+ this basic block already. */
+ gcc_assert (bb || changed);
+ if (bb != NULL)
+ changed |= gimple_purge_dead_abnormal_call_edges (bb);
+ }
+
+ return changed;
}
/* This function is called whenever a new edge is created or
Index: tree-inline.c
===================================================================
--- tree-inline.c (revision 165574)
+++ tree-inline.c (working copy)
@@ -4010,7 +4010,10 @@ expand_call_inline (basic_block bb, gimp
}
if (purge_dead_abnormal_edges)
- gimple_purge_dead_abnormal_call_edges (return_block);
+ {
+ gimple_purge_dead_eh_edges (return_block);
+ gimple_purge_dead_abnormal_call_edges (return_block);
+ }
/* If the value of the new expression is ignored, that's OK. We
don't warn about this for CALL_EXPRs, so we shouldn't warn about
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c (revision 165574)
+++ tree-ssa-pre.c (working copy)
@@ -484,10 +484,12 @@ static tree pretemp;
static tree storetemp;
static tree prephitemp;
-/* Set of blocks with statements that have had its EH information
- cleaned up. */
+/* Set of blocks with statements that have had their EH properties changed. */
static bitmap need_eh_cleanup;
+/* Set of blocks with statements that have had their AB properties changed. */
+static bitmap need_ab_cleanup;
+
/* The phi_translate_table caches phi translations for a given
expression and predecessor. */
@@ -4253,6 +4255,9 @@ eliminate (void)
|| TREE_CODE (rhs) != SSA_NAME
|| may_propagate_copy (rhs, sprime)))
{
+ bool can_make_abnormal_goto
+ = is_gimple_call (stmt)
+ && stmt_can_make_abnormal_goto (stmt);
gcc_assert (sprime != rhs);
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -4281,14 +4286,24 @@ eliminate (void)
stmt = gsi_stmt (gsi);
update_stmt (stmt);
- /* If we removed EH side effects from the statement, clean
+ /* If we removed EH side-effects from the statement, clean
its EH information. */
if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
{
bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Removed EH side effects.\n");
+ fprintf (dump_file, " Removed EH side-effects.\n");
+ }
+
+ /* Likewise for AB side-effects. */
+ if (can_make_abnormal_goto
+ && !stmt_can_make_abnormal_goto (stmt))
+ {
+ bitmap_set_bit (need_ab_cleanup,
+ gimple_bb (stmt)->index);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " Removed AB side-effects.\n");
}
}
}
@@ -4746,6 +4761,7 @@ init_pre (bool do_fre)
}
need_eh_cleanup = BITMAP_ALLOC (NULL);
+ need_ab_cleanup = BITMAP_ALLOC (NULL);
}
@@ -4777,6 +4793,14 @@ fini_pre (bool do_fre)
BITMAP_FREE (need_eh_cleanup);
+ if (!bitmap_empty_p (need_ab_cleanup))
+ {
+ gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup);
+ cleanup_tree_cfg ();
+ }
+
+ BITMAP_FREE (need_ab_cleanup);
+
if (!do_fre)
loop_optimizer_finalize ();
}
with Atree; use Atree;
with Einfo; use Einfo;
with Sinfo; use Sinfo;
with Q; use Q;
package body P is
procedure Expand_N_Attribute_Reference (N : Node_Id) is
Pref : constant Node_Id := My_Prefix (N);
begin
if Is_Protected_Self_Reference (Pref) then
Analyze (Pref);
end if;
case Get_Attribute_Id (N) is
when One =>
if Is_Non_Empty_List (My_Expressions (N)) then
Rewrite (N,
Make_Integer_Literal (No_Location,
Enumeration_Rep (Entity (Pref))));
elsif Ekind (Entity (Pref)) = E_Constant then
Rewrite (N,
Make_Integer_Literal (No_Location,
Enumeration_Rep (Entity (Pref))));
else
Rewrite (N,
Make_Integer_Literal (No_Location,
Enumeration_Rep (Entity (Pref))));
end if;
when Two => Rewrite (N, Pref);
when Three => Rewrite (N, Pref);
when others => null;
end case;
exception
when Program_Error => return;
end;
end P;
with Types; use Types;
with Uintp; use Uintp;
package Q is
function Is_Protected_Self_Reference (N : Node_Id) return Boolean;
procedure Analyze (N : Node_Id);
function Make_Integer_Literal
(Loc : Source_Ptr; Intval : Uint) return Node_Id;
function Is_Non_Empty_List (List : List_Id) return Boolean;
type Attribute_Id is (One, Two, Three, Four);
function Get_Attribute_Id (N : Node_Id) return Attribute_Id;
function My_Expressions (N : Node_Id) return List_Id;
function My_Prefix (N : Node_Id) return Node_Id;
end Q;
with Types; use Types;
package P is
procedure Expand_N_Attribute_Reference (N : Node_Id);
end P;