Merge switch statements in tree-cfgcleanup

Richard Biener richard.guenther@gmail.com
Fri Jul 22 13:14:00 GMT 2016


On Wed, Jul 20, 2016 at 6:26 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 07/20/2016 06:09 PM, Jeff Law wrote:
>>
>> So I'm going to let Richi run with the review on this one since the two
>> of you are already iterating.  But I did have one comment on the
>> placement of the pass.
>>
>> I believe one of the key things to consider for whether or not something
>> like this belongs in the cfgcleanup code is whether or not the
>> optimization is likely exposed repeatedly through the optimization
>> pipeline.  If it's mostly a source level issue or only usually exposed
>> by a limited set of optimizers, then a separate pass might be better.
>
>
> It can trigger before switchconv, and could expose optimization
> opportunities there, but I've also seen it trigger much later. Since I think
> it's cheap I don't see a reason not to put it in cfgcleanup, IMO it's the
> best fit conceptually.

I'm not convinced.  We do have CFG matching passes like phi-opt,
if-combine.  With your logic even simple jump-threading like
if (a) if (a) ... would be a job for CFG cleanup?

+  gsi2 = gsi_start_nondebug_after_labels_bb (bb);
+  if (gsi_end_p (gsi2))
+    return false;
+
+  gimple *stmt = gsi_stmt (gsi2);
+  if (gimple_code (stmt) != GIMPLE_SWITCH)
+    return false;

  stmt = last_stmt (bb);
  if (!stmt || gimple_code (stmt) != GIMPLE_SWITHC)
    return false;

is shorter and has the same effect.

+  edge e;
+  edge_iterator ei;
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    {
+      basic_block dest = e->dest;
+      if (find_edge (pred_bb, dest))
+       {
+         /* If a destination block is reached from both switches, any
+            phi nodes there would become corrupted.  */
+         gphi_iterator psi = gsi_start_phis (dest);
+         if (!gsi_end_p (psi))
+           return false;
+       }
+    }

I wonder if this tests all required blocks.  Why can't there be a forwarder
between pred_bb and dest for example?  I think you want sth like

 if (! dominated_by_p (CDI_DOMINATORS, dest, bb))
   ... verify no PHIs ...


+  auto_vec<tree> new_labels;
+

please pre-reserve enough space to hold labels from both switches
and use quick_push below.

+  /* Merge adjacent ranges.  */
+  size_t new_count = new_labels.length ();
+  for (i1 = i2 = 1; i1 < new_count; )
+    {
+      ce1 = new_labels[i1++];
+      tree high = CASE_HIGH (ce1);
+      if (high == NULL_TREE)
+       high = CASE_LOW (ce1);
+      while (i1 < new_count)
+       {
+         ce2 = new_labels[i1];

what about re-using the code from tree-cfg.c instead?  (group_case_labels_stmt)

+  if (dom_info_available_p (CDI_DOMINATORS))

I think DOM info is always available during CFG cleanup

+    {
+      basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
+      gcc_assert (dombb == pred_bb);
+      vec<basic_block> fix_bbs;
+      fix_bbs = get_all_dominated_blocks (CDI_DOMINATORS, pred_bb);
+      iterate_fix_dominators (CDI_DOMINATORS, fix_bbs, false);
+      fix_bbs.release ();
+    }


Richard.

>
> Bernd
>



More information about the Gcc-patches mailing list