src.get_operand (false_range, name);
}
+
+// This routine will try to refine the ranges of OP1 and OP2 given a relation
+// K between them. In order to perform this refinement, one of the operands
+// must be in the definition chain of the other. The use is refined using
+// op1/op2_range on the statement, and the defintion is then recalculated
+// using the relation.
+
+bool
+gori_compute::refine_using_relation (tree op1, vrange &op1_range,
+ tree op2, vrange &op2_range,
+ fur_source &src, relation_kind k)
+{
+ gcc_checking_assert (TREE_CODE (op1) == SSA_NAME);
+ gcc_checking_assert (TREE_CODE (op2) == SSA_NAME);
+ gcc_checking_assert (k != VREL_VARYING && k != VREL_UNDEFINED);
+
+ bool change = false;
+ bool op1_def_p = in_chain_p (op2, op1);
+ if (!op1_def_p)
+ if (!in_chain_p (op1, op2))
+ return false;
+
+ tree def_op = op1_def_p ? op1 : op2;
+ tree use_op = op1_def_p ? op2 : op1;
+
+ if (!op1_def_p)
+ k = relation_swap (k);
+
+ // op1_def is true if we want to look up op1, otherwise we want op2.
+ // if neither is the case, we returned in the above check.
+
+ gimple *def_stmt = SSA_NAME_DEF_STMT (def_op);
+ gimple_range_op_handler op_handler (def_stmt);
+ if (!op_handler)
+ return false;
+ tree def_op1 = op_handler.operand1 ();
+ tree def_op2 = op_handler.operand2 ();
+ // if the def isn't binary, the relation will not be useful.
+ if (!def_op2)
+ return false;
+
+ // Determine if op2 is directly referenced as an operand.
+ if (def_op1 == use_op)
+ {
+ // def_stmt has op1 in the 1st operand position.
+ Value_Range other_op (TREE_TYPE (def_op2));
+ src.get_operand (other_op, def_op2);
+
+ // Using op1_range as the LHS, and relation REL, evaluate op2.
+ tree type = TREE_TYPE (def_op1);
+ Value_Range new_result (type);
+ if (!op_handler.op1_range (new_result, type,
+ op1_def_p ? op1_range : op2_range,
+ other_op, k))
+ return false;
+ if (op1_def_p)
+ {
+ change |= op2_range.intersect (new_result);
+ // Recalculate op2.
+ if (op_handler.fold_range (new_result, type, op2_range, other_op))
+ {
+ change |= op1_range.intersect (new_result);
+ }
+ }
+ else
+ {
+ change |= op1_range.intersect (new_result);
+ // Recalculate op1.
+ if (op_handler.fold_range (new_result, type, op1_range, other_op))
+ {
+ change |= op2_range.intersect (new_result);
+ }
+ }
+ }
+ else if (def_op2 == use_op)
+ {
+ // def_stmt has op1 in the 1st operand position.
+ Value_Range other_op (TREE_TYPE (def_op1));
+ src.get_operand (other_op, def_op1);
+
+ // Using op1_range as the LHS, and relation REL, evaluate op2.
+ tree type = TREE_TYPE (def_op2);
+ Value_Range new_result (type);
+ if (!op_handler.op2_range (new_result, type,
+ op1_def_p ? op1_range : op2_range,
+ other_op, k))
+ return false;
+ if (op1_def_p)
+ {
+ change |= op2_range.intersect (new_result);
+ // Recalculate op1.
+ if (op_handler.fold_range (new_result, type, other_op, op2_range))
+ {
+ change |= op1_range.intersect (new_result);
+ }
+ }
+ else
+ {
+ change |= op1_range.intersect (new_result);
+ // Recalculate op2.
+ if (op_handler.fold_range (new_result, type, other_op, op1_range))
+ {
+ change |= op2_range.intersect (new_result);
+ }
+ }
+ }
+ return change;
+}
+
// Calculate a range for NAME from the operand 1 position of STMT
// assuming the result of the statement is LHS. Return the range in
// R, or false if no range could be calculated.
gimple *stmt = handler.stmt ();
tree op1 = handler.operand1 ();
tree op2 = handler.operand2 ();
+ tree lhs_name = gimple_get_lhs (stmt);
Value_Range op1_range (TREE_TYPE (op1));
Value_Range tmp (TREE_TYPE (op1));
if (op2)
{
src.get_operand (op2_range, op2);
- if (!handler.calc_op1 (tmp, lhs, op2_range))
+ relation_kind k = VREL_VARYING;
+ if (rel)
+ {
+ if (lhs_name == rel->op1 () && op1 == rel->op2 ())
+ k = rel->kind ();
+ else if (lhs_name == rel->op2 () && op1 == rel->op1 ())
+ k = relation_swap (rel->kind ());
+ else if (op1 == rel->op1 () && op2 == rel->op2 ())
+ refine_using_relation (op1, op1_range, op2, op2_range, src,
+ rel->kind ());
+ else if (op1 == rel->op2 () && op2 == rel->op1 ())
+ refine_using_relation (op1, op1_range, op2, op2_range, src,
+ relation_swap (rel->kind ()));
+ }
+ if (!handler.calc_op1 (tmp, lhs, op2_range, k))
return false;
}
else
// We pass op1_range to the unary operation. Nomally it's a
// hidden range_for_type parameter, but sometimes having the
// actual range can result in better information.
- if (!handler.calc_op1 (tmp, lhs, op1_range))
+ if (!handler.calc_op1 (tmp, lhs, op1_range, VREL_VARYING))
return false;
}
gimple *stmt = handler.stmt ();
tree op1 = handler.operand1 ();
tree op2 = handler.operand2 ();
+ tree lhs_name = gimple_get_lhs (stmt);
Value_Range op1_range (TREE_TYPE (op1));
Value_Range op2_range (TREE_TYPE (op2));
src.get_operand (op1_range, op1);
src.get_operand (op2_range, op2);
+ relation_kind k = VREL_VARYING;
+ if (rel)
+ {
+ if (lhs_name == rel->op1 () && op2 == rel->op2 ())
+ k = rel->kind ();
+ else if (lhs_name == rel->op2 () && op2 == rel->op1 ())
+ k = relation_swap (rel->kind ());
+ else if (op1 == rel->op1 () && op2 == rel->op2 ())
+ refine_using_relation (op1, op1_range, op2, op2_range, src,
+ rel->kind ());
+ else if (op1 == rel->op2 () && op2 == rel->op1 ())
+ refine_using_relation (op1, op1_range, op2, op2_range, src,
+ relation_swap (rel->kind ()));
+ }
+
// Intersect with range for op2 based on lhs and op1.
- if (!handler.calc_op2 (tmp, lhs, op1_range))
+ if (!handler.calc_op2 (tmp, lhs, op1_range, k))
return false;
unsigned idx;