Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

В каких случаях компиляторы оптимизируют код?

#cpp



Вопрос про инициализацию стандартных типов. Например:

float fl_val;
fl_val = 1.0f;
fl_val = 1.0;
fl_val = 1;


Здесь мы инициализируем float разными значениями. Понимают ли сейчас компиляторы
(например, GCC и Visual Studio), что происходит, и оптимизируют эти моменты? Например,
сразу приводят к float на этапе компиляции, а не во время выполнения: сначала int(1)
приводят к (1.0f). Затраты небольшие, но есть.
Вопрос с условием такого типа:

int a; // пусть она инициализирована неизвестным значением
int b = a >= 0 ? 1 : 2 * 10; 


* 10 относится только к условию false, или к true тоже? Проверить сейчас возможности нет.

    


Ответы

Ответ 1



1) Да, компиляторы уже давно очень-очень умные в плане оптимизации. Они прекрасно оптимизируют все константы, до которых могут дотянуться. Вот вам пример с gcc: вот такая функция #include void f() { float f = 4; printf("%f", f); } компилируется в следующее: .LC1: .string "%f" f(): pushq %rbp movq %rsp, %rbp subq $16, %rsp movl .LC0(%rip), %eax movl %eax, -4(%rbp) cvtss2sd -4(%rbp), %xmm0 movl $.LC1, %edi movl $1, %eax call printf leave ret .LC0: .long 1082130432 Вы видите созданную константу .LC0 = 1082130432. Это есть битовое представление 4.0f, в чём легко убедиться: вот такой код #include using namespace std; int main() { union { int32_t l; float f; }; f = 4; cout << l; return 0; } выдаёт в точности 1082130432. 2) Ну это же легко проверить, есть гора онлайн-компиляторов. Например: http://ideone.com/GJHdaH выдаёт ответ 1, то есть, умножение имеет более высокий приоритет. int a = 1; int b = a >= 0 ? 1 : 2 * 10; cout << b; Вы можете подсмотреть приоритеты в стандарте или в документации вашего компилятора, но для обычных целей простого эксперимента достаточно: вряд ли в имплементации компилятора такая дыра! Важное «но»: если у вас возникли вопросы, такие же вопросы возникнут и у читателей вашего кода. Поэтому не поленитесь расставить скобки, чтобы смысл вашего кода не вызывал вопросов. Не надейтесь, что все остальные держат в голове таблицу приоритетов операций, тем более что в разных языках она разная. Для хорошего, долгоживущего кода очень важна читаемость.

Ответ 2



Отвечая по поводу оптимизации - да, понимают. Все-таки, в 21 веке живем, такие мелочи компиляторы должны на раз щелкать. Вот такой код: float fl_val; fl_val = 1.0f; fl_val = 1.0; fl_val = 1; Сlang++ преобразовал в следующий (на -O0, на -O3, разумеется, весь этот мусор отсутствует): .LCPI1_0: .long 1065353216 # float 1 .text .globl main .align 16, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: pushq %rbp .Ltmp4: .cfi_def_cfa_offset 16 .Ltmp5: .cfi_offset %rbp, -16 movq %rsp, %rbp .Ltmp6: .cfi_def_cfa_register %rbp xorl %eax, %eax movss .LCPI1_0, %xmm0 # Загрузили 1 в регистр movss %xmm0, -4(%rbp) # fl_val = 1.0f; movss %xmm0, -4(%rbp) # fl_val = 1.0; movss %xmm0, -4(%rbp) # fl_val = 1; popq %rbp retq Как видим, в коде это одна и та же констатна, расположенная по адресу .LCPI1_0. Введение новой константы ничего интересного не дает: float fl_val; fl_val = 1.0f; fl_val = 1.0; fl_val = 42; Легким движением байтов, данный код превращается в элегантные шорты long-и: .LCPI1_0: .long 1109917696 # float 42 .LCPI1_1: .long 1065353216 # float 1 .text .globl main .align 16, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: pushq %rbp .Ltmp4: .cfi_def_cfa_offset 16 .Ltmp5: .cfi_offset %rbp, -16 movq %rsp, %rbp .Ltmp6: .cfi_def_cfa_register %rbp xorl %eax, %eax movss .LCPI1_0, %xmm0 # Загрузили 42 в регистр movss .LCPI1_1, %xmm1 # Загрузили 1 в регистр movss %xmm1, -4(%rbp) # fl_val = 1.0f; movss %xmm1, -4(%rbp) # fl_val = 1.0; movss %xmm0, -4(%rbp) # fl_val = 42; popq %rbp retq

Комментариев нет:

Отправить комментарий