@djEban

Почему clang выдает такой ассемблерный код?

Point p = { .x = 5; }

Point p;
p.x = 5;

Выдает следующий код:
Для 1 случая:
movl    L___const.main.p(%rip), %eax
movl    %eax, -4(%rbp)
L___const.main.p:
    .long    5

Для 2 случая:
movl $5, -4(%rbp)

Какой смысл использовать первый вариант инициализации, если второй вариант явно выигрывает по скорости выполнения кода?
Я так понимаю, это больше надо для инициализации глобальных структур
  • Вопрос задан
  • 444 просмотра
Решения вопроса 3
AshBlade
@AshBlade
Просто хочу быть счастливым
Зависит от окружения/флагов/версии
Но я здесь вижу:
1. Именованная константа со своим адресом (PIC)
2. Простое число

В первом случае необходимо использовать регистр (временное хранилище), т.к. нельзя копировать из памяти в память - надо оперировать регистрами
Ответ написан
wataru
@wataru
Разработчик на С++, экс-олимпиадник.
Что у вас за опции сборки (Это же с++, не смотря на теги же?) Оптимизация-то включена? GCC 14 даже без оптимизаций выдает именно второй код в обоих случаях.

Похоже, это недочет в компиляторе. Понятно, что тут можно использовать второй вариант без проблем. Но компилятор не смог до этого догадаться по каким-то причинам. Ясно, что для списка инициализации и просто присвоения используются разные куски компилятора. И вот в ветке для списка инициализации эту оптимизацию не прикрутили по каким-то причинам.

Если вы вставите более полный пример кода на godbolt.org, воспроизведете проблему, и поделитесь ссылкой, то, возможно, я смогу вам более детально ответить.

Edit:
Разобрались, что это clang c. Такой код он выдает с -O0. Если же оптимизации включены, то он его оптимизирует. Это не недочет или ошибка. Просто, вот такой у него стандартный код. Он вправе засовывать константы в секцию данных, а не вставлять прям в ассемблерный код.
Ответ написан
@vadimr
Семантически у вас в двух вариантах написаны совершенно разные вещи.

В первом случае в секции данных создаётся безымянная структура, ссылка на которую присваивается переменной p, а во втором случае записывается число в поле структуры p, автоматически размещаемой, т.е. для типичных архитектур находящейся на стеке.

На высоких уровнях оптимизации, конечно, компилятор догадается, что результат этих действий один и тот же, но формально это разные программы. По той же самой причине, по которой элементарные и агрегатные типы в языке Си различаются между собой по способу присваивания.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
mayton2019
@mayton2019
Bigdata Engineer
Если - бы я был бизнесом и автор пришел бы ко мне с таким вопросом - я б спросил : как сильно
влияет этот код на наш бизнес
. И как много времени и сил мы хотим потратить на investigation
этой проблемы.

Я языках программирования и компилляторах всегда есть много забавных побочных эффектов. Но
не все из них являются performance issue. Чтоб быть в фокусе. Обычно performance issues изучают
в
- циклах
- векторизированных операциях
- параллелизм и конкуренция в многопоточке
- I/O

Отдельно можно рассмотреть его величество алгоритм. Это тоже важно.

Что мы имеем в данном примере? Ровно ничего. Совершенно софистический код, который не делает
полезной работы и мы не можем никак оценить пользу или вред от оптимизаций. К слову если-бы
инициализация Point стояла бы в теле цикла, то мне не составило-бы труда развалить ее на атомы
(две переменных int) выполнить над ними все калькуляции и после выхода из цикла собрать снова
эту-же структуру.

Оценю в 1 story point вместе с тестами. И это будет дешевле по усилиям даже чем обсуждать этот
вопрос в хабре. Грубо говоря вопрос будет закрыт даже не появившись.

Автору еще посоветую посмотреть на GCC. И посмотрет на промежуточный LLVM код, который создает
clang еще до ассемблера. Возможно это поведение там зафиксировано. Как особенность clang.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы