aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r--gcc/tree-vrp.c89
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;
}