From: Yury Gribov Date: Tue, 13 Jun 2017 11:16:15 +0000 (+0000) Subject: tree-vrp.c (is_masked_range_test): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=df06757229f5824ec4e9fc365843cf6f857d4da8;p=gcc.git tree-vrp.c (is_masked_range_test): New function. 2017-06-13 Yury Gribov gcc/ * tree-vrp.c (is_masked_range_test): New function. (register_edge_assert_for): Determine ranges for some bit tests. From-SVN: r249150 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 83f048001fa..4567036291c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-06-13 Yury Gribov + + * tree-vrp.c (is_masked_range_test): New function. + (register_edge_assert_for): Determine ranges for + some bit tests. + 2017-06-13 Yury Gribov PR tree-optimization/67328 diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 716a7c285b3..a7424a3f8e2 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -5628,6 +5628,82 @@ register_edge_assert_for_1 (tree op, enum tree_code code, } } +/* Check if comparison + NAME COND_OP INTEGER_CST + has a form of + (X & 11...100..0) COND_OP XX...X00...0 + Such comparison can yield assertions like + X >= XX...X00...0 + X <= XX...X11...1 + in case of COND_OP being NE_EXPR or + X < XX...X00...0 + X > XX...X11...1 + in case of EQ_EXPR. */ + +static bool +is_masked_range_test (tree name, tree valt, enum tree_code cond_code, + tree *new_name, tree *low, enum tree_code *low_code, + tree *high, enum tree_code *high_code) +{ + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + + if (!is_gimple_assign (def_stmt) + || gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR) + return false; + + tree maskt = gimple_assign_rhs2 (def_stmt); + if (TREE_CODE (maskt) != INTEGER_CST) + return false; + + wide_int mask = maskt; + wide_int inv_mask = ~mask; + wide_int val = valt; // Assume VALT is INTEGER_CST + + if ((inv_mask & (inv_mask + 1)) != 0 + || (val & mask) != val) + return false; + + tree t = gimple_assign_rhs1 (def_stmt); + tree type = TREE_TYPE (t); + + bool is_range = cond_code == EQ_EXPR; + + wide_int min = wi::min_value (type), + max = wi::max_value (type); + + if (is_range) + { + *low_code = val == min ? ERROR_MARK : GE_EXPR; + *high_code = val == max ? ERROR_MARK : LE_EXPR; + } + else + { + /* We can still generate assertion if one of alternatives + is known to always be false. */ + if (val == min) + { + *low_code = (enum tree_code) 0; + *high_code = GT_EXPR; + } + else if ((val | inv_mask) == max) + { + *low_code = LT_EXPR; + *high_code = (enum tree_code) 0; + } + else + return false; + } + + *new_name = t; + *low = wide_int_to_tree (type, val); + *high = wide_int_to_tree (type, val | inv_mask); + + if (wi::neg_p (val, TYPE_SIGN (type))) + std::swap (*low, *high); + + return true; +} + /* Try to register an edge assertion for SSA name NAME on edge E for the condition COND contributing to the conditional jump pointed to by SI. */ @@ -5700,6 +5776,24 @@ register_edge_assert_for (tree name, edge e, register_edge_assert_for_1 (op1, EQ_EXPR, e, asserts); } } + + /* Sometimes we can infer ranges from (NAME & MASK) == VALUE. */ + if ((comp_code == EQ_EXPR || comp_code == NE_EXPR) + && TREE_CODE (val) == INTEGER_CST) + { + enum tree_code low_code, high_code; + tree low, high; + if (is_masked_range_test (name, val, comp_code, &name, &low, + &low_code, &high, &high_code)) + { + if (low_code != ERROR_MARK) + register_edge_assert_for_2 (name, e, low_code, name, + low, /*invert*/false, asserts); + if (high_code != ERROR_MARK) + register_edge_assert_for_2 (name, e, high_code, name, + high, /*invert*/false, asserts); + } + } } /* Finish found ASSERTS for E and register them at GSI. */