Bug 34027 - вызывающе неоптимальный код для memcmp с константным размером
Summary: вызывающе неоптимальный код для memcmp с константным размером
Status: CLOSED WONTFIX
Alias: None
Product: Sisyphus
Classification: Development
Component: gcc6 (show other bugs)
Version: unstable
Hardware: all Linux
: P3 normal
Assignee: Gleb F-Malinovskiy
QA Contact: qa-sisyphus
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-10-18 23:04 MSK by alexey.tourbin
Modified: 2018-07-14 01:22 MSK (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description alexey.tourbin 2017-10-18 23:04:28 MSK
Мужчины, у вас memcmp(s1, s2, 4) генерирует вызов memcmp через PLT.
Что-то не везет у вас с компилятором, ни с пятым ни с шестым.

$ cat test.c
#include <stdbool.h>
#include <string.h>
bool isBindir(const char *d, size_t dlen)
{
    // Compare a string to a string literal.
#define strLen(ss) (sizeof(ss "") - 1)
#define memEq(s, ss) (memcmp(s, ss, strLen(ss)) == 0)
#define strEq(s, ss) (s##len == strLen(ss) && memEq(s, ss))
#define startsWith(s, ss) (s##len >= strLen(ss) && memEq(s, ss))
#define endsWith(s, ss) (s##len >= strLen(ss) && memEq(s + s##len - strLen(ss), ss))
    return endsWith(d, "bin/");
}
int main()
{
    return isBindir("/usr/bin/", strLen("/usr/bin/")) ? 0 : 1;
}

$ gcc -E test.c |grep \"bin/
    return (dlen >= (sizeof("bin/" "") - 1) && (memcmp(d + dlen - (sizeof("bin/" "") - 1), "bin/", (sizeof("bin/" "") - 1)) == 0));

$ gcc -g -O2 -Wall test.c && objdump -D a.out |perl -ln00e 'print if /isBindir/'
0000000000400510 <isBindir>:
  400510:       48 83 fe 03             cmp    $0x3,%rsi
  400514:       76 2a                   jbe    400540 <isBindir+0x30>
  400516:       48 8d 7c 37 fc          lea    -0x4(%rdi,%rsi,1),%rdi
  40051b:       48 83 ec 08             sub    $0x8,%rsp
  40051f:       ba 04 00 00 00          mov    $0x4,%edx
  400524:       be e0 05 40 00          mov    $0x4005e0,%esi
  400529:       e8 c2 fe ff ff          callq  4003f0 <memcmp@plt>
  40052e:       85 c0                   test   %eax,%eax
  400530:       0f 94 c0                sete   %al
  400533:       48 83 c4 08             add    $0x8,%rsp
  400537:       c3                      retq   
  400538:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  40053f:       00 
  400540:       31 c0                   xor    %eax,%eax
  400542:       c3                      retq   
  400543:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40054a:       00 00 00 
  40054d:       0f 1f 00                nopl   (%rax)

Я скачал себе седьмой компилятор, у него код генерируется нормальный.  Одна инструкция cmp, как и надо!  Это может быть связано не только с компилятором, а еще какой-то сортифай форс си-эйч-кей там был, может это он гадит.

$ ~/gcc-7/bin/gcc -g -O2 -Wall test.c && objdump -D a.out |perl -ln00e 'print if /isBindir/'
0000000000400480 <isBindir>:
  400480:       31 c0                   xor    %eax,%eax
  400482:       48 83 fe 03             cmp    $0x3,%rsi
  400486:       76 0b                   jbe    400493 <isBindir+0x13>
  400488:       81 7c 37 fc 62 69 6e    cmpl   $0x2f6e6962,-0x4(%rdi,%rsi,1)
  40048f:       2f 
  400490:       0f 94 c0                sete   %al
  400493:       f3 c3                   repz retq 
  400495:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40049c:       00 00 00 
  40049f:       90                      nop

В общем, для промышленного применения ПСПО уровня масштаба предприятия такой компилятор совершенно не годится.  Да даже профилировать код не годится.  Я пытаюсь получить более оптимальную последовательность инструкций, а он оказывается функцию вызывает!  И сколько такого плохо скомпилированного кода в репозитории.
Comment 1 Dmitry V. Levin 2018-07-13 02:26:37 MSK
Спасибо.
В gcc7 это безобразие исправлено, в gcc6 исправлять смысла нет.
Пакеты со временем пересоберём.
Comment 2 alexey.tourbin 2018-07-14 00:48:36 MSK
Чота я подумал может это не сортифай форс, а макрос в glibc был, типа
#define memcmp(dest, src, n) (__builtin_constant_p(n) ? glibc_inline_memcpy(dest,src,n) : __builtin_memcpy(dest,src,n))
Был там какой-то асм.

И некоторое время казалось, что всё нормально. А потом макрос в glibc почикали, и оказалось что всё голое, никто ни за что не отвечает.
Comment 3 Dmitry V. Levin 2018-07-14 01:22:48 MSK
Что-то я не припоминаю макросов для memcmp в glibc.
Не для memcpy, а именно для memcmp.