Почему Clang не оптимизирует глобальный константный как #define? - PullRequest
0 голосов
/ 18 января 2019

У меня есть эта тестовая программа, использующая константу #define:

#include <stdio.h>

#define FOO 1

int main()
{
    printf("%d\n", FOO);

    return 0;
}

При компиляции с «Apple LLVM версии 10.0.0 (clang-1000.11.45.5)» я получаю исполняемый файл размером 8432 байта. Вот список сборки:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    L_.str(%rip), %rdi
    movl    $1, %esi
    movl    $0, -4(%rbp)
    movb    $0, %al
    callq   _printf
    xorl    %esi, %esi
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %esi, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%d\n"


.subsections_via_symbols

Теперь я заменяю #define FOO 1 на const int FOO = 1;. Размер исполняемого файла теперь составляет 8464 байта, а список сборки выглядит следующим образом:

.section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    L_.str(%rip), %rdi
    movl    $1, %esi
    movl    $0, -4(%rbp)
    movb    $0, %al
    callq   _printf
    xorl    %esi, %esi
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %esi, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__const
    .globl  _FOO                    ## @FOO
    .p2align    2
_FOO:
    .long   1                       ## 0x1

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "%d\n"


.subsections_via_symbols

Таким образом, он фактически объявил переменную FOO, увеличив размер исполняемого файла на 32 байта. Я получаю тот же результат с -O3 уровнем оптимизации.

Почему это? Обычно компилятор должен быть достаточно умным, чтобы оптимизировать и добавлять константу в таблицу символов вместо того, чтобы занимать для нее память.

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Это еще один случай, когда разница между C и C ++ имеет значение.

В C const int FOO имеет внешнюю связь и поэтому должен быть включен в двоичный файл.

Компиляция с g ++ или clang ++ дает вам желаемую оптимизацию, так как FOO имеет внутреннюю связь в C ++.

Вы можете добиться оптимизации в режиме C, явно запросив внутреннюю связь для FOO через

static const int FOO = 1;

И clang, и gcc с включенной оптимизацией по времени соединения (-flto) также удаляют неиспользуемый символ, даже если связь является внешней. (Live с и без LTO.)

0 голосов
/ 18 января 2019

Тот факт, что вы используете переменную FOO во второй программе, означает, что она должна где-то жить, поэтому компилятор должен ее где-то размещать.

В случае #define переменная отсутствует - препроцессор заменил текст «FOO» текстом «1», поэтому при вызове printf() было передано постоянное значение, а не переменная.

...