From 242ea7e93aaa0a1a3f24d555ded71bf9da7e5c0d Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 22 Sep 2022 18:17:20 -0400 Subject: [PATCH 5/6] Refine ranges using relations in GORI. This allows GORI to recognize when a relation passed in applies to the 2 operands of the current statement. Check to see if further range refinement is possible before proceeding. * gimple-range-gori.cc (gori_compute::refine_using_relation): New. (gori_compute::compute_operand1_range): Invoke refine_using_relation when applicable. (gori_compute::compute_operand2_range): Ditto. * gimple-range-gori.h (class gori_compute): Adjust prototypes. --- gcc/gimple-range-gori.cc | 146 ++++++++++++++++++++++++++++++++++++++- gcc/gimple-range-gori.h | 3 + 2 files changed, 146 insertions(+), 3 deletions(-) diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 57a7e820749..b37d03cddda 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -934,6 +934,115 @@ gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range, 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. @@ -947,6 +1056,7 @@ gori_compute::compute_operand1_range (vrange &r, 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)); @@ -959,7 +1069,21 @@ gori_compute::compute_operand1_range (vrange &r, 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 @@ -967,7 +1091,7 @@ gori_compute::compute_operand1_range (vrange &r, // 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; } @@ -1030,6 +1154,7 @@ gori_compute::compute_operand2_range (vrange &r, 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)); @@ -1037,9 +1162,24 @@ gori_compute::compute_operand2_range (vrange &r, 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; diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index 1fff3e6255a..c7a32162a1b 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -166,6 +166,9 @@ public: bool has_edge_range_p (tree name, edge e); void dump (FILE *f); private: + bool refine_using_relation (tree op1, vrange &op1_range, + tree op2, vrange &op2_range, + fur_source &src, relation_kind k); bool may_recompute_p (tree name, edge e); bool may_recompute_p (tree name, basic_block bb = NULL); bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs, -- 2.37.3