diff mbox

[RFC] Fix PR79432, SSA from the gimplifier and abnormal edges

Message ID alpine.LSU.2.20.1702101310510.6076@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Feb. 10, 2017, 12:24 p.m. UTC
It turns out the SSA var defs/uses generated by the gimplifier can break 
apart in a way no longer satisfying the dominance requirement of SSA
uses vs. their defs by means of CFG construction adding abnormal edges
for stuff like setjmp (but also non-local gotos I guess).

This would be quite costly to overcome in gimplification - one needs
to check whether a (part?) of an expression to be gimplified may
produce such edges and disable SSA name generation for them.  With
the recursive nature of the gimplifier plus the general complexity
of GENERIC I can't see how to do this.

Thus the following patch "recovers" from the extra abnormal edges
by effectively treating SSA vars pre into-SSA as "non-SSA" and thus
doing PHI insertion for them when rewriting the function into SSA.
Implementation-wise the easiest thing was to re-write the affected
SSA vars out-of-SSA (replace them by a decl).

The out-of-SSA rewriting is placed in insert_phi_nodes because thats
the first point in time we have immediate uses present (otherwise
it could be done at any point after CFG construction).

I'm not 100% happy with this but after trying for a day I can't come
up with a better solution - it has the chance of papering over
bogus gimplifications but OTOH that we only do this for functions
calling setjmp or having non-local labels would make those trigger
SSA verification in the other cases.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

Any comments / ideas?  Anyone with good arguments that this is
even conceptually the correct thing to do?

I'm bootstrapping this with the calls_setjmp/has_nonlocal_label
short-cutted with a 1 || as well as without (to increase testing
coverage).

Thanks,
Richard.

2017-02-10  Richard Biener  <rguenther@suse.de>

	PR middle-end/79432
	* tree-into-ssa.c (insert_phi_nodes): When the function can
	have abnormal edges rewrite SSA names with broken use-def
	dominance out of SSA and register them for PHI insertion.

	* gcc.dg/torture/pr79432.c: New testcase.

Comments

Jeff Law Feb. 13, 2017, 11:15 p.m. UTC | #1
On 02/10/2017 05:24 AM, Richard Biener wrote:
>
> It turns out the SSA var defs/uses generated by the gimplifier can break
> apart in a way no longer satisfying the dominance requirement of SSA
> uses vs. their defs by means of CFG construction adding abnormal edges
> for stuff like setjmp (but also non-local gotos I guess).
>
> This would be quite costly to overcome in gimplification - one needs
> to check whether a (part?) of an expression to be gimplified may
> produce such edges and disable SSA name generation for them.  With
> the recursive nature of the gimplifier plus the general complexity
> of GENERIC I can't see how to do this.
ISTM there is no apriori way to know if any object is live across a call 
which would create these abnormal edges.  How in the world did this work 
in the past?

Sigh.  Because the problem starts at gimplification, we can't even do 
something like pre-scan the block for problem calls -- we don't have a CFG.

Can this only happen during gimplification of an expression where a 
sub-expression has a problematic call?  How bad do you think things 
would blow up if we scanned for a call and avoided using SSA_NAMEs when 
there's a problematical call within the expression?  Or is there no way 
structurally to do that within the gimplifier?

Are setjmp/longjump the only problems here, or does EH tickle these 
issues as well (if so, then ISTM you'd need a different test).

>
> Thus the following patch "recovers" from the extra abnormal edges
> by effectively treating SSA vars pre into-SSA as "non-SSA" and thus
> doing PHI insertion for them when rewriting the function into SSA.
> Implementation-wise the easiest thing was to re-write the affected
> SSA vars out-of-SSA (replace them by a decl).
If we can't do the right thing from the start, then "recovery" seems to 
be the only option.


>
> The out-of-SSA rewriting is placed in insert_phi_nodes because thats
> the first point in time we have immediate uses present (otherwise
> it could be done at any point after CFG construction).
THe earlier the better.  So as soon as we have a CFG & SSA we have to 
fixup.  So location seems right.

>
> I'm not 100% happy with this but after trying for a day I can't come
> up with a better solution - it has the chance of papering over
> bogus gimplifications but OTOH that we only do this for functions
> calling setjmp or having non-local labels would make those trigger
> SSA verification in the other cases.
>
> Bootstrap and regtest running on x86_64-unknown-linux-gnu.
>
> Any comments / ideas?  Anyone with good arguments that this is
> even conceptually the correct thing to do?
>
> I'm bootstrapping this with the calls_setjmp/has_nonlocal_label
> short-cutted with a 1 || as well as without (to increase testing
> coverage).
>
> Thanks,
> Richard.
>
> 2017-02-10  Richard Biener  <rguenther@suse.de>
>
> 	PR middle-end/79432
> 	* tree-into-ssa.c (insert_phi_nodes): When the function can
> 	have abnormal edges rewrite SSA names with broken use-def
> 	dominance out of SSA and register them for PHI insertion.
>
> 	* gcc.dg/torture/pr79432.c: New testcase.
It's gross.  But unless we have a reasonable way to do this during 
gimplification, I don't see anything better.

jeff
Richard Biener Feb. 14, 2017, 7:55 a.m. UTC | #2
On Mon, 13 Feb 2017, Jeff Law wrote:

> On 02/10/2017 05:24 AM, Richard Biener wrote:
> > 
> > It turns out the SSA var defs/uses generated by the gimplifier can break
> > apart in a way no longer satisfying the dominance requirement of SSA
> > uses vs. their defs by means of CFG construction adding abnormal edges
> > for stuff like setjmp (but also non-local gotos I guess).
> > 
> > This would be quite costly to overcome in gimplification - one needs
> > to check whether a (part?) of an expression to be gimplified may
> > produce such edges and disable SSA name generation for them.  With
> > the recursive nature of the gimplifier plus the general complexity
> > of GENERIC I can't see how to do this.
> ISTM there is no apriori way to know if any object is live across a call which
> would create these abnormal edges.  How in the world did this work in the
> past?

It worked in the past because we didn't use SSA names for temporaries in
the gimplifiers and regular decls just got effectively uninitialized
uses across such edges (by into-SSA and PHI insertion, exactly how I
fix this "after the fact")

> Sigh.  Because the problem starts at gimplification, we can't even do
> something like pre-scan the block for problem calls -- we don't have a CFG.
> 
> Can this only happen during gimplification of an expression where a
> sub-expression has a problematic call?  How bad do you think things would blow
> up if we scanned for a call and avoided using SSA_NAMEs when there's a
> problematical call within the expression?  Or is there no way structurally to
> do that within the gimplifier?

Well, the only thing I could imagine is doing walk_tree on all GENERIC
where it matters (all?).

> Are setjmp/longjump the only problems here, or does EH tickle these issues as
> well (if so, then ISTM you'd need a different test).

The only issue is when CFG construction adds backedges which only happens
for abnormals.  Only backedges can make uses no longer dominate defs.

> > 
> > Thus the following patch "recovers" from the extra abnormal edges
> > by effectively treating SSA vars pre into-SSA as "non-SSA" and thus
> > doing PHI insertion for them when rewriting the function into SSA.
> > Implementation-wise the easiest thing was to re-write the affected
> > SSA vars out-of-SSA (replace them by a decl).
> If we can't do the right thing from the start, then "recovery" seems to be the
> only option.

I think it's a question of cost and maintainability.  It for sure must
be possible to fix this in the gimplifier but I think the costs are too 
high.

> 
> > 
> > The out-of-SSA rewriting is placed in insert_phi_nodes because thats
> > the first point in time we have immediate uses present (otherwise
> > it could be done at any point after CFG construction).
> THe earlier the better.  So as soon as we have a CFG & SSA we have to fixup.
> So location seems right.

Yeah, if we'd have immediate uses at CFG construction then I'd fix it
at the time we introduce those abnormal edges.  For GCC 8 we might want
to consider this (building SSA operands earlier).

> > 
> > I'm not 100% happy with this but after trying for a day I can't come
> > up with a better solution - it has the chance of papering over
> > bogus gimplifications but OTOH that we only do this for functions
> > calling setjmp or having non-local labels would make those trigger
> > SSA verification in the other cases.
> > 
> > Bootstrap and regtest running on x86_64-unknown-linux-gnu.
> > 
> > Any comments / ideas?  Anyone with good arguments that this is
> > even conceptually the correct thing to do?
> > 
> > I'm bootstrapping this with the calls_setjmp/has_nonlocal_label
> > short-cutted with a 1 || as well as without (to increase testing
> > coverage).
> > 
> > Thanks,
> > Richard.
> > 
> > 2017-02-10  Richard Biener  <rguenther@suse.de>
> > 
> > 	PR middle-end/79432
> > 	* tree-into-ssa.c (insert_phi_nodes): When the function can
> > 	have abnormal edges rewrite SSA names with broken use-def
> > 	dominance out of SSA and register them for PHI insertion.
> > 
> > 	* gcc.dg/torture/pr79432.c: New testcase.
> It's gross.  But unless we have a reasonable way to do this during
> gimplification, I don't see anything better.

Ok.  I've applied the patch for now.  If anybody comes up with a cheap
enough idea to cover these in the gimplifier we can reconsider.

Richard.

> jeff
> 
>
diff mbox

Patch

Index: gcc/tree-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c	(revision 245323)
+++ gcc/tree-into-ssa.c	(working copy)
@@ -1066,6 +1066,59 @@  insert_phi_nodes (bitmap_head *dfs)
 
   timevar_push (TV_TREE_INSERT_PHI_NODES);
 
+  /* When the gimplifier introduces SSA names it cannot easily avoid
+     situations where abnormal edges added by CFG construction break
+     the use-def dominance requirement.  For this case rewrite SSA
+     names with broken use-def dominance out-of-SSA and register them
+     for PHI insertion.  We only need to do this if abnormal edges
+     can appear in the function.  */
+  tree name;
+  if (cfun->calls_setjmp
+      || cfun->has_nonlocal_label)
+    FOR_EACH_SSA_NAME (i, name, cfun)
+      {
+	gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+	if (SSA_NAME_IS_DEFAULT_DEF (name))
+	  continue;
+
+	basic_block def_bb = gimple_bb (def_stmt);
+	imm_use_iterator it;
+	gimple *use_stmt;
+	bool need_phis = false;
+	FOR_EACH_IMM_USE_STMT (use_stmt, it, name)
+	  {
+	    basic_block use_bb = gimple_bb (use_stmt);
+	    if (use_bb != def_bb
+		&& ! dominated_by_p (CDI_DOMINATORS, use_bb, def_bb))
+	      need_phis = true;
+	  }
+	if (need_phis)
+	  {
+	    tree var = create_tmp_reg (TREE_TYPE (name));
+	    use_operand_p use_p;
+	    FOR_EACH_IMM_USE_STMT (use_stmt, it, name)
+	      {
+		basic_block use_bb = gimple_bb (use_stmt);
+		FOR_EACH_IMM_USE_ON_STMT (use_p, it)
+		    SET_USE (use_p, var);
+		update_stmt (use_stmt);
+		set_livein_block (var, use_bb);
+		set_rewrite_uses (use_stmt, true);
+		bitmap_set_bit (interesting_blocks, use_bb->index);
+	      }
+	    def_operand_p def_p;
+	    ssa_op_iter dit;
+	    FOR_EACH_SSA_DEF_OPERAND (def_p, def_stmt, dit, SSA_OP_DEF)
+	      if (DEF_FROM_PTR (def_p) == name)
+		SET_DEF (def_p, var);
+	    update_stmt (def_stmt);
+	    set_def_block (var, def_bb, false);
+	    set_register_defs (def_stmt, true);
+	    bitmap_set_bit (interesting_blocks, def_bb->index);
+	    release_ssa_name (name);
+	  }
+      }
+
   auto_vec<var_info *> vars (var_infos->elements ());
   FOR_EACH_HASH_TABLE_ELEMENT (*var_infos, info, var_info_p, hi)
     if (info->info.need_phi_state != NEED_PHI_STATE_NO)
Index: gcc/testsuite/gcc.dg/torture/pr79432.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr79432.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/pr79432.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+
+int fn1 (void);
+int __attribute__((returns_twice)) vfork (void);
+
+void fn2 ()
+{
+  int a;
+  a = fn1() + 2 + (vfork() + 1 + vfork());
+}
+void fn3 ()
+{
+  int a;
+  a = fn1() + 1 + vfork();
+}
+void fn4 ()
+{
+  int a;
+  a = fn1() + vfork();
+}