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" } }