#include "internal-fn.h"
#include "cgraph.h"
#include "tree-ssa.h"
+#include "gimple-range.h"
/* This pass propagates the RHS of assignment statements into use
sites of the LHS of the assignment. It's basically a specialized
((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1))))
((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
- transform these into (last 2 only if ranger can prove Y < B):
+ transform these into (last 2 only if ranger can prove Y < B
+ or Y = N * B):
X r<< Y
+ or
+ X r<< (& & (B - 1))
+ The latter for the forms with T2 wider than T if ranger can't prove Y < B.
Or for:
(X << (Y & (B - 1))) | (X >> ((-Y) & (B - 1)))
gimple *g;
gimple *def_arg_stmt[2] = { NULL, NULL };
int wider_prec = 0;
+ bool add_masking = false;
arg[0] = gimple_assign_rhs1 (stmt);
arg[1] = gimple_assign_rhs2 (stmt);
tree cdef_arg1[2], cdef_arg2[2], def_arg2_alt[2];
enum tree_code cdef_code[2];
gimple *def_arg_alt_stmt[2] = { NULL, NULL };
- bool check_range = false;
+ int check_range = 0;
gimple *check_range_stmt = NULL;
/* Look through conversion of the shift count argument.
The C/C++ FE cast any shift count argument to integer_type_node.
|| cdef_arg2[i] == def_arg2_alt[1 - i])
{
rotcnt = cdef_arg2[i];
+ check_range = -1;
+ if (cdef_arg2[i] == def_arg2[1 - i])
+ check_range_stmt = def_arg_stmt[1 - i];
+ else
+ check_range_stmt = def_arg_alt_stmt[1 - i];
break;
}
defcodefor_name (cdef_arg2[i], &code, &tem, NULL);
|| tem == def_arg2_alt[1 - i]))
{
rotcnt = tem;
+ check_range = -1;
+ if (tem == def_arg2[1 - i])
+ check_range_stmt = def_arg_stmt[1 - i];
+ else
+ check_range_stmt = def_arg_alt_stmt[1 - i];
break;
}
}
if (tem == def_arg2[1 - i] || tem == def_arg2_alt[1 - i])
{
rotcnt = tem;
- check_range = true;
+ check_range = 1;
if (tem == def_arg2[1 - i])
check_range_stmt = def_arg_stmt[1 - i];
else
|| tem2 == def_arg2_alt[1 - i])
{
rotcnt = tem2;
- check_range = true;
+ check_range = 1;
if (tem2 == def_arg2[1 - i])
check_range_stmt = def_arg_stmt[1 - i];
else
if (TREE_CODE (rotcnt) != SSA_NAME)
return false;
int_range_max r;
- if (!get_global_range_query ()->range_of_expr (r, rotcnt,
- check_range_stmt))
- return false;
+ range_query *q = get_range_query (cfun);
+ if (q == get_global_range_query ())
+ q = enable_ranger (cfun);
+ if (!q->range_of_expr (r, rotcnt, check_range_stmt))
+ {
+ if (check_range > 0)
+ return false;
+ r.set_varying (TREE_TYPE (rotcnt));
+ }
int prec = TYPE_PRECISION (TREE_TYPE (rotcnt));
signop sign = TYPE_SIGN (TREE_TYPE (rotcnt));
wide_int min = wide_int::from (TYPE_PRECISION (rtype), prec, sign);
wide_int max = wide_int::from (wider_prec - 1, prec, sign);
- int_range<2> r2 (TREE_TYPE (rotcnt), min, max);
+ if (check_range < 0)
+ max = min;
+ int_range<1> r2 (TREE_TYPE (rotcnt), min, max);
r.intersect (r2);
if (!r.undefined_p ())
- return false;
+ {
+ if (check_range > 0)
+ {
+ int_range_max r3;
+ for (int i = TYPE_PRECISION (rtype) + 1; i < wider_prec;
+ i += TYPE_PRECISION (rtype))
+ {
+ int j = i + TYPE_PRECISION (rtype) - 2;
+ min = wide_int::from (i, prec, sign);
+ max = wide_int::from (MIN (j, wider_prec - 1),
+ prec, sign);
+ int_range<1> r4 (TREE_TYPE (rotcnt), min, max);
+ r3.union_ (r4);
+ }
+ r.intersect (r3);
+ if (!r.undefined_p ())
+ return false;
+ }
+ add_masking = true;
+ }
}
if (rotcnt == NULL_TREE)
return false;
gsi_insert_before (gsi, g, GSI_SAME_STMT);
rotcnt = gimple_assign_lhs (g);
}
+ if (add_masking)
+ {
+ g = gimple_build_assign (make_ssa_name (TREE_TYPE (rotcnt)),
+ BIT_AND_EXPR, rotcnt,
+ build_int_cst (TREE_TYPE (rotcnt),
+ TYPE_PRECISION (rtype) - 1));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ rotcnt = gimple_assign_lhs (g);
+ }
lhs = gimple_assign_lhs (stmt);
if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
lhs = make_ssa_name (TREE_TYPE (def_arg1[0]));
cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
BITMAP_FREE (to_purge);
+ if (get_range_query (cfun) != get_global_range_query ())
+ disable_ranger (cfun);
+
if (cfg_changed)
todoflags |= TODO_cleanup_cfg;