This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC PATCH] Improve switchconv optimization (PR tree-optimization/79472)


On February 14, 2017 9:04:45 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>The following patch is an attempt to fix a regression where we no
>longer
>switch convert one switch because earlier optimizations turn it into
>unsupported shape.

Is that because of early threading?

>The patch contains two important changes (that can perhaps be split off
>separately):
>1) handle virtual PHIs; while because we require all the switch bbs
> to be empty, all the edges from the switch to final_bb should have the
>   same virtual op SSA_NAME, if the final_bb is reachable through other
>  edges from other code, it might have virtual PHI and switchconv would
>   unnecessarily give up
>2) if the switch cases form contiguous range, there is no need to
>require
>   anything about the default case, it can be abort, or arbitrary code
>   that can or might not fall through into final_bb, or it can e.g. be
>  empty bb and just the values from default bb might not be appropriate
>   constants; we emit an if (val is in range) vals = CSWTCH[...]; else
> anyway and the else can be anything; we still have to require standard
>  default case if the range is non-contiguous, because then the default
>   is used also for some values in the tables.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux.  It causes a
>single
>regression, vrp40.c, which looks like this:
>int f(int a) {
>switch (a & 1) { case 0: case 1: return 3; case 2: return 5; case 3:
>return 7;
>case 4: return 11; case 5: return 13; case 6: return 17; case 7: return
>19; }
>}
>and expects to be optimized into return 3 by vrp1.  As switchconv is
>earlier
>than that, vrp1 sees:
>  _1 = a_3(D) & 1;
>  _4 = (unsigned int) _1;
>  _5 = CSWTCH.1[_4];
>  return _5;
>and doesn't optimize it.  If the testcase had say case 7: replaced with
>default:, it wouldn't pass already before.

That looks odd...

  If the patch is ok, what
>should
>we do with vrp40.c?  Change it in some way (e.g. return variable in one
>case) so that switchconv doesn't trigger, or add an optimization in vrp
>if we see a load from constant array with known initializer and the
>range
>is small enough and contains the same value for all those values,
>replace
>it with the value? 

Possibly, but for GCC 8.

can we teach EVRP about this?  It runs before switch conversion.

Richard.


 It would help also with say:
>const int a[] = { 7, 8, 9, 1, 1, 1, 1, 2, 3, 4, 5, 6 };
>int foo (int x)
>{
>  if (x <= 2 || x >= 7) return 3;
>  return a[x];
>}
>turn it into
>int foo (int x)
>{
>  if (x <= 2 || x >= 7) return 3;
>  return 1;
>}
>
>2017-02-14  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/79472
>	* tree-switch-conversion.c (struct switch_conv_info): Add
>	contiguous_range and default_case_nonstandard fields.
>	(collect_switch_conv_info): Compute contiguous_range and
>	default_case_nonstandard fields, don't clear final_bb if
>	contiguous_range and only the default case doesn't have the required
>	structure.
>	(check_all_empty_except_final): Set default_case_nonstandard instead
>	of failing if contiguous_range and the default case doesn't have empty
>	block.
>	(check_final_bb): Add SWTCH argument, don't fail if contiguous_range
>	and only the default case doesn't have the required constants.  Skip
>	virtual phis.
>	(gather_default_values): Skip virtual phis.  Allow non-NULL CASE_LOW
>	if default_case_nonstandard.
>	(build_constructors): Build constant 1 just once.  Assert that default
>	values aren't inserted in between cases if contiguous_range.  Skip
>	virtual phis.
>	(build_arrays): Skip virtual phis.
>	(prune_bbs): Add DEFAULT_BB argument, don't remove that bb.
>	(fix_phi_nodes): Don't add e2f phi arg if default_case_nonstandard.
>	Handle virtual phis.
>	(gen_inbound_check): Handle default_case_nonstandard case.
>	(process_switch): Adjust check_final_bb caller.  Call
>	gather_default_values with the first non-default case instead of
>	default case if default_case_nonstandard.
>
>	* gcc.dg/tree-ssa/cswtch-3.c: New test.
>	* gcc.dg/tree-ssa/cswtch-4.c: New test.
>	* gcc.dg/tree-ssa/cswtch-5.c: New test.
>
>--- gcc/tree-switch-conversion.c.jj	2017-02-14 14:54:08.020975500 +0100
>+++ gcc/tree-switch-conversion.c	2017-02-14 17:09:01.162826954 +0100
>@@ -592,6 +592,14 @@ struct switch_conv_info
>      dump file, if there is one.  */
>   const char *reason;
> 
>+  /* True if default case is not used for any value between range_min
>and
>+     range_max inclusive.  */
>+  bool contiguous_range;
>+
>+  /* True if default case does not have the required shape for other
>case
>+     labels.  */
>+  bool default_case_nonstandard;
>+
>   /* Parameters for expand_switch_using_bit_tests.  Should be computed
>      the same way as in expand_case.  */
>   unsigned int uniq;
>@@ -606,8 +614,9 @@ collect_switch_conv_info (gswitch *swtch
>   unsigned int branch_num = gimple_switch_num_labels (swtch);
>   tree min_case, max_case;
>   unsigned int count, i;
>-  edge e, e_default;
>+  edge e, e_default, e_first;
>   edge_iterator ei;
>+  basic_block first;
> 
>   memset (info, 0, sizeof (*info));
> 
>@@ -616,8 +625,8 @@ collect_switch_conv_info (gswitch *swtch
>      Collect the bits we can deduce from the CFG.  */
>   info->index_expr = gimple_switch_index (swtch);
>   info->switch_bb = gimple_bb (swtch);
>-  info->default_bb =
>-    label_to_block (CASE_LABEL (gimple_switch_default_label (swtch)));
>+  info->default_bb
>+    = label_to_block (CASE_LABEL (gimple_switch_default_label
>(swtch)));
>   e_default = find_edge (info->switch_bb, info->default_bb);
>   info->default_prob = e_default->probability;
>   info->default_count = e_default->count;
>@@ -625,17 +634,54 @@ collect_switch_conv_info (gswitch *swtch
>     if (e != e_default)
>       info->other_count += e->count;
> 
>+  /* Get upper and lower bounds of case values, and the covered range.
> */
>+  min_case = gimple_switch_label (swtch, 1);
>+  max_case = gimple_switch_label (swtch, branch_num - 1);
>+
>+  info->range_min = CASE_LOW (min_case);
>+  if (CASE_HIGH (max_case) != NULL_TREE)
>+    info->range_max = CASE_HIGH (max_case);
>+  else
>+    info->range_max = CASE_LOW (max_case);
>+
>+  info->contiguous_range = true;
>+  tree last = CASE_HIGH (min_case) ? CASE_HIGH (min_case) :
>info->range_min;
>+  for (i = 2; i < branch_num; i++)
>+    {
>+      tree elt = gimple_switch_label (swtch, i);
>+      wide_int w = last;
>+      if (w + 1 != CASE_LOW (elt))
>+	{
>+	  info->contiguous_range = false;
>+	  break;
>+	}
>+      last = CASE_HIGH (elt) ? CASE_HIGH (elt) : CASE_LOW (elt);
>+    }
>+
>+  if (info->contiguous_range)
>+    {
>+      first = label_to_block (CASE_LABEL (gimple_switch_label (swtch,
>1)));
>+      e_first = find_edge (info->switch_bb, first);
>+    }
>+  else
>+    {
>+      first = info->default_bb;
>+      e_first = e_default;
>+    }
>+
>   /* See if there is one common successor block for all branch
>      targets.  If it exists, record it in FINAL_BB.
>-     Start with the destination of the default case as guess
>-     or its destination in case it is a forwarder block.  */
>-  if (! single_pred_p (e_default->dest))
>-    info->final_bb = e_default->dest;
>-  else if (single_succ_p (e_default->dest)
>-	   && ! single_pred_p (single_succ (e_default->dest)))
>-    info->final_bb = single_succ (e_default->dest);
>+     Start with the destination of the first non-default case
>+     if the range is contiguous and default case otherwise as
>+     guess or its destination in case it is a forwarder block.  */
>+  if (! single_pred_p (e_first->dest))
>+    info->final_bb = e_first->dest;
>+  else if (single_succ_p (e_first->dest)
>+	   && ! single_pred_p (single_succ (e_first->dest)))
>+    info->final_bb = single_succ (e_first->dest);
>   /* Require that all switch destinations are either that common
>-     FINAL_BB or a forwarder to it.  */
>+     FINAL_BB or a forwarder to it, except for the default
>+     case if contiguous range.  */
>   if (info->final_bb)
>     FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
>       {
>@@ -647,22 +693,18 @@ collect_switch_conv_info (gswitch *swtch
> 	    && single_succ (e->dest) == info->final_bb)
> 	  continue;
> 
>+	if (e == e_default && info->contiguous_range)
>+	  {
>+	    info->default_case_nonstandard = true;
>+	    continue;
>+	  }
>+
> 	info->final_bb = NULL;
> 	break;
>       }
> 
>-  /* Get upper and lower bounds of case values, and the covered range.
> */
>-  min_case = gimple_switch_label (swtch, 1);
>-  max_case = gimple_switch_label (swtch, branch_num - 1);
>-
>-  info->range_min = CASE_LOW (min_case);
>-  if (CASE_HIGH (max_case) != NULL_TREE)
>-    info->range_max = CASE_HIGH (max_case);
>-  else
>-    info->range_max = CASE_LOW (max_case);
>-
>-  info->range_size =
>-    int_const_binop (MINUS_EXPR, info->range_max, info->range_min);
>+  info->range_size
>+    = int_const_binop (MINUS_EXPR, info->range_max, info->range_min);
> 
>/* Get a count of the number of case labels.  Single-valued case labels
>      simply count as one, but a case range counts double, since it may
>@@ -713,7 +755,7 @@ check_range (struct switch_conv_info *in
> static bool
> check_all_empty_except_final (struct switch_conv_info *info)
> {
>-  edge e;
>+  edge e, e_default = find_edge (info->switch_bb, info->default_bb);
>   edge_iterator ei;
> 
>   FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
>@@ -723,6 +765,12 @@ check_all_empty_except_final (struct swi
> 
>       if (!empty_block_p (e->dest))
> 	{
>+	  if (info->contiguous_range && e == e_default)
>+	    {
>+	      info->default_case_nonstandard = true;
>+	      continue;
>+	    }
>+
> 	  info->reason = "bad case - a non-final BB not empty";
> 	  return false;
> 	}
>@@ -737,7 +785,7 @@ check_all_empty_except_final (struct swi
>    phi nodes are OK, otherwise false.  */
> 
> static bool
>-check_final_bb (struct switch_conv_info *info)
>+check_final_bb (gswitch *swtch, struct switch_conv_info *info)
> {
>   gphi_iterator gsi;
> 
>@@ -747,6 +795,9 @@ check_final_bb (struct switch_conv_info
>       gphi *phi = gsi.phi ();
>       unsigned int i;
> 
>+      if (virtual_operand_p (gimple_phi_result (phi)))
>+	continue;
>+
>       info->phi_count++;
> 
>       for (i = 0; i < gimple_phi_num_args (phi); i++)
>@@ -754,27 +805,55 @@ check_final_bb (struct switch_conv_info
> 	  basic_block bb = gimple_phi_arg_edge (phi, i)->src;
> 
> 	  if (bb == info->switch_bb
>-	      || (single_pred_p (bb) && single_pred (bb) == info->switch_bb))
>+	      || (single_pred_p (bb)
>+		  && single_pred (bb) == info->switch_bb
>+		  && (!info->default_case_nonstandard
>+		      || empty_block_p (bb))))
> 	    {
> 	      tree reloc, val;
>+	      const char *reason = NULL;
> 
> 	      val = gimple_phi_arg_def (phi, i);
> 	      if (!is_gimple_ip_invariant (val))
>+		reason = "non-invariant value from a case";
>+	      else
> 		{
>-		  info->reason = "non-invariant value from a case";
>-		  return false; /* Non-invariant argument.  */
>+		  reloc = initializer_constant_valid_p (val, TREE_TYPE (val));
>+		  if ((flag_pic && reloc != null_pointer_node)
>+		      || (!flag_pic && reloc == NULL_TREE))
>+		    {
>+		      if (reloc)
>+			reason
>+			  = "value from a case would need runtime relocations";
>+		      else
>+			reason
>+			  = "value from a case is not a valid initializer";
>+		    }
> 		}
>-	      reloc = initializer_constant_valid_p (val, TREE_TYPE (val));
>-	      if ((flag_pic && reloc != null_pointer_node)
>-		  || (!flag_pic && reloc == NULL_TREE))
>+	      if (reason)
> 		{
>-		  if (reloc)
>-		    info->reason
>-		      = "value from a case would need runtime relocations";
>-		  else
>-		    info->reason
>-		      = "value from a case is not a valid initializer";
>-		  return false;
>+		  /* For contiguous range, we can allow non-constant
>+		     or one that needs relocation, as long as it is
>+		     only reachable from the default case.  */
>+		  if (bb == info->switch_bb)
>+		    bb = info->final_bb;
>+		  if (!info->contiguous_range || bb != info->default_bb)
>+		    {
>+		      info->reason = reason;
>+		      return false;
>+		    }
>+
>+		  unsigned int branch_num = gimple_switch_num_labels (swtch);
>+		  for (unsigned int i = 1; i < branch_num; i++)
>+		    {
>+		      tree lab = CASE_LABEL (gimple_switch_label (swtch, i));
>+		      if (label_to_block (lab) == bb)
>+			{
>+			  info->reason = reason;
>+			  return false;
>+			}
>+		    }
>+		  info->default_case_nonstandard = true;
> 		}
> 	    }
> 	}
>@@ -815,7 +894,9 @@ free_temp_arrays (struct switch_conv_inf
> }
> 
> /* Populate the array of default values in the order of phi nodes.
>-   DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. 
>*/
>+   DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch
>+   if the range is non-contiguous or the default case has standard
>+   structure, otherwise it is the first non-default case instead.  */
> 
> static void
>gather_default_values (tree default_case, struct switch_conv_info
>*info)
>@@ -825,7 +906,8 @@ gather_default_values (tree default_case
>   edge e;
>   int i = 0;
> 
>-  gcc_assert (CASE_LOW (default_case) == NULL_TREE);
>+  gcc_assert (CASE_LOW (default_case) == NULL_TREE
>+	      || info->default_case_nonstandard);
> 
>   if (bb == info->final_bb)
>     e = find_edge (info->switch_bb, bb);
>@@ -835,6 +917,8 @@ gather_default_values (tree default_case
>for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next
>(&gsi))
>     {
>       gphi *phi = gsi.phi ();
>+      if (virtual_operand_p (gimple_phi_result (phi)))
>+	continue;
>       tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
>       gcc_assert (val);
>       info->default_values[i++] = val;
>@@ -850,6 +934,7 @@ build_constructors (gswitch *swtch, stru
> {
>   unsigned i, branch_num = gimple_switch_num_labels (swtch);
>   tree pos = info->range_min;
>+  tree pos_one = build_int_cst (TREE_TYPE (pos), 1);
> 
>   for (i = 1; i < branch_num; i++)
>     {
>@@ -869,6 +954,7 @@ build_constructors (gswitch *swtch, stru
>       while (tree_int_cst_lt (pos, CASE_LOW (cs)))
> 	{
> 	  int k;
>+	  gcc_assert (!info->contiguous_range);
> 	  for (k = 0; k < info->phi_count; k++)
> 	    {
> 	      constructor_elt elt;
>@@ -879,8 +965,7 @@ build_constructors (gswitch *swtch, stru
> 	      info->constructors[k]->quick_push (elt);
> 	    }
> 
>-	  pos = int_const_binop (PLUS_EXPR, pos,
>-				 build_int_cst (TREE_TYPE (pos), 1));
>+	  pos = int_const_binop (PLUS_EXPR, pos, pos_one);
> 	}
>       gcc_assert (tree_int_cst_equal (pos, CASE_LOW (cs)));
> 
>@@ -893,6 +978,8 @@ build_constructors (gswitch *swtch, stru
> 	   !gsi_end_p (gsi); gsi_next (&gsi))
> 	{
> 	  gphi *phi = gsi.phi ();
>+	  if (virtual_operand_p (gimple_phi_result (phi)))
>+	    continue;
> 	  tree val = PHI_ARG_DEF_FROM_EDGE (phi, e);
> 	  tree low = CASE_LOW (cs);
> 	  pos = CASE_LOW (cs);
>@@ -905,8 +992,7 @@ build_constructors (gswitch *swtch, stru
> 	      elt.value = unshare_expr_without_location (val);
> 	      info->constructors[j]->quick_push (elt);
> 
>-	      pos = int_const_binop (PLUS_EXPR, pos,
>-				     build_int_cst (TREE_TYPE (pos), 1));
>+	      pos = int_const_binop (PLUS_EXPR, pos, pos_one);
> 	    } while (!tree_int_cst_lt (high, pos)
> 		     && tree_int_cst_lt (low, pos));
> 	  j++;
>@@ -1118,8 +1204,12 @@ build_arrays (gswitch *swtch, struct swi
>   info->arr_ref_first = stmt;
> 
>   for (gpi = gsi_start_phis (info->final_bb), i = 0;
>-       !gsi_end_p (gpi); gsi_next (&gpi), i++)
>-    build_one_array (swtch, i, arr_index_type, gpi.phi (), tidx,
>info);
>+       !gsi_end_p (gpi); gsi_next (&gpi))
>+    {
>+      gphi *phi = gpi.phi ();
>+      if (!virtual_operand_p (gimple_phi_result (phi)))
>+	build_one_array (swtch, i++, arr_index_type, phi, tidx, info);
>+    }
> }
> 
>/* Generates and appropriately inserts loads of default values at the
>position
>@@ -1148,7 +1238,7 @@ gen_def_assigns (gimple_stmt_iterator *g
>    of succession).  */
> 
> static void
>-prune_bbs (basic_block bbd, basic_block final)
>+prune_bbs (basic_block bbd, basic_block final, basic_block default_bb)
> {
>   edge_iterator ei;
>   edge e;
>@@ -1158,7 +1248,7 @@ prune_bbs (basic_block bbd, basic_block
>       basic_block bb;
>       bb = e->dest;
>       remove_edge (e);
>-      if (bb != final)
>+      if (bb != final && bb != default_bb)
> 	delete_basic_block (bb);
>     }
>   delete_basic_block (bbd);
>@@ -1177,11 +1267,20 @@ fix_phi_nodes (edge e1f, edge e2f, basic
>   int i;
> 
>   for (gsi = gsi_start_phis (bbf), i = 0;
>-       !gsi_end_p (gsi); gsi_next (&gsi), i++)
>+       !gsi_end_p (gsi); gsi_next (&gsi))
>     {
>       gphi *phi = gsi.phi ();
>-      add_phi_arg (phi, info->target_inbound_names[i], e1f,
>UNKNOWN_LOCATION);
>-      add_phi_arg (phi, info->target_outbound_names[i], e2f,
>UNKNOWN_LOCATION);
>+      tree inbound, outbound;
>+      if (virtual_operand_p (gimple_phi_result (phi)))
>+	inbound = outbound = gimple_vop (cfun);
>+      else
>+	{
>+	  inbound = info->target_inbound_names[i];
>+	  outbound = info->target_outbound_names[i++];
>+	}
>+      add_phi_arg (phi, inbound, e1f, UNKNOWN_LOCATION);
>+      if (!info->default_case_nonstandard)
>+	add_phi_arg (phi, outbound, e2f, UNKNOWN_LOCATION);
>     }
> }
> 
>@@ -1218,10 +1317,10 @@ gen_inbound_check (gswitch *swtch, struc
> 
>   gcond *cond_stmt;
> 
>-  gassign *last_assign;
>+  gassign *last_assign = NULL;
>   gimple_stmt_iterator gsi;
>   basic_block bb0, bb1, bb2, bbf, bbd;
>-  edge e01, e02, e21, e1d, e1f, e2f;
>+  edge e01 = NULL, e02, e21, e1d, e1f, e2f;
>   location_t loc = gimple_location (swtch);
> 
>   gcc_assert (info->default_values);
>@@ -1241,9 +1340,12 @@ gen_inbound_check (gswitch *swtch, struc
>   update_stmt (cond_stmt);
> 
>   /* block 2 */
>-  label2 = gimple_build_label (label_decl2);
>-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
>-  last_assign = gen_def_assigns (&gsi, info);
>+  if (!info->default_case_nonstandard)
>+    {
>+      label2 = gimple_build_label (label_decl2);
>+      gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
>+      last_assign = gen_def_assigns (&gsi, info);
>+    }
> 
>   /* block 1 */
>   label1 = gimple_build_label (label_decl1);
>@@ -1258,16 +1360,40 @@ gen_inbound_check (gswitch *swtch, struc
>   e02 = split_block (bb0, cond_stmt);
>   bb2 = e02->dest;
> 
>-  e21 = split_block (bb2, last_assign);
>-  bb1 = e21->dest;
>-  remove_edge (e21);
>+  if (info->default_case_nonstandard)
>+    {
>+      bb1 = bb2;
>+      bb2 = info->default_bb;
>+      e01 = e02;
>+      e01->flags = EDGE_TRUE_VALUE;
>+      e02 = make_edge (bb0, bb2, EDGE_FALSE_VALUE);
>+      edge e_default = find_edge (bb1, bb2);
>+      for (gphi_iterator gsi = gsi_start_phis (bb2);
>+	   !gsi_end_p (gsi); gsi_next (&gsi))
>+	{
>+	  gphi *phi = gsi.phi ();
>+	  tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e_default);
>+	  add_phi_arg (phi, arg, e02,
>+		       gimple_phi_arg_location_from_edge (phi, e_default));
>+	}
>+      /* Partially fix the dominator tree, if it is available.  */
>+      if (dom_info_available_p (CDI_DOMINATORS))
>+	redirect_immediate_dominators (CDI_DOMINATORS, bb1, bb0);
>+    }
>+  else
>+    {
>+      e21 = split_block (bb2, last_assign);
>+      bb1 = e21->dest;
>+      remove_edge (e21);
>+    }
> 
>   e1d = split_block (bb1, info->arr_ref_last);
>   bbd = e1d->dest;
>   remove_edge (e1d);
> 
>   /* flags and profiles of the edge for in-range values */
>-  e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE);
>+  if (!info->default_case_nonstandard)
>+    e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE);
>   e01->probability = REG_BR_PROB_BASE - info->default_prob;
>   e01->count = info->other_count;
> 
>@@ -1283,17 +1409,24 @@ gen_inbound_check (gswitch *swtch, struc
>   e1f->probability = REG_BR_PROB_BASE;
>   e1f->count = info->other_count;
> 
>-  e2f = make_edge (bb2, bbf, EDGE_FALLTHRU);
>-  e2f->probability = REG_BR_PROB_BASE;
>-  e2f->count = info->default_count;
>+  if (info->default_case_nonstandard)
>+    e2f = NULL;
>+  else
>+    {
>+      e2f = make_edge (bb2, bbf, EDGE_FALLTHRU);
>+      e2f->probability = REG_BR_PROB_BASE;
>+      e2f->count = info->default_count;
>+    }
> 
>   /* frequencies of the new BBs */
>   bb1->frequency = EDGE_FREQUENCY (e01);
>   bb2->frequency = EDGE_FREQUENCY (e02);
>-  bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f);
>+  if (!info->default_case_nonstandard)
>+    bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f);
> 
>   /* Tidy blocks that have become unreachable.  */
>-  prune_bbs (bbd, info->final_bb);
>+  prune_bbs (bbd, info->final_bb,
>+	     info->default_case_nonstandard ? info->default_bb : NULL);
> 
>   /* Fixup the PHI nodes in bbF.  */
>   fix_phi_nodes (e1f, e2f, bbf, info);
>@@ -1304,15 +1437,17 @@ gen_inbound_check (gswitch *swtch, struc
>       vec<basic_block> bbs_to_fix_dom;
> 
>       set_immediate_dominator (CDI_DOMINATORS, bb1, bb0);
>-      set_immediate_dominator (CDI_DOMINATORS, bb2, bb0);
>+      if (!info->default_case_nonstandard)
>+	set_immediate_dominator (CDI_DOMINATORS, bb2, bb0);
>       if (! get_immediate_dominator (CDI_DOMINATORS, bbf))
> 	/* If bbD was the immediate dominator ...  */
> 	set_immediate_dominator (CDI_DOMINATORS, bbf, bb0);
> 
>-      bbs_to_fix_dom.create (4);
>+      bbs_to_fix_dom.create (3 + (bb2 != bbf));
>       bbs_to_fix_dom.quick_push (bb0);
>       bbs_to_fix_dom.quick_push (bb1);
>-      bbs_to_fix_dom.quick_push (bb2);
>+      if (bb2 != bbf)
>+	bbs_to_fix_dom.quick_push (bb2);
>       bbs_to_fix_dom.quick_push (bbf);
> 
>       iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
>@@ -1387,7 +1522,7 @@ process_switch (gswitch *swtch)
>       gcc_assert (info.reason);
>       return info.reason;
>     }
>-  if (!check_final_bb (&info))
>+  if (!check_final_bb (swtch, &info))
>     {
>       gcc_assert (info.reason);
>       return info.reason;
>@@ -1397,7 +1532,9 @@ process_switch (gswitch *swtch)
>      transformation.  */
> 
>   create_temp_arrays (&info);
>-  gather_default_values (gimple_switch_default_label (swtch), &info);
>+  gather_default_values (info.default_case_nonstandard
>+			 ? gimple_switch_label (swtch, 1)
>+			 : gimple_switch_default_label (swtch), &info);
>   build_constructors (swtch, &info);
> 
>build_arrays (swtch, &info); /* Build the static arrays and
>assignments.   */
>--- gcc/testsuite/gcc.dg/tree-ssa/cswtch-3.c.jj	2017-02-14
>15:46:55.002417399 +0100
>+++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-3.c	2017-02-14
>15:46:55.002417399 +0100
>@@ -0,0 +1,330 @@
>+/* PR tree-optimization/79472 */
>+/* { dg-options "-O2 -fdump-tree-switchconv" } */
>+/* { dg-do run } */
>+
>+int *expected;
>+
>+void
>+foo (int x, int y)
>+{
>+  if (x != expected[0] || y != expected[1])
>+    __builtin_abort ();
>+  expected += 2;
>+}
>+
>+__attribute__((noinline, noclone)) void
>+f1 (int v, int w)
>+{
>+  int i, j;
>+  if (w)
>+    {
>+      i = 129;
>+      j = i - 1;
>+      goto lab;
>+    }
>+  switch (v)
>+    {
>+    case 170:
>+      j = 7;
>+      i = 27;
>+      break;
>+    case 171:
>+      i = 8;
>+      j = 122;
>+      break;
>+    case 172:
>+      i = 21;
>+      j = -19;
>+      break;
>+    case 173:
>+      i = 18;
>+      j = 17;
>+      break;
>+    case 174:
>+      i = 139;
>+      j = -5;
>+      break;
>+    case 175:
>+      i = 14;
>+      j = -26;
>+      break;
>+    case 176:
>+      j = 5;
>+      i = -14;
>+      break;
>+    case 177:
>+      j = 8;
>+      i = 12;
>+      break;
>+    default:
>+      __builtin_abort ();
>+    }
>+
>+ lab:
>+  foo (i, j);
>+}
>+
>+__attribute__((noinline, noclone)) void
>+f2 (int v)
>+{
>+  int i, j;
>+  switch (v)
>+    {
>+    case 170:
>+      j = 7;
>+      i = 27;
>+      break;
>+    case 171:
>+      i = 8;
>+      j = 122;
>+      break;
>+    case 172:
>+      i = 21;
>+      j = -19;
>+      break;
>+    case 173:
>+      i = 18;
>+      j = 17;
>+      break;
>+    case 174:
>+      i = 139;
>+      j = -5;
>+      break;
>+    case 175:
>+      i = 14;
>+      j = -26;
>+      break;
>+    case 176:
>+      j = 5;
>+      i = -14;
>+      break;
>+    case 177:
>+      j = 8;
>+      i = 12;
>+      break;
>+    default:
>+      foo (5, 12);
>+      foo (17, 19);
>+      i = 8;
>+      j = 19;
>+      break;
>+    }
>+
>+  foo (i, j);
>+}
>+
>+__attribute__((noinline, noclone)) void
>+f3 (int v)
>+{
>+  int i;
>+  switch (v)
>+    {
>+    default:
>+      i = v;
>+      goto lab;
>+    case 170:
>+      i = 27;
>+      break;
>+    case 171:
>+      i = 8;
>+      break;
>+    case 172:
>+      i = 21;
>+      break;
>+    case 173:
>+      i = 18;
>+      break;
>+    case 174:
>+      i = 139;
>+      break;
>+    case 175:
>+      i = 14;
>+      break;
>+    case 176:
>+      i = -14;
>+      break;
>+    case 177:
>+      i = 12;
>+      break;
>+    }
>+
>+ lab:
>+  foo (i, -5);
>+}
>+
>+__attribute__((noinline, noclone)) void
>+f4 (int v, int w)
>+{
>+  int i, j, k = 5;
>+  if (w)
>+    {
>+      foo (0, 0);
>+      k = 26;
>+      goto do_default;
>+    }
>+  switch (v)
>+    {
>+    case 170:
>+      j = 7;
>+      i = 27;
>+      break;
>+    case 171:
>+      i = 8;
>+      j = 122;
>+      break;
>+    case 172:
>+      i = 21;
>+      j = -19;
>+      break;
>+    case 173:
>+      i = 18;
>+      j = 17;
>+      break;
>+    case 174:
>+      i = 139;
>+      j = -5;
>+      break;
>+    case 175:
>+      i = 14;
>+      j = -26;
>+      break;
>+    case 176:
>+      j = 5;
>+      i = -14;
>+      break;
>+    case 177:
>+      j = 8;
>+      i = 12;
>+      break;
>+    default:
>+    do_default:
>+      foo (5, 12);
>+      foo (17, 19);
>+      i = 8;
>+      j = 19;
>+      break;
>+    }
>+
>+  foo (i, j + k);
>+}
>+
>+void
>+f5 (int v, int w)
>+{
>+  int i;
>+  if (w)
>+    {
>+      foo (23, 0);
>+      i = 129;
>+    }
>+  else
>+    switch (v)
>+      {
>+      case 170:
>+	i = 27;
>+	break;
>+      case 171:
>+	i = 8;
>+	break;
>+      case 172:
>+	i = 21;
>+	break;
>+      case 173:
>+	i = 18;
>+	break;
>+      case 174:
>+	i = 139;
>+	break;
>+      case 175:
>+	i = 14;
>+	break;
>+      case 176:
>+	i = -14;
>+	break;
>+      case 177:
>+	i = 12;
>+	break;
>+      default:
>+	i = 80;
>+	break;
>+      }
>+
>+ lab:
>+  foo (i, 0);
>+}
>+
>+int
>+main ()
>+{
>+  int *e;
>+#define T(call, cnt, ...) \
>+  expected = e = (int []) __VA_ARGS__;		\
>+  call;						\
>+  if (expected != e + cnt)			\
>+    __builtin_abort ()
>+  T (f1 (171, 1), 2, { 129, 128 });
>+  T (f1 (140, 1), 2, { 129, 128 });
>+  T (f1 (170, 0), 2, { 27, 7 });
>+  T (f1 (171, 0), 2, { 8, 122 });
>+  T (f1 (172, 0), 2, { 21, -19 });
>+  T (f1 (173, 0), 2, { 18, 17 });
>+  T (f1 (174, 0), 2, { 139, -5 });
>+  T (f1 (175, 0), 2, { 14, -26 });
>+  T (f1 (176, 0), 2, { -14, 5 });
>+  T (f1 (177, 0), 2, { 12, 8 });
>+  T (f2 (-31), 6, { 5, 12, 17, 19, 8, 19 });
>+  T (f2 (169), 6, { 5, 12, 17, 19, 8, 19 });
>+  T (f2 (170), 2, { 27, 7 });
>+  T (f2 (171), 2, { 8, 122 });
>+  T (f2 (172), 2, { 21, -19 });
>+  T (f2 (173), 2, { 18, 17 });
>+  T (f2 (174), 2, { 139, -5 });
>+  T (f2 (175), 2, { 14, -26 });
>+  T (f2 (176), 2, { -14, 5 });
>+  T (f2 (177), 2, { 12, 8 });
>+  T (f2 (178), 6, { 5, 12, 17, 19, 8, 19 });
>+  T (f2 (231), 6, { 5, 12, 17, 19, 8, 19 });
>+  T (f3 (-31), 2, { -31, -5 });
>+  T (f3 (169), 2, { 169, -5 });
>+  T (f3 (170), 2, { 27, -5 });
>+  T (f3 (171), 2, { 8, -5 });
>+  T (f3 (172), 2, { 21, -5 });
>+  T (f3 (173), 2, { 18, -5 });
>+  T (f3 (174), 2, { 139, -5 });
>+  T (f3 (175), 2, { 14, -5 });
>+  T (f3 (176), 2, { -14, -5 });
>+  T (f3 (177), 2, { 12, -5 });
>+  T (f3 (178), 2, { 178, -5 });
>+  T (f3 (231), 2, { 231, -5 });
>+  T (f4 (171, 1), 8, { 0, 0, 5, 12, 17, 19, 8, 45 });
>+  T (f4 (140, 1), 8, { 0, 0, 5, 12, 17, 19, 8, 45 });
>+  T (f4 (-31, 0), 6, { 5, 12, 17, 19, 8, 24 });
>+  T (f4 (169, 0), 6, { 5, 12, 17, 19, 8, 24 });
>+  T (f4 (170, 0), 2, { 27, 12 });
>+  T (f4 (171, 0), 2, { 8, 127 });
>+  T (f4 (172, 0), 2, { 21, -14 });
>+  T (f4 (173, 0), 2, { 18, 22 });
>+  T (f4 (174, 0), 2, { 139, 0 });
>+  T (f4 (175, 0), 2, { 14, -21 });
>+  T (f4 (176, 0), 2, { -14, 10 });
>+  T (f4 (177, 0), 2, { 12, 13 });
>+  T (f4 (178, 0), 6, { 5, 12, 17, 19, 8, 24 });
>+  T (f4 (231, 0), 6, { 5, 12, 17, 19, 8, 24 });
>+  T (f5 (171, 1), 4, { 23, 0, 129, 0 });
>+  T (f5 (140, 1), 4, { 23, 0, 129, 0 });
>+  T (f5 (-31, 0), 2, { 80, 0 });
>+  T (f5 (169, 0), 2, { 80, 0 });
>+  T (f5 (170, 0), 2, { 27, 0 });
>+  T (f5 (171, 0), 2, { 8, 0 });
>+  T (f5 (172, 0), 2, { 21, 0 });
>+  T (f5 (173, 0), 2, { 18, 0 });
>+  T (f5 (174, 0), 2, { 139, 0 });
>+  T (f5 (175, 0), 2, { 14, 0 });
>+  T (f5 (176, 0), 2, { -14, 0 });
>+  T (f5 (177, 0), 2, { 12, 0 });
>+  T (f5 (178, 0), 2, { 80, 0 });
>+  T (f5 (231, 0), 2, { 80, 0 });
>+}
>+
>+/* { dg-final { scan-tree-dump-times "Switch converted" 5 "switchconv"
>} } */
>+/* { dg-final { scan-tree-dump-times "= CSWTCH" 8 "switchconv" } } */
>--- gcc/testsuite/gcc.dg/tree-ssa/cswtch-4.c.jj	2017-02-14
>15:46:55.003417386 +0100
>+++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-4.c	2017-02-14
>15:46:55.003417386 +0100
>@@ -0,0 +1,57 @@
>+/* PR tree-optimization/79472 */
>+/* { dg-options "-O2 -fdump-tree-switchconv" } */
>+/* { dg-do compile } */
>+
>+void
>+frobulate (unsigned int v)
>+{
>+  const char *s;
>+  
>+  switch (v)
>+    {
>+    case 0:
>+      s = "foo";
>+      break;
>+    case 1:
>+      s = "bar";
>+      break;
>+    case 2:
>+      s = "spam";
>+      break;
>+    default:
>+      __builtin_abort ();
>+      break;
>+    }
>+
>+  __builtin_printf ("%s\n", s);
>+}
>+
>+void
>+frobulate_for_gcc (unsigned int v)
>+{
>+  const char *s;
>+  
>+  switch (v)
>+    {
>+    case 0:
>+      s = "foo";
>+      break;
>+    case 1:
>+      s = "bar";
>+      break;
>+    case 2:
>+      s = "spam";
>+      break;
>+    default:
>+      s = (const char *) 0;
>+      break;
>+    }
>+  
>+  if (!s)
>+    __builtin_abort ();
>+  
>+  __builtin_printf ("%s\n", s);
>+}
>+
>+/* { dg-final { scan-tree-dump-times "Switch converted" 2 "switchconv"
>} } */
>+/* { dg-final { scan-tree-dump-times "= CSWTCH" 2 "switchconv" } } */
>--- gcc/testsuite/gcc.dg/tree-ssa/cswtch-5.c.jj	2017-02-14
>17:11:40.802710606 +0100
>+++ gcc/testsuite/gcc.dg/tree-ssa/cswtch-5.c	2017-02-14
>17:13:59.424872889 +0100
>@@ -0,0 +1,66 @@
>+/* PR tree-optimization/79472 */
>+/* { dg-options "-O2 -fdump-tree-switchconv" } */
>+/* { dg-do compile } */
>+
>+void
>+foo (unsigned int v)
>+{
>+  const char *s;
>+  
>+  switch (v)
>+    {
>+    case 0:
>+      s = "foo";
>+      break;
>+    case 1:
>+      s = "bar";
>+      break;
>+    case 2:
>+      s = "spam";
>+      break;
>+    default:
>+      for (int i = 0; i < v; i++)
>+        __builtin_printf ("baz\n");
>+      return;
>+    }
>+
>+  __builtin_printf ("%s\n", s);
>+}
>+
>+int
>+bar (unsigned int v, int w)
>+{
>+  const char *s;
>+  
>+  switch (v)
>+    {
>+    case 0:
>+      s = "foo";
>+      break;
>+    case 1:
>+      s = "bar";
>+      break;
>+    case 2:
>+      s = "spam";
>+      break;
>+    default:
>+      __builtin_printf ("baz\n");
>+      if (v > 25)
>+	__builtin_printf ("bl1\n");
>+      else
>+	__builtin_printf ("bl2\n");
>+      goto lab;
>+    }
>+
>+  __builtin_printf ("%s\n", s);
>+  if (w > 25)
>+    __builtin_printf ("cl1\n");
>+  else
>+    __builtin_printf ("cl2\n");
>+ lab:
>+  __builtin_printf ("dl\n");
>+  return v + w;
>+}
>+
>+/* { dg-final { scan-tree-dump-times "Switch converted" 2 "switchconv"
>} } */
>+/* { dg-final { scan-tree-dump-times "= CSWTCH" 2 "switchconv" } } */
>
>	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]