--- /dev/null
+// { 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" } }
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. */
+ tree cond = gimple_switch_index (stmt);
if (TREE_CODE (cond) == SSA_NAME)
{
- def_stmt = SSA_NAME_DEF_STMT (cond);
- if (is_gimple_assign (def_stmt))
+ gimple def_stmt = SSA_NAME_DEF_STMT (cond);
+ if (gimple_assign_cast_p (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;
+ tree def = gimple_assign_rhs1 (def_stmt);
+ if (TREE_CODE (def) != SSA_NAME)
+ return false;
- if (!fail)
+ /* 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. */
+ tree ti = TREE_TYPE (def);
+ 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);