НОВОСТИ Сколько инструкций процессора использует компилятор?

Alvaros
Онлайн
Регистрация
14.05.16
Сообщения
21.452
Реакции
101
Репутация
204
Месяц назад я , сколько разных инструкций поддерживается современными процессорами, и насчитал 945 в Ice Lake. Комментаторы : какая часть всего этого разнообразия реально используется компиляторами? Например, некто Pepijn de Vos в 2016 , сколько разных инструкций задействовано в бинарниках у него в /usr/bin, и насчитал 411 — т.е. примерно треть всех инструкций x86_64, существовавших на тот момент, не использовались ни в одной из стандартных программ в его ОС. Другая любопытная его находка — что код для x86_64 на треть состоит из инструкций mov. (В общем-то , что одних инструкций mov достаточно, чтобы написать любую программу.)

Я решил развить исследование de Vos, взяв в качестве «эталонного кода» компилятор LLVM/Clang. У него сразу несколько преимуществ перед содержимым /usr/bin неназванной версии неназванной ОС:

  1. С ним удобно работать: это один огромный бинарник, по размеру сопоставимый со всем содержимым /usr/bin среднестатистического линукса;
  2. Он позволяет сравнить разные ISA: на доступны официальные бинарники для x86, ARM, SPARC, MIPS и PowerPC;
  3. Он позволяет отследить исторические тренды: официальные бинарники доступны для всех релизов начиная с 2003;
  4. Наконец, в исследовании компиляторов логично использовать компилятор и в качестве подопытного объекта :)

Начну со статистики по мартовскому релизу LLVM 10.0:
ISAРазмер бинарникаОбщее число инструкцийЧисло разных инструкций
AArch64
97 МБ

13,814,975

195
ARMv7A
101 МБ

15,621,010

308
i386
106 МБ

20,138,657

122
PowerPC64LE
108 МБ

17,208,502

288
SPARCv9
129 МБ

19,993,362

122
x86_64
107 МБ

15,281,299

203
В прошлом топике комментаторы , что самый компактный код у них получается для SPARC. Здесь же видим, что бинарник для AArch64 оказывается на треть меньше что по размеру, что по общему числу инструкций.

А вот распределение по числу инструкций:
khwwhmu8v3ybigswfc2qkw_h9wu.png
j9spjenramwfdy81yg1knir-vxa.png
98x0s1ug_plt-kum6z-pnequy3k.png
fmuobun0f3s-ou6wq4qbsaht0yk.png
7v6hj10_uzguo7gnlinmk8nqiaq.png
xgxzquiy039jdtqw2u708x7be1k.png


Неожиданно, что код для SPARC на 11% состоит из nop-ов, заполняющих . Для i386 среди самых частых инструкций видим и int3, заполняющую промежутки между функциями, и nop, используемую для выравнивания циклов на строки кэша. Наблюдение de Vos о том, что код на треть состоит из mov, подтверждается на обоих вариантах x86; но даже и на load-store-архитектурах mov оказывается если не самой частой инструкцией, то второй после load.

А как набор используемых инструкций менялся со временем?

Единственная ISA, для которой в каждом релизе есть официальный бинарник — это i386:
jm90tpkyf7o9o9asxx6lkyedpvg.png


Серая линия, отложенная на правой оси — это число разных инструкций, использованных в компиляторе. Как мы видим, некоторое время назад компилятор компилировался гораздо разнообразнее. int3 стала использоваться для заполнения промежутков только с 2018; до этого использовались такие же nop, как и для выравнивания внутри функций. Здесь же видно, что выравнивание внутри функций стало использоваться с 2013; до этого nop-ов было гораздо меньше. Ещё интересно, что до 2016 mov-ы составляли почти половину компилятора.

Самые первые версии LLVM, до появления clang, выпускались ещё и с бинарниками для SPARC. Потом поддержка SPARC утратила актуальность, и вновь она появилась лишь через 14 лет — с на порядок увеличившимся числом nop-ов:
yxcbax8rti9hvxewftfrhy3casg.png


Исторически следующая ISA, для которой выпускались бинарники LLVM — это PowerPC: сначала для Mac OS X и затем, после десятилетнего перерыва, для RHEL. Как видно из графика, переход после этого перерыва к 64-битному варианту ISA сопровождался заменой большинства lwz на ld, и вдобавок удвоением разнообразия инструкций:
3uryiswbi_mulnxmx-fhmd1dkeu.png


В бинарниках для x86_64 и ARM частота использования разных инструкций почти не изменялась:
nw-36tjm3kcixpao1e477xqss8o.png


m96qg_c_icdo7tfhkdortqzm708.png


При подсчёте инструкций ARM я отсекал — вместе с ними получалось около тысячи разных инструкций, но даже и без них ARM сильно опережает другие ISA по разнообразию генерируемых инструкций. Таким образом, слой b на этом графике включает и все условные переходы тоже. Для остальных ISA, где условными могут быть только переходы и немногие другие инструкции, суффиксы условий при подсчёте не отсекались.

Наконец, самая недавняя ISA, для которой публикуются официальные бинарники — это AArch64. Здесь интересно то, что orr с прошлого года почти перестала использоваться:
p3t5bn-h4uc-ve0khw7pancivxu.png


PowerPC и AArch64 оказались единственными ISA, для которых число разных используемых инструкций всё растёт и растёт.
 
Сверху Снизу