[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