Avoid recomputing PHI results after failure (PR104203).
authorMartin Sebor <msebor@redhat.com>
Tue, 25 Jan 2022 21:20:51 +0000 (14:20 -0700)
committerMartin Sebor <msebor@redhat.com>
Tue, 25 Jan 2022 21:22:49 +0000 (14:22 -0700)
Resolves:
PR tree-optimization/104203 - huge compile-time regression in pointer_query

gcc/ChangeLog:

PR tree-optimization/104203
* gimple-ssa-warn-access.cc (pass_data pass_data_waccess): Use
TV_WARN_ACCESS.
* pointer-query.cc (access_ref::merge_ref): Change return type.
Convert failure to a conservative success.
(access_ref::get_ref): Adjust to the change above.  Short-circuit
PHI evaluation after first failure turned into conservative success.
* pointer-query.h (access_ref::merge_ref): Change return type.
* timevar.def (TV_WARN_ACCESS): New timer variable.

gcc/gimple-ssa-warn-access.cc
gcc/pointer-query.cc
gcc/pointer-query.h
gcc/timevar.def

index 8bc33ee..afcf0f7 100644 (file)
@@ -2053,7 +2053,7 @@ const pass_data pass_data_waccess = {
   GIMPLE_PASS,
   "waccess",
   OPTGROUP_NONE,
-  TV_NONE,
+  TV_WARN_ACCESS, /* timer variable */
   PROP_cfg, /* properties_required  */
   0,       /* properties_provided  */
   0,       /* properties_destroyed  */
index 5b723e9..b092ef4 100644 (file)
@@ -629,7 +629,7 @@ access_ref::phi () const
    ARG refers to the null pointer.  Return true on success and false
    on failure.  */
 
-bool
+void
 access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
                       int ostype, bool skip_null,
                       ssa_name_limit_t &snlim, pointer_query &qry)
@@ -637,8 +637,16 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
   access_ref aref;
   if (!compute_objsize_r (arg, stmt, false, ostype, &aref, snlim, &qry)
       || aref.sizrng[0] < 0)
-    /* This may be a PHI with all null pointer arguments.  */
-    return false;
+    {
+      /* This may be a PHI with all null pointer arguments.  Handle it
+        conservatively by setting all properties to the most permissive
+        values. */
+      base0 = false;
+      offrng[0] = offrng[1] = 0;
+      add_max_offset ();
+      set_max_size_range ();
+      return;
+    }
 
   if (all_refs)
     {
@@ -675,13 +683,13 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
       if (arg_known_size)
        sizrng[0] = aref.sizrng[0];
 
-      return true;
+      return;
     }
 
   /* Disregard null pointers in PHIs with two or more arguments.
      TODO: Handle this better!  */
   if (nullp)
-    return true;
+    return;
 
   const bool known_size = (sizrng[0] != 0 || sizrng[1] != maxobjsize);
 
@@ -717,7 +725,7 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
   sizrng[0] = minsize;
   parmarray = merged_parmarray;
 
-  return true;
+  return;
 }
 
 /* Determine and return the largest object to which *THIS refers.  If
@@ -755,14 +763,12 @@ access_ref::get_ref (vec<access_ref> *all_refs,
 
          access_ref aref;
          tree arg1 = gimple_assign_rhs1 (def_stmt);
-         if (!aref.merge_ref (all_refs, arg1, def_stmt, ostype, false,
-                              *psnlim, *qry))
-           return NULL_TREE;
+         aref.merge_ref (all_refs, arg1, def_stmt, ostype, false,
+                         *psnlim, *qry);
 
          tree arg2 = gimple_assign_rhs2 (def_stmt);
-         if (!aref.merge_ref (all_refs, arg2, def_stmt, ostype, false,
-                              *psnlim, *qry))
-           return NULL_TREE;
+         aref.merge_ref (all_refs, arg2, def_stmt, ostype, false,
+                         *psnlim, *qry);
 
          if (pref && pref != this)
            {
@@ -801,15 +807,23 @@ access_ref::get_ref (vec<access_ref> *all_refs,
       phi_ref = *pref;
     }
 
+  const offset_int maxobjsize = wi::to_offset (max_object_size ());
   const unsigned nargs = gimple_phi_num_args (phi_stmt);
   for (unsigned i = 0; i < nargs; ++i)
     {
       access_ref phi_arg_ref;
       bool skip_null = i || i + 1 < nargs;
       tree arg = gimple_phi_arg_def (phi_stmt, i);
-      if (!phi_ref.merge_ref (all_refs, arg, phi_stmt, ostype, skip_null,
-                             *psnlim, *qry))
-       return NULL_TREE;
+      phi_ref.merge_ref (all_refs, arg, phi_stmt, ostype, skip_null,
+                        *psnlim, *qry);
+
+      if (!phi_ref.base0
+         && phi_ref.sizrng[0] == 0
+         && phi_ref.sizrng[1] >= maxobjsize)
+       /* When an argument results in the most permissive result,
+          the remaining arguments cannot constrain it.  Short-circuit
+          the evaluation.  */
+       break;
     }
 
   if (phi_ref.sizrng[0] < 0)
index 7dc965b..dbdcd59 100644 (file)
@@ -67,7 +67,7 @@ struct access_ref
   gphi *phi () const;
 
   /* Merge the result for a pointer with *THIS.  */
-  bool merge_ref (vec<access_ref> *all_refs, tree, gimple *, int, bool,
+  void merge_ref (vec<access_ref> *all_refs, tree, gimple *, int, bool,
                  ssa_name_limit_t &, pointer_query &);
 
   /* Return the object to which REF refers.  */
index c239e8e..2dae5e1 100644 (file)
@@ -307,6 +307,7 @@ DEFTIMEVAR (TV_TREE_UBSAN            , "tree ubsan")
 DEFTIMEVAR (TV_INITIALIZE_RTL        , "initialize rtl")
 DEFTIMEVAR (TV_GIMPLE_LADDRESS       , "address lowering")
 DEFTIMEVAR (TV_TREE_LOOP_IFCVT       , "tree loop if-conversion")
+DEFTIMEVAR (TV_WARN_ACCESS           , "access analysis")
 
 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_EARLY_LOCAL          , "early local passes")