[PATCH] Avoid more casts of switch values

Richard Biener rguenther@suse.de
Wed Mar 26 11:56:00 GMT 2014


This avoids the (int) cast for switches on enums (which are
appearantly using an unsigned type in C++).  It does so by
enhancing the code in simplify_gimple_switch to see if the
case value checks are preserved with a sign-change.

Bootstrap / regtest running on x86_64-unkown-linux-gnu, queued for stage1.

Richard.

2014-03-26  Richard Biener  <rguenther@suse.de>

	* tree-ssa-forwprop.c (simplify_gimple_switch): Enhance
	check for which sign-changes we allow when forwarding
	a converted value into a switch.

	* g++.dg/tree-ssa/forwprop-switch.C: New testcase.

Index: gcc/tree-ssa-forwprop.c
===================================================================
*** gcc/tree-ssa-forwprop.c	(revision 208812)
--- gcc/tree-ssa-forwprop.c	(working copy)
*************** simplify_gimple_switch_label_vec (gimple
*** 1356,1398 ****
  static bool
  simplify_gimple_switch (gimple stmt)
  {
-   tree cond = gimple_switch_index (stmt);
-   tree def, to, ti;
-   gimple def_stmt;
- 
    /* The optimization that we really care about is removing unnecessary
       casts.  That will let us do much better in propagating the inferred
       constant at the switch target.  */
    if (TREE_CODE (cond) == SSA_NAME)
      {
!       def_stmt = SSA_NAME_DEF_STMT (cond);
!       if (is_gimple_assign (def_stmt))
  	{
! 	  if (gimple_assign_rhs_code (def_stmt) == NOP_EXPR)
! 	    {
! 	      int need_precision;
! 	      bool fail;
! 
! 	      def = gimple_assign_rhs1 (def_stmt);
  
! 	      to = TREE_TYPE (cond);
! 	      ti = TREE_TYPE (def);
! 
! 	      /* If we have an extension that preserves value, then we
! 		 can copy the source value into the switch.  */
! 
! 	      need_precision = TYPE_PRECISION (ti);
! 	      fail = false;
! 	      if (! INTEGRAL_TYPE_P (ti))
! 		fail = true;
! 	      else if (TYPE_UNSIGNED (to) && !TYPE_UNSIGNED (ti))
! 		fail = true;
! 	      else if (!TYPE_UNSIGNED (to) && TYPE_UNSIGNED (ti))
! 		need_precision += 1;
! 	      if (TYPE_PRECISION (to) < need_precision)
! 		fail = true;
! 
! 	      if (!fail)
  		{
  		  gimple_switch_set_index (stmt, def);
  		  simplify_gimple_switch_label_vec (stmt, ti);
--- 1356,1391 ----
  static bool
  simplify_gimple_switch (gimple stmt)
  {
    /* The optimization that we really care about is removing unnecessary
       casts.  That will let us do much better in propagating the inferred
       constant at the switch target.  */
+   tree cond = gimple_switch_index (stmt);
    if (TREE_CODE (cond) == SSA_NAME)
      {
!       gimple def_stmt = SSA_NAME_DEF_STMT (cond);
!       if (gimple_assign_cast_p (def_stmt))
  	{
! 	  tree def = gimple_assign_rhs1 (def_stmt);
! 	  tree ti = TREE_TYPE (def);
  
! 	  /* If we have an extension or sign-change that preserves the
! 	     values we check against then we can copy the source value into
! 	     the switch.  */
! 	  if (INTEGRAL_TYPE_P (ti)
! 	      && TYPE_PRECISION (ti) <= TYPE_PRECISION (TREE_TYPE (cond)))
! 	    {
! 	      size_t n = gimple_switch_num_labels (stmt);
! 	      tree min = NULL_TREE, max = NULL_TREE;
! 	      if (n > 1)
! 		{
! 		  min = CASE_LOW (gimple_switch_label (stmt, 1));
! 		  if (CASE_HIGH (gimple_switch_label (stmt, n - 1)))
! 		    max = CASE_HIGH (gimple_switch_label (stmt, n - 1));
! 		  else
! 		    max = CASE_LOW (gimple_switch_label (stmt, n - 1));
! 		}
! 	      if ((!min || int_fits_type_p (min, ti))
! 		  && (!max || int_fits_type_p (max, ti)))
  		{
  		  gimple_switch_set_index (stmt, def);
  		  simplify_gimple_switch_label_vec (stmt, ti);
Index: gcc/testsuite/g++.dg/tree-ssa/forwprop-switch.C
===================================================================
*** gcc/testsuite/g++.dg/tree-ssa/forwprop-switch.C	(revision 0)
--- gcc/testsuite/g++.dg/tree-ssa/forwprop-switch.C	(working copy)
***************
*** 0 ****
--- 1,24 ----
+ // { dg-do compile }
+ // { dg-options "-O -fdump-tree-cddce1" }
+ 
+ enum Scale  { E1, E2, E3, E4, E5, E6, E7, E8 };
+ 
+ int Test(Scale s)
+ { 
+   switch(s)
+     {
+       case E1: return 12;
+       case E2: return 17;
+       case E3: return 22;
+       case E4: return 42;
+       default:  break;
+     }
+   return 0;
+ }
+ 
+ // tree forwprop should have eliminated the (int) s cast for the
+ // switch value and directly switch on the 's' parameter
+ 
+ // { dg-final { scan-tree-dump-not "\\\(int\\\)" "cddce1" } }
+ // { dg-final { scan-tree-dump "switch \\\(s_.\\\(D\\\)\\\)" "cddce1" } }
+ // { dg-final { cleanup-tree-dump "cddce1" } }



More information about the Gcc-patches mailing list