[gcc r17-3337] fold-const-call.cc: add strnlen in fold_const_call [PR86937]
Daniel Barboza via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:e7b77e39552d82141f71f039f70885754de72093 commit r17-3337-ge7b77e39552d82141f71f039f70885754de72093 Author: Daniel Barboza <[email protected]> Date: Fri Aug 14 18:14:42 2026 -0300 fold-const-call.cc: add strnlen in fold_const_call [PR86937] 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. Diff: --- 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(-) diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc index b3a9d7715d66..c483b80e7045 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 000000000000..b6b2876bf647 --- /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 70f6a432b978..45a948c22b6e 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]; };