Оптимизация компилятора статического constexpr - PullRequest
1 голос
/ 01 октября 2019

С учетом следующего кода C ++:

#include <stdio.h>

static constexpr int x = 1;

void testfn() {
    if (x == 2)
        printf("This is test.\n");
}

int main() {
    for (int a = 0; a < 10; a++)
        testfn();
    return 0;
}

Visual Studio 2019 создает следующую сборку сборки Debug (просмотр с использованием подхода 1 принятого ответа по адресу: Как просмотреть сборку за кодом с помощью VisualC ++? )

int main() {
00EC1870  push        ebp  
00EC1871  mov         ebp,esp  
00EC1873  sub         esp,0CCh  
00EC1879  push        ebx  
00EC187A  push        esi  
00EC187B  push        edi  
00EC187C  lea         edi,[ebp-0CCh]  
00EC1882  mov         ecx,33h  
00EC1887  mov         eax,0CCCCCCCCh  
00EC188C  rep stos    dword ptr es:[edi]  
00EC188E  mov         ecx,offset _6D4A0457_how_compiler_treats_staticconstexpr@cpp (0ECC003h)  
00EC1893  call        @__CheckForDebuggerJustMyCode@4 (0EC120Dh)  
    for (int a = 0; a < 10; a++)
00EC1898  mov         dword ptr [ebp-8],0  
00EC189F  jmp         main+3Ah (0EC18AAh)  
00EC18A1  mov         eax,dword ptr [ebp-8]  
00EC18A4  add         eax,1  
00EC18A7  mov         dword ptr [ebp-8],eax  
00EC18AA  cmp         dword ptr [ebp-8],0Ah  
00EC18AE  jge         main+47h (0EC18B7h)  
        testfn();
00EC18B0  call        testfn (0EC135Ch)  
00EC18B5  jmp         main+31h (0EC18A1h)  
    return 0;
00EC18B7  xor         eax,eax  
}

Как видно из сборки, возможно, потому что это сборка отладки, бессмысленные ссылки на цикл for и testfn в main. Я бы надеялся, что они вообще не найдут упоминания в ассемблерном коде, учитывая, что printf в testfn никогда не попадет, поскольку static constexpr int x=1.

У меня есть 2 вопроса:

(1) Возможно, в сборке Release цикл for оптимизирован. Как я могу это проверить? Просмотр кода сборки сборки выпуска не работает для меня даже при использовании подхода 2, указанного по адресу: Как просмотреть сборку за кодом с помощью Visual C ++? . Файл с кодом сборки вообще не создается.

(2) При использовании static constexpr int/double/char, а не #define, при каких обстоятельствах гарантируется, что первый не повлечет за собой ненужных накладных расходов(вычисления / оценки во время выполнения)? #define, хотя и очень злобные, кажется, предлагают гораздо большую гарантию, чем static constexpr в этом отношении.

1 Ответ

4 голосов
/ 01 октября 2019

Проблема в том, что вы компилируете код, используя отладочную сборку. Если вы хотите здравомыслие в asm, вместо этого скомпилируйте как release. Проблема в том, что для подтверждения логики базового кода используется отладчик. Логика вашего базового кода в том, что он должен вызывать testfn () 10 раз. В результате вы сможете установить точку останова для этого метода и достичь ее в правильной точке выполнения. В сборке релиза эта точка останова никогда не будет достигнута (потому что она была бы оптимизирована).

В вашем случае, однако, совершенно неверно говорить, что constexpr игнорируется. Вы можете заметить, что в сгенерированном asm нет вызовов printf (), поэтому компилятор правильно определил, что if (x == 2) никогда не может быть истинным, и удалил его. Однако, если компилятор полностью уберет вызов testfn (), ваша точка останова никогда не будет достигнута, и отладчик будет бесполезен.

Не смотрите на вывод отладочной сборки и представьте, что он говорит вам что-нибудь полезное о коде или компиляторе. Вы должны ожидать, что код будет преднамеренно де-оптимизирован.

...