commit 496e3d19a8570d4d62a64bd540ce86bc1ddef219
Author: Andrew MacLeod <amacleod@redhat.com>
Date: Mon Feb 14 19:43:40 2022 -0500
Use GORI to evaluate arguments of a COND_EXPR.
Provide an API into gori to perform a basic evaluation of the arguments of a
COND_EXPR if they are in the dependency chain of the condition.
PR tree-optimization/104526
gcc/
* gimple-range-fold.cc (fold_using_range::range_of_cond_expr): Call
new routine.
* gimple-range-gori.cc (range_def_chain::get_def_chain): Force a build
of dependency chain if there isn't one.
(gori_compute::condexpr_adjust): New.
* gimple-range-gori.h (class gori_compute): New prototype.
gcc/testsuite/
* gcc.dg/pr104526.c: New.
@@ -1273,6 +1273,18 @@ fold_using_range::range_of_cond_expr (irange &r, gassign *s, fur_source &src)
src.get_operand (range1, op1);
src.get_operand (range2, op2);
+ // Try to see if there is a dependence between the COND and either operand
+ if (src.gori ())
+ if (src.gori ()->condexpr_adjust (range1, range2, s, cond, op1, op2, src))
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Possible COND_EXPR adjustment. Range op1 : ");
+ range1.dump(dump_file);
+ fprintf (dump_file, " and Range op2: ");
+ range2.dump(dump_file);
+ fprintf (dump_file, "\n");
+ }
+
// If the condition is known, choose the appropriate expression.
if (cond_range.singleton_p ())
{
@@ -334,7 +334,7 @@ range_def_chain::get_def_chain (tree name)
unsigned v = SSA_NAME_VERSION (name);
// If it has already been processed, just return the cached value.
- if (has_def_chain (name))
+ if (has_def_chain (name) && m_def_chain[v].bm)
return m_def_chain[v].bm;
// No definition chain for default defs.
@@ -1303,6 +1303,99 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
return false;
}
+// Given COND ? OP1 : OP2 with ranges R1 for OP1 and R2 for OP2, Use gori
+// to further resolve R1 and R2 if there are any dependencies between
+// OP1 and COND or OP2 and COND. All values can are to be calculated using SRC
+// as the origination source location for operands..
+// Effectively, use COND an the edge condition and solve for OP1 on the true
+// edge and OP2 on the false edge.
+
+bool
+gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
+ tree op1, tree op2, fur_source &src)
+{
+ int_range_max tmp, cond_true, cond_false;
+ tree ssa1 = gimple_range_ssa_p (op1);
+ tree ssa2 = gimple_range_ssa_p (op2);
+ if (!ssa1 && !ssa2)
+ return false;
+ if (!COMPARISON_CLASS_P (cond))
+ return false;
+ range_operator *hand = range_op_handler (TREE_CODE (cond), TREE_TYPE (op1));
+ if (!hand)
+ return false;
+
+ tree c1 = gimple_range_ssa_p (TREE_OPERAND (cond, 0));
+ tree c2 = gimple_range_ssa_p (TREE_OPERAND (cond, 1));
+
+ // Only solve if there is one SSA name in the condition.
+ if ((!c1 && !c2) || (c1 && c2))
+ return false;
+
+ // Pick up the current values of each part of the condition.
+ int_range_max cl, cr;
+ src.get_operand (cl, TREE_OPERAND (cond, 0));
+ src.get_operand (cr, TREE_OPERAND (cond, 1));
+
+ tree cond_name = c1 ? c1 : c2;
+ gimple *def_stmt = SSA_NAME_DEF_STMT (cond_name);
+
+ // Evaluate the value of COND_NAME on the true and false edges, using either
+ // the op1 or op2 routines based on its location.
+ if (c1)
+ {
+ tree t = TREE_TYPE (TREE_OPERAND (cond, 0));
+ if (!hand->op1_range (cond_false, t, m_bool_zero, cr))
+ return false;
+ if (!hand->op1_range (cond_true, t, m_bool_one, cr))
+ return false;
+ cond_false.intersect (cl);
+ cond_true.intersect (cl);
+ }
+ else
+ {
+ tree t = TREE_TYPE (TREE_OPERAND (cond, 1));
+ if (!hand->op2_range (cond_false, t, m_bool_zero, cl))
+ return false;
+ if (!hand->op2_range (cond_true, t, m_bool_one, cl))
+ return false;
+ cond_false.intersect (cr);
+ cond_true.intersect (cr);
+ }
+
+ unsigned idx;
+ if ((idx = tracer.header ("cond_expr evaluation : ")))
+ {
+ fprintf (dump_file, " range1 = ");
+ r1.dump (dump_file);
+ fprintf (dump_file, ", range2 = ");
+ r1.dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+
+ // Now solve for SSA1 or SSA2 if they are in the dependency chain.
+ if (ssa1 && in_chain_p (ssa1, cond_name))
+ {
+ if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src))
+ r1.intersect (tmp);
+ }
+ if (ssa2 && in_chain_p (ssa2, cond_name))
+ {
+ if (compute_operand_range (tmp, def_stmt, cond_false, ssa2, src))
+ r2.intersect (tmp);
+ }
+ if (idx)
+ {
+ tracer.print (idx, "outgoing: range1 = ");
+ r1.dump (dump_file);
+ fprintf (dump_file, ", range2 = ");
+ r1.dump (dump_file);
+ fprintf (dump_file, "\n");
+ tracer.trailer (idx, "cond_expr", true, cond_name, cond_true);
+ }
+ return true;
+}
+
// Dump what is known to GORI computes to listing file F.
void
@@ -158,6 +158,8 @@ class gori_compute : public gori_map
public:
gori_compute (int not_executable_flag = 0);
bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q);
+ bool condexpr_adjust (irange &r1, irange &r2, gimple *s, tree cond, tree op1,
+ tree op2, fur_source &src);
bool has_edge_range_p (tree name, basic_block bb = NULL);
bool has_edge_range_p (tree name, edge e);
void dump (FILE *f);
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo(void);
+
+static int a, b = 1, *c = &b;
+int main() {
+ for (; a; a--) {
+ int d = 2 >> (1 / *c);
+ if (!d)
+ foo();
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "foo" "evrp" } } */