https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126266
Bug ID: 126266
Summary: strlen pass cannot recognize *s == 0
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: missed-optimization
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: giraffe.commits at aol dot com
Target Milestone: ---
The strlen pass can determine that if strlen (s) == 0, the string s must be
empty.
However, in cases where *s == 0 is used rather than strlen (s) == 0, the same
information is not gathered.
For calls to strlen, the string information is created by handle_builtin_strlen
calling new_strinfo to create a strinfo representing the string's being empty.
Ideally some similar addition to the pass to analyse expressions like *s == 0
is warranted.
This difference results in (for example) the following scenario, where two
functions, despite being semantically identical, are compiled differently. In
particular, the latter function's strcpy is replaced with a memcpy (eventually
removed entirely), whereas no such change is applied to the former.
$ cat ./z.c && gcc -O2 -S -Wall -Wextra -fdump-tree-strlen=/dev/stdout ./z.c
#include <string.h> /* Alternatively `#include "strlenopt.h"`. */
void f1(char *s) {
extern char d[1];
if (*s == 0) {
strcpy (d, s);
}
}
void f2(char *s) {
extern char d[1];
size_t len = strlen (s);
if (len == 0) {
strcpy (d, s);
}
}
;; Function f1 (f1, funcdef_no=0, decl_uid=2893, cgraph_uid=1, symbol_order=0)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
void f1 (char * s)
{
char _1;
<bb 2> [local count: 1073741824]:
_1 = *s_4(D);
if (_1 == 0)
goto <bb 3>; [33.00%]
else
goto <bb 4>; [67.00%]
<bb 3> [local count: 354334800]:
strcpy (&d, s_4(D));
<bb 4> [local count: 1073741824]:
return;
}
;; Function f2 (f2, funcdef_no=1, decl_uid=2898, cgraph_uid=2, symbol_order=1)
;; 1 loops found
;;
;; Loop 0
;; header 0, latch 1
;; depth 0, outer -1
;; nodes: 0 1 2 3 4
;; 2 succs { 3 4 }
;; 3 succs { 4 }
;; 4 succs { 1 }
void f2 (char * s)
{
size_t len;
long unsigned int _6;
<bb 2> [local count: 1073741824]:
len_4 = strlen (s_3(D));
if (len_4 == 0)
goto <bb 3>; [33.00%]
else
goto <bb 4>; [67.00%]
<bb 3> [local count: 354334800]:
_6 = len_4 + 1;
__builtin_memcpy (&d, s_3(D), _6);
<bb 4> [local count: 1073741824]:
return;
}