[PATCH v2] fold-const-call.cc: add strnlen in fold_const_call [PR86937]

Daniel Barboza <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
We're not trying to fold builtin_strnlen calls into constants like we do
with builtin_strlen.  This results in missed optimizations where we
have a strnlen that uses a PHI as input:

const char a[4] = "123";

int g (int i)
{
  return __builtin_strnlen (i ? a : "", 4);
}

The strnlen call could be folded into a single PHI <0, 3> but instead
we're calling strnlen with the PHI result:

  # iftmp.1_2 = PHI <&aD.4472(3), ""(2)>
  # VUSE <.MEM_4(D)>
  # RANGE [irange] long unsigned int [0, 4] MASK 0x7 VALUE 0x0
  # USE = nonlocal escaped const-pool { D.4472 } (nonlocal)
  _1 = strnlenD.1862 (iftmp.1_2, 4);
  # RANGE [irange] int [0, 4] MASK 0x7 VALUE 0x0
  _5 = (intD.7) _1;
  # VUSE <.MEM_4(D)>
  return _5;

After this change:

  # RANGE [irange] int [0, 0][3, 3] MASK 0x3 VALUE 0x0
  # prephitmp_7 = PHI <3(3), i_3(D)(2)>
  # VUSE <.MEM_4(D)>
  return prephitmp_7;

Bootstrapped and regression tested in x86_64.

	PR tree-optimization/86937

gcc/ChangeLog:

	* fold-const-call.cc (fold_const_call): fold
	CFN_BUILT_IN_STRNLEN calls.

gcc/testsuite/ChangeLog:

	* gcc.dg/warn-strnlen-no-nul.c: warnings were
	added/removed/changed due to the new STRNLEN folding.
	* gcc.dg/tree-ssa/pr86937.c: New test.
---

Changes from v1:
- add extra space in "strnlen " scan
- remove the added xfail tests in warn-strnlen-no-nul.c
- v1 link: https://gcc.gnu.org/pipermail/gcc-patches/2026-August/727358.html

 gcc/fold-const-call.cc                     | 11 ++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr86937.c    | 15 +++++++++++
 gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c | 29 +++++++++++-----------
 3 files changed, 41 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr86937.c

diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index b3a9d7715d6..c483b80e704 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -1911,6 +1911,17 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
 	}
       return NULL_TREE;
 
+    case CFN_BUILT_IN_STRNLEN:
+      if ((p0 = c_getstr (arg0)))
+	{
+	  unsigned HOST_WIDE_INT s1 = 0;
+	  if (!size_t_cst_p (arg1, &s1))
+	    return NULL_TREE;
+
+	  return build_int_cst (type, strnlen (p0, s1));
+	}
+      return NULL_TREE;
+
     case CFN_FOLD_LEFT_PLUS:
       return fold_const_fold_left (type, arg0, arg1, PLUS_EXPR);
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr86937.c b/gcc/testsuite/gcc.dg/tree-ssa/pr86937.c
new file mode 100644
index 00000000000..b6b2876bf64
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr86937.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-pre" } */
+const char a[4] = "123";
+
+int f (int i)
+{
+  return __builtin_strlen (i ? a : "");
+}
+
+int g (int i)
+{
+  return __builtin_strnlen (i ? a : "", 4);
+}
+
+/* { dg-final { scan-tree-dump-times "strnlen " 0 "pre" } } */
diff --git a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
index 70f6a432b97..45a948c22b6 100644
--- a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
+++ b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c
@@ -147,14 +147,14 @@ T (v0 ? b[3] : "", bsz);
    the strnlen calls are safe because the reads are bounded by
    the length of the constant arguments.  Most of the calls are
    not diagnosed anymore as a result of the fix for PR 103215.  */
-T (v0 ? "" : b[0], bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[0], bsz + 1);
 T (v0 ? "" : b[1], bsz + 1);
 T (v0 ? "" : b[2], bsz + 1);
-T (v0 ? "" : b[3], bsz + 1);
-T (v0 ? b[0] : "", bsz + 1);      /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[3], bsz + 1);      /* { dg-warning "unterminated" } */
+T (v0 ? b[0] : "", bsz + 1);
 T (v0 ? b[1] : "", bsz + 1);
 T (v0 ? b[2] : "", bsz + 1);
-T (v0 ? b[3] : "", bsz + 1);
+T (v0 ? b[3] : "", bsz + 1);      /* { dg-warning "unterminated" } */
 
 T (v0 ? "" : b[i0], bsz);
 T (v0 ? "" : b[i1], bsz);
@@ -168,11 +168,11 @@ T (v0 ? b[i3] : "", bsz);
 T (v0 ? "" : b[i0], bsz + 1);
 T (v0 ? "" : b[i1], bsz + 1);
 T (v0 ? "" : b[i2], bsz + 1);
-T (v0 ? "" : b[i3], bsz + 1);
+T (v0 ? "" : b[i3], bsz + 1);     /* { dg-warning "unterminated" } */
 T (v0 ? b[i0] : "", bsz + 1);
 T (v0 ? b[i1] : "", bsz + 1);
 T (v0 ? b[i2] : "", bsz + 1);
-T (v0 ? b[i3] : "", bsz + 1);
+T (v0 ? b[i3] : "", bsz + 1);     /* { dg-warning "unterminated" } */
 
 T (v0 ? "1234" : b[3], bsz);
 T (v0 ? "1234" : b[i3], bsz);
@@ -184,17 +184,18 @@ T (v0 ? b[0] : b[2], bsz);
 T (v0 ? b[2] : b[3], bsz);
 T (v0 ? b[3] : b[2], bsz);
 
-T (v0 ? "1234" : b[3], bsz + 1);
-T (v0 ? "1234" : b[i3], bsz + 1);
-T (v0 ? b[3] : "1234", bsz + 1);
-T (v0 ? b[i3] : "1234", bsz + 1);
+/* New warnings being thrown after PR86937.  */
+T (v0 ? "1234" : b[3], bsz + 1);     /* { dg-warning "unterminated" } */
+T (v0 ? "1234" : b[i3], bsz + 1);    /* { dg-warning "unterminated" } */
+T (v0 ? b[3] : "1234", bsz + 1);     /* { dg-warning "unterminated" } */
+T (v0 ? b[i3] : "1234", bsz + 1);    /* { dg-warning "unterminated" } */
 
 /* That the following are not diagnosed is a bug/limitation resulting from
    the fix for PR 103215.  */
-T (v0 ? a : b[3], bsz + 1);       /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */
-T (v0 ? b[0] : b[2], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */
-T (v0 ? b[2] : b[3], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */
-T (v0 ? b[3] : b[2], bsz + 1);    /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */
+T (v0 ? a : b[3], bsz + 1);
+T (v0 ? b[0] : b[2], bsz + 1);
+T (v0 ? b[2] : b[3], bsz + 1);    /* { dg-warning "unterminated" } */
+T (v0 ? b[3] : b[2], bsz + 1);    /* { dg-warning "unterminated" } */
 
 struct A { char a[5], b[5]; };
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.