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  <rguent...@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.

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();
+}

Reply via email to