Bug 82912 - missing strlen optimization for stpncpy with constant string and bound
Summary: missing strlen optimization for stpncpy with constant string and bound
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks: strlen
  Show dependency treegraph
 
Reported: 2017-11-09 00:47 UTC by Martin Sebor
Modified: 2023-10-26 00:11 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2017-11-09 00:47:33 UTC
GCC can figure out the length of the string created by the call to strncpy() in f0() but it doesn't do the same for stpncpy() in f2() or f3().

Using stpncpy() the way f2() and f3() do is idiomatic and often preferred because it is assumed to be more efficient than the equivalent sequence involving strncpy().

See also pr82911 for a similar missed optimization opportunity involving strncpy().

$ cat c.c && gcc -O2 -S -Wall -Wextra -fdump-tree-optimized=/dev/stdout c.c
void f0 (char *d)
{
  __builtin_strncpy (d, "123", 2);
  d[2] = 0;

  if (__builtin_strlen (d) != 2)   // eliminated, good
    __builtin_abort ();
}

void f2 (char *d)
{
  *__builtin_stpncpy (d, "123", 2) = 0;
  
  if (__builtin_strlen (d) != 2)   // not eliminated but should be
    __builtin_abort ();
}

void f3 (char *d, _Bool b)
{
  *__builtin_stpncpy (d, b ? "123" : "1234", 2) = 0;

  if (__builtin_strlen (d) != 2)   // not eliminated but could be
    __builtin_abort ();
}

;; Function f0 (f0, funcdef_no=0, decl_uid=1887, cgraph_uid=0, symbol_order=0)

f0 (char * d)
{
  <bb 2> [local count: 10000]:
  __builtin_memcpy (d_3(D), "123", 2);
  MEM[(char *)d_3(D) + 2B] = 0;
  return;

}



;; Function f2 (f2, funcdef_no=1, decl_uid=1890, cgraph_uid=1, symbol_order=1)

f2 (char * d)
{
  char * _1;
  long unsigned int _2;

  <bb 2> [local count: 10000]:
  _1 = __builtin_stpncpy (d_4(D), "123", 2);
  *_1 = 0;
  _2 = __builtin_strlen (d_4(D));
  if (_2 != 2)
    goto <bb 3>; [0.04%]
  else
    goto <bb 4>; [99.96%]

  <bb 3> [count: 0]:
  __builtin_abort ();

  <bb 4> [local count: 9996]:
  return;

}



;; Function f3 (f3, funcdef_no=2, decl_uid=1894, cgraph_uid=2, symbol_order=2)

f3 (char * d, _Bool b)
{
  char * _1;
  long unsigned int _2;
  const char * iftmp.0_3;

  <bb 2> [local count: 10000]:
  if (b_4(D) != 0)
    goto <bb 4>; [50.00%]
  else
    goto <bb 3>; [50.00%]

  <bb 3> [local count: 5000]:

  <bb 4> [local count: 10000]:
  # iftmp.0_3 = PHI <"123"(2), "1234"(3)>
  _1 = __builtin_stpncpy (d_6(D), iftmp.0_3, 2);
  *_1 = 0;
  _2 = __builtin_strlen (d_6(D));
  if (_2 != 2)
    goto <bb 5>; [0.04%]
  else
    goto <bb 6>; [99.96%]

  <bb 5> [count: 0]:
  __builtin_abort ();

  <bb 6> [local count: 9996]:
  return;

}