Отключение SIMD
Инструкции Single Instruction Multiple Data (SIMD) способны выполнять операцию (например, сложение) одновременно над несколькими словами данных, что может значительно ускорить работу программ. Архитектура x86_64
поддерживает различные стандарты SIMD:
- MMX: Набор инструкций Multi Media Extension был представлен в 1997 году и определяет восемь 64-битных регистров, называемых
mm0
-mm7
. Эти регистры являются псевдонимами регистров x87 блока с плавающей запятой. - SSE: Набор инструкций Streaming SIMD Extensions был представлен в 1999 году. Вместо повторного использования регистров с плавающей запятой он добавляет совершенно новый набор регистров. Шестнадцать новых регистров называются
xmm0
-xmm15
и имеют размер 128 бит каждый. - AVX: Advanced Vector Extensions - это расширения, которые еще больше увеличивают размер мультимедийных регистров. Новые регистры называются
ymm0
-ymm15
и имеют размер 256 бит каждый. Они расширяют регистрыxmm
, поэтому, например,xmm0
- это нижняя половинаymm0
.
Используя такие стандарты SIMD, программы часто могут значительно ускориться. Хорошие компиляторы способны автоматически преобразовывать обычные циклы в такой SIMD-код с помощью процесса, называемого автовекторизацией.
Однако большие регистры SIMD приводят к проблемам в ядрах ОС. Причина в том, что ядро должно создавать резервные копии всех регистров, которые оно использует, в память при каждом аппаратном прерывании, потому что они должны иметь свои первоначальные значения, когда прерванная программа продолжает работу. Поэтому, если ядро использует SIMD-регистры, ему приходится резервировать гораздо больше данных (512-1600 байт), что заметно снижает производительность. Чтобы избежать этого снижения производительности, мы хотим отключить функции sse
и mmx
(функция avx
отключена по умолчанию).
Мы можем сделать это через поле features
в нашей целевой спецификации. Чтобы отключить функции mmx
и sse
, мы добавим их с минусом:
"features": "-mmx,-sse"
Числа с плавающей точкой
К сожалению для нас, архитектура x86_64
использует регистры SSE для операций с числами с плавающей точкой. Таким образом, каждое использование чисел с плавающей точкой с отключенным SSE вызовёт ошибку в LLVM. Проблема в том, что библиотека core
уже использует числа с плавающей точкой (например, в ней реализованы трейты для f32
и f64
), поэтому недостаточно избегать чисел с плавающей точкой в нашем ядре.
К счастью, LLVM поддерживает функцию soft-float
, эмулирующую все операции с числавами с плавающей точкой через программные функции, основанные на обычных целых числах. Это позволяет использовать плавающие числа в нашем ядре без SSE, просто это будет немного медленнее.
Чтобы включить функцию soft-float
для нашего ядра, мы добавим ее в строку features
в спецификации цели с префиксом плюс:
"features": "-mmx,-sse,+soft-float"