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;

}

Reply via email to