return f.fold_stmt (r, s, src);
}
+// Calculate op1 on statetemt S with LHS into range R using range query Q
+// to resolve any other operands.
+
+bool
+op1_range (vrange &r, gimple *s, const vrange &lhs, range_query *q)
+{
+ gimple_range_op_handler handler (s);
+ if (!handler)
+ return false;
+
+ fur_stmt src (s, q);
+
+ tree op2_expr = handler.operand2 ();
+ if (!op2_expr)
+ return handler.calc_op1 (r, lhs);
+
+ Value_Range op2 (TREE_TYPE (op2_expr));
+ if (!src.get_operand (op2, op2_expr))
+ return false;
+
+ return handler.calc_op1 (r, lhs, op2);
+}
+
+// Calculate op1 on statetemt S into range R using range query Q.
+// LHS is set to VARYING in this case.
+
+bool
+op1_range (vrange &r, gimple *s, range_query *q)
+{
+ tree lhs_type = gimple_range_type (s);
+ if (!lhs_type)
+ return false;
+ Value_Range lhs_range;
+ lhs_range.set_varying (lhs_type);
+ return op1_range (r, s, lhs_range, q);
+}
+
+// Calculate op2 on statetemt S with LHS into range R using range query Q
+// to resolve any other operands.
+
+bool
+op2_range (vrange &r, gimple *s, const vrange &lhs, range_query *q)
+{
+
+ gimple_range_op_handler handler (s);
+ if (!handler)
+ return false;
+
+ fur_stmt src (s, q);
+
+ Value_Range op1 (TREE_TYPE (handler.operand1 ()));
+ if (!src.get_operand (op1, handler.operand1 ()))
+ return false;
+
+ return handler.calc_op2 (r, lhs, op1);
+}
+
+// Calculate op2 on statetemt S into range R using range query Q.
+// LHS is set to VARYING in this case.
+
+bool
+op2_range (vrange &r, gimple *s, range_query *q)
+{
+ tree lhs_type = gimple_range_type (s);
+ if (!lhs_type)
+ return false;
+ Value_Range lhs_range;
+ lhs_range.set_varying (lhs_type);
+ return op2_range (r, s, lhs_range, q);
+}
+
// Provide a fur_source which can be used to determine any relations on
// a statement. It manages the callback from fold_using_ranges to determine
// a relation_trio for a statement.
bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector,
range_query *q = NULL);
+// Calculate op1 on stmt S.
+bool op1_range (vrange &, gimple *s, range_query *q = NULL);
+bool op1_range (vrange &, gimple *s, const vrange &lhs, range_query *q = NULL);
+// Calculate op2 on stmt S.
+bool op2_range (vrange &, gimple *s, range_query *q = NULL);
+bool op2_range (vrange &, gimple *s, const vrange &lhs, range_query *q = NULL);
+
// This routine will return a relation trio for stmt S.
relation_trio fold_relations (gimple *s, range_query *q = NULL);
void
gimple_infer_range::add_range (tree name, vrange &range)
{
+ // Do not add an inferred range if it is VARYING.
+ if (range.varying_p ())
+ return;
m_names[num_args] = name;
m_ranges[num_args] = range;
if (num_args < size_limit - 1)
// Process S for range inference and fill in the summary list.
// This is the routine where new inferred ranges should be added.
+// If USE_RANGEOPS is true, invoke range-ops on stmts with a single
+// ssa-name aa constant to reflect an inferred range. ie
+// x_2 = y_3 + 1 will provide an inferred range for y_3 of [-INF, +INF - 1].
+// This defaults to FALSE as it can be expensive.,
-gimple_infer_range::gimple_infer_range (gimple *s)
+gimple_infer_range::gimple_infer_range (gimple *s, bool use_rangeops)
{
num_args = 0;
walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore,
non_null_loadstore);
+ // Gated by flag.
+ if (!use_rangeops)
+ return;
+
+ // Check if there are any inferred ranges from range-ops.
+ gimple_range_op_handler handler (s);
+ if (!handler)
+ return;
+
+ // Only proceed if ONE operand is an SSA_NAME, This may provide an
+ // inferred range for 'y + 3' , but will bypass expressions like
+ // 'y + z' as it depends on symbolic values.
+ tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+ tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
+ if ((ssa1 != NULL) == (ssa2 != NULL))
+ return;
+
+ // The other operand should be a constant, so just use the global range
+ // query to pick up any other values.
+ if (ssa1)
+ {
+ Value_Range op1 (TREE_TYPE (ssa1));
+ if (op1_range (op1, s, get_global_range_query ()) && !op1.varying_p ())
+ add_range (ssa1, op1);
+ }
+ else
+ {
+ gcc_checking_assert (ssa2);
+ Value_Range op2 (TREE_TYPE (ssa2));
+ if (op2_range (op2, s, get_global_range_query ()) && !op2.varying_p ())
+ add_range (ssa2, op2);
+ }
}
// Create an single inferred range for NAMe using range R.
class gimple_infer_range
{
public:
- gimple_infer_range (gimple *s);
+ gimple_infer_range (gimple *s, bool use_rangeops = false);
gimple_infer_range (tree name, vrange &r);
inline unsigned num () const { return num_args; }
inline tree name (unsigned index) const