diff options
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 4a018f73c17..d3922db038a 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -1,5 +1,5 @@ /* Support routines for Value Range Propagation (VRP). - Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Diego Novillo <dnovillo@redhat.com>. @@ -4462,6 +4462,93 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi, } } + /* Similarly add asserts for NAME == CST and NAME being defined as + NAME = NAME2 >> CST2. */ + if (TREE_CODE_CLASS (comp_code) == tcc_comparison + && TREE_CODE (val) == INTEGER_CST) + { + gimple def_stmt = SSA_NAME_DEF_STMT (name); + tree name2 = NULL_TREE, cst2 = NULL_TREE; + tree val2 = NULL_TREE; + unsigned HOST_WIDE_INT mask[2] = { 0, 0 }; + + /* Extract CST2 from the right shift. */ + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == RSHIFT_EXPR) + { + name2 = gimple_assign_rhs1 (def_stmt); + cst2 = gimple_assign_rhs2 (def_stmt); + if (TREE_CODE (name2) == SSA_NAME + && host_integerp (cst2, 1) + && (unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1) + < 2 * HOST_BITS_PER_WIDE_INT + && INTEGRAL_TYPE_P (TREE_TYPE (name2)) + && live_on_edge (e, name2) + && !has_single_use (name2)) + { + if ((unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1) + < HOST_BITS_PER_WIDE_INT) + mask[0] = ((unsigned HOST_WIDE_INT) 1 + << tree_low_cst (cst2, 1)) - 1; + else + { + mask[1] = ((unsigned HOST_WIDE_INT) 1 + << (tree_low_cst (cst2, 1) + - HOST_BITS_PER_WIDE_INT)) - 1; + mask[0] = -1; + } + val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2); + } + } + + if (val2 != NULL_TREE + && TREE_CODE (val2) == INTEGER_CST + && simple_cst_equal (fold_build2 (RSHIFT_EXPR, + TREE_TYPE (val), + val2, cst2), val)) + { + enum tree_code new_comp_code = comp_code; + tree tmp, new_val; + + tmp = name2; + if (comp_code == EQ_EXPR || comp_code == NE_EXPR) + { + if (!TYPE_UNSIGNED (TREE_TYPE (val))) + { + unsigned int prec = TYPE_PRECISION (TREE_TYPE (val)); + tree type = build_nonstandard_integer_type (prec, 1); + tmp = build1 (NOP_EXPR, type, name2); + val2 = fold_convert (type, val2); + } + tmp = fold_build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp, val2); + new_val = build_int_cst_wide (TREE_TYPE (tmp), mask[0], mask[1]); + new_comp_code = comp_code == EQ_EXPR ? LE_EXPR : GT_EXPR; + } + else if (comp_code == LT_EXPR || comp_code == GE_EXPR) + new_val = val2; + else + { + new_val = build_int_cst_wide (TREE_TYPE (val2), + mask[0], mask[1]); + new_val = fold_binary (BIT_IOR_EXPR, TREE_TYPE (val2), + val2, new_val); + } + + if (dump_file) + { + fprintf (dump_file, "Adding assert for "); + print_generic_expr (dump_file, name2, 0); + fprintf (dump_file, " from "); + print_generic_expr (dump_file, tmp, 0); + fprintf (dump_file, "\n"); + } + + register_new_assert_for (name2, tmp, new_comp_code, new_val, + NULL, e, bsi); + retval = true; + } + } + return retval; } |