]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Introduce access_ref::merge_ref.
authorMartin Sebor <msebor@redhat.com>
Mon, 6 Dec 2021 16:23:22 +0000 (09:23 -0700)
committerMartin Sebor <msebor@redhat.com>
Thu, 9 Dec 2021 16:51:47 +0000 (09:51 -0700)
gcc/ChangeLog:

* pointer-query.cc (access_ref::merge_ref): Define new function.
(access_ref::get_ref): Move code into merge_ref and call it.
* pointer-query.h (access_ref::merge_ref): Declare new function.

gcc/pointer-query.cc
gcc/pointer-query.h

index c75c4da6b600f5eb7c61e3c7667363002b8c6166..24fbac84ec4629bb2ddd4974550a3ce7f7214428 100644 (file)
@@ -624,6 +624,97 @@ access_ref::phi () const
   return as_a <gphi *> (def_stmt);
 }
 
+/* Determine the size and offset for ARG, append it to ALL_REFS, and
+   merge the result with *THIS.  Ignore ARG if SKIP_NULL is set and
+   ARG refers to the null pointer.  Return true on success and false
+   on failure.  */
+
+bool
+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)
+{
+  access_ref aref;
+  if (!compute_objsize_r (arg, stmt, ostype, &aref, snlim, &qry)
+      || aref.sizrng[0] < 0)
+    /* This may be a PHI with all null pointer arguments.  */
+    return false;
+
+  if (all_refs)
+    {
+      access_ref dummy_ref;
+      aref.get_ref (all_refs, &dummy_ref, ostype, &snlim, &qry);
+    }
+
+  if (TREE_CODE (arg) == SSA_NAME)
+    qry.put_ref (arg, aref, ostype);
+
+  if (all_refs)
+    all_refs->safe_push (aref);
+
+  aref.deref += deref;
+
+  bool merged_parmarray = aref.parmarray;
+
+  const bool nullp = skip_null && integer_zerop (arg);
+  const offset_int maxobjsize = wi::to_offset (max_object_size ());
+  offset_int minsize = sizrng[0];
+
+  if (sizrng[0] < 0)
+    {
+      /* If *THIS doesn't contain a meaningful result yet set it to AREF
+        unless the argument is null and it's okay to ignore it.  */
+      if (!nullp)
+       *this = aref;
+
+      /* Set if the current argument refers to one or more objects of
+        known size (or range of sizes), as opposed to referring to
+        one or more unknown object(s).  */
+      const bool arg_known_size = (aref.sizrng[0] != 0
+                                  || aref.sizrng[1] != maxobjsize);
+      if (arg_known_size)
+       sizrng[0] = aref.sizrng[0];
+
+      return true;
+    }
+
+  /* Disregard null pointers in PHIs with two or more arguments.
+     TODO: Handle this better!  */
+  if (nullp)
+    return true;
+
+  const bool known_size = (sizrng[0] != 0 || sizrng[1] != maxobjsize);
+
+  if (known_size && aref.sizrng[0] < minsize)
+    minsize = aref.sizrng[0];
+
+  /* Determine the amount of remaining space in the argument.  */
+  offset_int argrem[2];
+  argrem[1] = aref.size_remaining (argrem);
+
+  /* Determine the amount of remaining space computed so far and
+     if the remaining space in the argument is more use it instead.  */
+  offset_int merged_rem[2];
+  merged_rem[1] = size_remaining (merged_rem);
+
+  /* Reset the PHI's BASE0 flag if any of the nonnull arguments
+     refers to an object at an unknown offset.  */
+  if (!aref.base0)
+    base0 = false;
+
+  if (merged_rem[1] < argrem[1]
+      || (merged_rem[1] == argrem[1]
+         && sizrng[1] < aref.sizrng[1]))
+    /* Use the argument with the most space remaining as the result,
+       or the larger one if the space is equal.  */
+    *this = aref;
+
+  sizrng[0] = minsize;
+  parmarray = merged_parmarray;
+
+  return true;
+}
+
 /* Determine and return the largest object to which *THIS refers.  If
    *THIS refers to a PHI and PREF is nonnull, fill *PREF with the details
    of the object determined by compute_objsize(ARG, OSTYPE) for each PHI
@@ -636,9 +727,8 @@ access_ref::get_ref (vec<access_ref> *all_refs,
                     ssa_name_limit_t *psnlim /* = NULL */,
                     pointer_query *qry /* = NULL */) const
 {
-  gphi *phi_stmt = this->phi ();
-  if (!phi_stmt)
-    return ref;
+  if (!ref || TREE_CODE (ref) != SSA_NAME)
+    return NULL;
 
   /* FIXME: Calling get_ref() with a null PSNLIM is dangerous and might
      cause unbounded recursion.  */
@@ -646,13 +736,49 @@ access_ref::get_ref (vec<access_ref> *all_refs,
   if (!psnlim)
     psnlim = &snlim_buf;
 
-  if (!psnlim->visit_phi (ref))
-    return NULL_TREE;
-
   pointer_query empty_qry;
   if (!qry)
     qry = &empty_qry;
 
+  if (gimple *def_stmt = SSA_NAME_DEF_STMT (ref))
+    {
+      if (is_gimple_assign (def_stmt))
+       {
+         tree_code code = gimple_assign_rhs_code (def_stmt);
+         if (code != MIN_EXPR && code != MAX_EXPR)
+           return NULL_TREE;
+
+         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;
+
+         tree arg2 = gimple_assign_rhs2 (def_stmt);
+         if (!aref.merge_ref (all_refs, arg2, def_stmt, ostype, false,
+                              *psnlim, *qry))
+           return NULL_TREE;
+
+         if (pref && pref != this)
+           {
+             tree ref = pref->ref;
+             *pref = aref;
+             pref->ref = ref;
+           }
+
+         return aref.ref;
+       }
+    }
+  else
+    return NULL_TREE;
+
+  gphi *phi_stmt = this->phi ();
+  if (!phi_stmt)
+    return ref;
+
+  if (!psnlim->visit_phi (ref))
+    return NULL_TREE;
+
   /* The conservative result of the PHI reflecting the offset and size
      of the largest PHI argument, regardless of whether or not they all
      refer to the same object.  */
@@ -670,91 +796,17 @@ access_ref::get_ref (vec<access_ref> *all_refs,
       phi_ref = *pref;
     }
 
-  /* Set if any argument is a function array (or VLA) parameter not
-     declared [static].  */
-  bool parmarray = false;
-  /* The size of the smallest object referenced by the PHI arguments.  */
-  offset_int minsize = 0;
-  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 (!compute_objsize_r (arg, phi_stmt, ostype, &phi_arg_ref, *psnlim,
-                             qry)
-         || phi_arg_ref.sizrng[0] < 0)
-       /* A PHI with all null pointer arguments.  */
+      if (!phi_ref.merge_ref (all_refs, arg, phi_stmt, ostype, skip_null,
+                             *psnlim, *qry))
        return NULL_TREE;
-
-      if (TREE_CODE (arg) == SSA_NAME)
-       qry->put_ref (arg, phi_arg_ref);
-
-      if (all_refs)
-       all_refs->safe_push (phi_arg_ref);
-
-      parmarray |= phi_arg_ref.parmarray;
-
-      const bool nullp = integer_zerop (arg) && (i || i + 1 < nargs);
-
-      if (phi_ref.sizrng[0] < 0)
-       {
-         /* If PHI_REF doesn't contain a meaningful result yet set it
-            to the result for the first argument.  */
-         if (!nullp)
-           phi_ref = phi_arg_ref;
-
-         /* Set if the current argument refers to one or more objects of
-            known size (or range of sizes), as opposed to referring to
-            one or more unknown object(s).  */
-         const bool arg_known_size = (phi_arg_ref.sizrng[0] != 0
-                                      || phi_arg_ref.sizrng[1] != maxobjsize);
-         if (arg_known_size)
-           minsize = phi_arg_ref.sizrng[0];
-
-         continue;
-       }
-
-      const bool phi_known_size = (phi_ref.sizrng[0] != 0
-                                  || phi_ref.sizrng[1] != maxobjsize);
-
-      if (phi_known_size && phi_arg_ref.sizrng[0] < minsize)
-       minsize = phi_arg_ref.sizrng[0];
-
-      /* Disregard null pointers in PHIs with two or more arguments.
-        TODO: Handle this better!  */
-      if (nullp)
-       continue;
-
-      /* Determine the amount of remaining space in the argument.  */
-      offset_int argrem[2];
-      argrem[1] = phi_arg_ref.size_remaining (argrem);
-
-      /* Determine the amount of remaining space computed so far and
-        if the remaining space in the argument is more use it instead.  */
-      offset_int phirem[2];
-      phirem[1] = phi_ref.size_remaining (phirem);
-
-      /* Reset the PHI's BASE0 flag if any of the nonnull arguments
-        refers to an object at an unknown offset.  */
-      if (!phi_arg_ref.base0)
-       phi_ref.base0 = false;
-
-      if (phirem[1] < argrem[1]
-         || (phirem[1] == argrem[1]
-             && phi_ref.sizrng[1] < phi_arg_ref.sizrng[1]))
-       /* Use the argument with the most space remaining as the result,
-          or the larger one if the space is equal.  */
-       phi_ref = phi_arg_ref;
     }
 
-  /* Replace the lower bound of the largest argument with the size
-     of the smallest argument, and set PARMARRAY if any argument
-     was one.  */
-  phi_ref.sizrng[0] = minsize;
-  phi_ref.parmarray = parmarray;
-
   if (phi_ref.sizrng[0] < 0)
     {
       /* Fail if none of the PHI's arguments resulted in updating PHI_REF
@@ -766,7 +818,14 @@ access_ref::get_ref (vec<access_ref> *all_refs,
 
   /* Avoid changing *THIS.  */
   if (pref && pref != this)
-    *pref = phi_ref;
+    {
+      /* Keep the SSA_NAME of the PHI unchanged so that all PHI arguments
+        can be referred to later if necessary.  This is useful even if
+        they all refer to the same object.  */
+      tree ref = pref->ref;
+      *pref = phi_ref;
+      pref->ref = ref;
+    }
 
   psnlim->leave_phi (ref);
 
index cbc87c86ed3f3b4692482dc6b92165a522fc9425..fe46f711e96b415703aaa47f7ff917e499383ad0 100644 (file)
@@ -66,6 +66,10 @@ struct access_ref
   /* Return the PHI node REF refers to or null if it doesn't.  */
   gphi *phi () const;
 
+  /* Merge the result for a pointer with *THIS.  */
+  bool merge_ref (vec<access_ref> *all_refs, tree, gimple *, int, bool,
+                 ssa_name_limit_t &, pointer_query &);
+
   /* Return the object to which REF refers.  */
   tree get_ref (vec<access_ref> *, access_ref * = nullptr, int = 1,
                ssa_name_limit_t * = nullptr, pointer_query * = nullptr) const;