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

Reply via email to