Use GORI to evaluate arguments of a COND_EXPR.
authorAndrew MacLeod <amacleod@redhat.com>
Tue, 15 Feb 2022 00:43:40 +0000 (19:43 -0500)
committerAndrew MacLeod <amacleod@redhat.com>
Tue, 15 Feb 2022 22:03:27 +0000 (17:03 -0500)
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.

gcc/gimple-range-fold.cc
gcc/gimple-range-gori.cc
gcc/gimple-range-gori.h
gcc/testsuite/gcc.dg/pr104526.c [new file with mode: 0644]

index 5133a43..2fc8376 100644 (file)
@@ -1270,6 +1270,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 ())
     {
index 3e53283..258da6e 100644 (file)
@@ -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,100 @@ 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;
+  tree type = TREE_TYPE (TREE_OPERAND (cond, 0));
+  if (type != TREE_TYPE (TREE_OPERAND (cond, 1)))
+    return false;
+  range_operator *hand = range_op_handler (TREE_CODE (cond), type);
+  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)
+    {
+      if (!hand->op1_range (cond_false, type, m_bool_zero, cr))
+       return false;
+      if (!hand->op1_range (cond_true, type, m_bool_one, cr))
+       return false;
+      cond_false.intersect (cl);
+      cond_true.intersect (cl);
+    }
+  else
+    {
+      if (!hand->op2_range (cond_false, type, m_bool_zero, cl))
+       return false;
+      if (!hand->op2_range (cond_true, type, 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
index b799a84..605884e 100644 (file)
@@ -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);
diff --git a/gcc/testsuite/gcc.dg/pr104526.c b/gcc/testsuite/gcc.dg/pr104526.c
new file mode 100644 (file)
index 0000000..a295308
--- /dev/null
@@ -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" } } */