https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92765

--- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Untested patch to fix all these wrong-code issues would be something like:
--- gcc/tree-ssa-strlen.c.jj    2019-11-28 09:35:32.443298424 +0100
+++ gcc/tree-ssa-strlen.c       2019-12-03 17:02:32.131658020 +0100
@@ -3473,54 +3473,30 @@ compute_string_length (int idx)
 static unsigned HOST_WIDE_INT
 determine_min_objsize (tree dest)
 {
-  unsigned HOST_WIDE_INT size = 0;
+  unsigned HOST_WIDE_INT size;

   init_object_sizes ();

   if (compute_builtin_object_size (dest, 2, &size))
     return size;

-  /* Try to determine the size of the object through the RHS
-     of the assign statement.  */
-  if (TREE_CODE (dest) == SSA_NAME)
-    {
-      gimple *stmt = SSA_NAME_DEF_STMT (dest);
-      if (!is_gimple_assign (stmt))
-       return HOST_WIDE_INT_M1U;
-
-      if (!gimple_assign_single_p (stmt)
-         && !gimple_assign_unary_nop_p (stmt))
-       return HOST_WIDE_INT_M1U;
+  return HOST_WIDE_INT_M1U;
+}

-      dest = gimple_assign_rhs1 (stmt);
-      return determine_min_objsize (dest);
-    }
+/* Similarly, but maximum instead of minimum, and return 0 when the
+   size cannot be determined.  */

-  /* Try to determine the size of the object from its type.  */
-  if (TREE_CODE (dest) != ADDR_EXPR)
-    return HOST_WIDE_INT_M1U;
-
-  tree type = TREE_TYPE (dest);
-  if (TREE_CODE (type) == POINTER_TYPE)
-    type = TREE_TYPE (type);
-
-  type = TYPE_MAIN_VARIANT (type);
-
-  /* The size of a flexible array cannot be determined.  Otherwise,
-     for arrays with more than one element, return the size of its
-     type.  GCC itself misuses arrays of both zero and one elements
-     as flexible array members so they are excluded as well.  */
-  if (TREE_CODE (type) != ARRAY_TYPE
-      || !array_at_struct_end_p (dest))
-    {
-      tree type_size = TYPE_SIZE_UNIT (type);
-      if (type_size && TREE_CODE (type_size) == INTEGER_CST
-         && !integer_onep (type_size)
-         && !integer_zerop (type_size))
-        return tree_to_uhwi (type_size);
-    }
+static unsigned HOST_WIDE_INT
+determine_max_objsize (tree dest)
+{
+  unsigned HOST_WIDE_INT size;

-  return HOST_WIDE_INT_M1U;
+  init_object_sizes ();
+
+  if (compute_builtin_object_size (dest, 0, &size))
+    return size;
+
+  return 0;
 }

 /* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths
@@ -3603,7 +3579,9 @@ get_len_or_size (tree arg, int idx, unsi
          /* Set *SIZE to the size of the smallest object referenced
             by ARG if ARG denotes a single object, or to HWI_M1U
             otherwise.  */
-         *size = determine_min_objsize (arg);
+         *size = determine_max_objsize (arg);
+         if (*size == 0)
+           *size = HOST_WIDE_INT_M1U;
          *nulterm = false;
        }
     }
plus add testsuite coverage from the testcases in this PR and deal with
testsuite regressions:
FAIL: gcc.dg/Wstring-compare.c  (test for warnings, line 123)
FAIL: gcc.dg/strcmpopt_2.c scan-tree-dump-times strlen1 "cmp_eq \\(" 8
FAIL: gcc.dg/strcmpopt_4.c scan-tree-dump-times strlen1 "cmp_eq \\(" 1
FAIL: gcc.dg/strlenopt-69.c scan-tree-dump-not optimized "abort|strcmp|strncmp"
where strcmpopt_2.c now matches just 4 times instead of 8.

Or do we consider the #c10 testcase valid, but what strcmpopt_2.c does like:
typedef struct { char s[8]; int x; } S;

__attribute__ ((noinline)) int
f1 (S *s)
{
  return __builtin_strcmp (s->s, "abc") != 0;
}

ok (in that if there is a pointer to S, at least sizeof (s->s) bytes will be
mapped?  We could look through COMPONENT_REFs in the access path and if there
is  any UNION_TYPE in there, be conservative and consider the same addresses in
all the union members and take conservative answer from all of them?  Wouldn't
that still be a problem if we have union somewhere earlier and just take
address of a union member?

Reply via email to