История изменений
Исправление numas13, (текущая версия) :
Теперь понял про что. Да, с алиасингом по-другому никак.
Не только. У небольшого базового блока очень большие шансы быть объединённым с другими.
- e2k https://ce.mentality.rip/z/KWfWMT
- 1 гиперблок, 3
fmuld
- 1 гиперблок, 3
- amd64 https://godbolt.org/z/vbP56ozM5
- 2 суперблока (+1 базовый блок), 3
mulsd
- 2 суперблока (+1 базовый блок), 3
Когда в e2k начинается работа с памятью, то всё становится намного веселее. Часть/части базовых блоков начинают мигрировать выше нагружая процессор бесполезной работой, если исполнение не лежит через эту ветку. Но с другой стороны это повышает загруженность ШК и избавляет от и без того медленных ветвлений в e2k.
В e2k всегда будет обращаться в память, даже если эту ветку не надо исполнять. Кеш-промахи будут в любом случае. :)
Но в обоих случаях компилятор не знает что именно будет исполнятся, а это может сильно повлиять на генерируемый код.
- e2k https://ce.mentality.rip/z/5Gq8qn
- Ожидания памяти не будет в худшем случае, но будет вариативная задержка (если не ошибаюсь, 4-7 такта до 16C и 4-5 для 16C) из-за невыставленных nop для fmuld.
- amd64 https://godbolt.org/z/3v64c3re1
- Не взятые ветвления обычно дешевле.
Хотя ты заметишь, что можно было бы спланировать и лучше, но lcc частенько так «косячит», так что привыкай. Только не надо вновь загонять про «вот напишут нормальный компилятор и заживём». Это не такая простая задача как может показаться на первый взгляд.
Вообще-то подготовленный переход позволяет из одной точки перейти на разные метки. А ibranch технически должен быть равен некоему disp на скрытый регистр при начале выполнения + ct (то есть задержка в 3 такта гарантированно прошла).
disp => ct
== 5 тактов.
И если бы он был больше одного такта, то в конце был бы не ibranch .L45, а ct %ctpr1 (если даже считать, что rbranch содержит магию и на ct не заменяется).
Нет всё верно, это тот самый «unhappy path». Зачем зря греть воздух и подготавливать переход? Тем более, что количество доп. конвейеров очень ограничено. В реальных программах компилятор так не делает, т.к. они обычно заняты.
Исправление numas13, :
Теперь понял про что. Да, с алиасингом по-другому никак.
Не только. У небольшого базового блока очень большие шансы быть объединённым с другими.
- e2k https://ce.mentality.rip/z/KWfWMT
- 1 гиперблок, 3
fmuld
- 1 гиперблок, 3
- amd64 https://godbolt.org/z/vbP56ozM5
- 3 суперблока, 3
mulsd
- 3 суперблока, 3
Когда в e2k начинается работа с памятью, то всё становится намного веселее. Часть/части базовых блоков начинают мигрировать выше нагружая процессор бесполезной работой, если исполнение не лежит через эту ветку. Но с другой стороны это повышает загруженность ШК и избавляет от и без того медленных ветвлений в e2k.
В e2k всегда будет обращаться в память, даже если эту ветку не надо исполнять. Кеш-промахи будут в любом случае. :)
Но в обоих случаях компилятор не знает что именно будет исполнятся, а это может сильно повлиять на генерируемый код.
- e2k https://ce.mentality.rip/z/5Gq8qn
- Ожидания памяти не будет в худшем случае, но будет вариативная задержка (если не ошибаюсь, 4-7 такта до 16C и 4-5 для 16C) из-за невыставленных nop для fmuld.
- amd64 https://godbolt.org/z/3v64c3re1
- Не взятые ветвления обычно дешевле.
Хотя ты заметишь, что можно было бы спланировать и лучше, но lcc частенько так «косячит», так что привыкай. Только не надо вновь загонять про «вот напишут нормальный компилятор и заживём». Это не такая простая задача как может показаться на первый взгляд.
Вообще-то подготовленный переход позволяет из одной точки перейти на разные метки. А ibranch технически должен быть равен некоему disp на скрытый регистр при начале выполнения + ct (то есть задержка в 3 такта гарантированно прошла).
disp => ct
== 5 тактов.
И если бы он был больше одного такта, то в конце был бы не ibranch .L45, а ct %ctpr1 (если даже считать, что rbranch содержит магию и на ct не заменяется).
Нет всё верно, это тот самый «unhappy path». Зачем зря греть воздух и подготавливать переход? Тем более, что количество доп. конвейеров очень ограничено. В реальных программах компилятор так не делает, т.к. они обычно заняты.
Исходная версия numas13, :
Теперь понял про что. Да, с алиасингом по-другому никак.
Не только. У небольшого базового блока очень большие шансы быть объединённым с другими.
- e2k https://ce.mentality.rip/z/KWfWMT
- 1 гиперблок, 3
fmuld
- 1 гиперблок, 3
- amd64 https://godbolt.org/z/vbP56ozM5
- 2 суперблока, 3
mulsd
- 2 суперблока, 3
Когда в e2k начинается работа с памятью, то всё становится намного веселее. Часть/части базовых блоков начинают мигрировать выше нагружая процессор бесполезной работой, если исполнение не лежит через эту ветку. Но с другой стороны это повышает загруженность ШК и избавляет от и без того медленных ветвлений в e2k.
В e2k всегда будет обращаться в память, даже если эту ветку не надо исполнять. Кеш-промахи будут в любом случае. :)
Но в обоих случаях компилятор не знает что именно будет исполнятся, а это может сильно повлиять на генерируемый код.
- e2k https://ce.mentality.rip/z/5Gq8qn
- Ожидания памяти не будет в худшем случае, но будет вариативная задержка (если не ошибаюсь, 4-7 такта до 16C и 4-5 для 16C) из-за невыставленных nop для fmuld.
- amd64 https://godbolt.org/z/3v64c3re1
- Не взятые ветвления обычно дешевле.
Хотя ты заметишь, что можно было бы спланировать и лучше, но lcc частенько так «косячит», так что привыкай. Только не надо вновь загонять про «вот напишут нормальный компилятор и заживём». Это не такая простая задача как может показаться на первый взгляд.
Вообще-то подготовленный переход позволяет из одной точки перейти на разные метки. А ibranch технически должен быть равен некоему disp на скрытый регистр при начале выполнения + ct (то есть задержка в 3 такта гарантированно прошла).
disp => ct
== 5 тактов.
И если бы он был больше одного такта, то в конце был бы не ibranch .L45, а ct %ctpr1 (если даже считать, что rbranch содержит магию и на ct не заменяется).
Нет всё верно, это тот самый «unhappy path». Зачем зря греть воздух и подготавливать переход? Тем более, что количество доп. конвейеров очень ограничено. В реальных программах компилятор так не делает, т.к. они обычно заняты.