aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-scalar-evolution.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-scalar-evolution.c')
-rw-r--r--gcc/tree-scalar-evolution.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index 88a0eaa..d6f2a2f 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -1937,6 +1937,36 @@ interpret_rhs_expr (struct loop *loop, gimple *at_stmt,
res = chrec_convert (type, chrec1, at_stmt);
break;
+ case BIT_AND_EXPR:
+ /* Given int variable A, handle A&0xffff as (int)(unsigned short)A.
+ If A is SCEV and its value is in the range of representable set
+ of type unsigned short, the result expression is a (no-overflow)
+ SCEV. */
+ res = chrec_dont_know;
+ if (tree_fits_uhwi_p (rhs2))
+ {
+ int precision;
+ unsigned HOST_WIDE_INT val = tree_to_uhwi (rhs2);
+
+ val ++;
+ /* Skip if value of rhs2 wraps in unsigned HOST_WIDE_INT or
+ it's not the maximum value of a smaller type than rhs1. */
+ if (val != 0
+ && (precision = exact_log2 (val)) > 0
+ && (unsigned) precision < TYPE_PRECISION (TREE_TYPE (rhs1)))
+ {
+ tree utype = build_nonstandard_integer_type (precision, 1);
+
+ if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (rhs1)))
+ {
+ chrec1 = analyze_scalar_evolution (loop, rhs1);
+ chrec1 = chrec_convert (utype, chrec1, at_stmt);
+ res = chrec_convert (TREE_TYPE (rhs1), chrec1, at_stmt);
+ }
+ }
+ }
+ break;
+
default:
res = chrec_dont_know;
break;