+++ title = "Отключение SIMD" weight = 2 path = "ru/disable-simd" template = "edition-2/extra.html" +++ Инструкции [Single Instruction Multiple Data (SIMD)] способны выполнять операцию (например, сложение) одновременно над несколькими словами данных, что может значительно ускорить работу программ. Архитектура `x86_64` поддерживает различные стандарты SIMD: [Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD - [MMX]: Набор инструкций _Multi Media Extension_ был представлен в 1997 году и определяет восемь 64-битных регистров, называемых `mm0` - `mm7`. Эти регистры являются псевдонимами регистров [x87 блока с плавающей запятой][x87 floating point unit]. - [SSE]: Набор инструкций _Streaming SIMD Extensions_ был представлен в 1999 году. Вместо повторного использования регистров с плавающей запятой он добавляет совершенно новый набор регистров. Шестнадцать новых регистров называются `xmm0` - `xmm15` и имеют размер 128 бит каждый. - [AVX]: _Advanced Vector Extensions_ - это расширения, которые еще больше увеличивают размер мультимедийных регистров. Новые регистры называются `ymm0` - `ymm15` и имеют размер 256 бит каждый. Они расширяют регистры `xmm`, поэтому, например, `xmm0` - это нижняя половина `ymm0`. [MMX]: https://en.wikipedia.org/wiki/MMX_(instruction_set) [x87 floating point unit]: https://en.wikipedia.org/wiki/X87 [SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions [AVX]: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions Используя такие стандарты SIMD, программы часто могут значительно ускориться. Хорошие компиляторы способны автоматически преобразовывать обычные циклы в такой SIMD-код с помощью процесса, называемого [автовекторизацией][auto-vectorization]. [auto-vectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization Однако большие регистры SIMD приводят к проблемам в ядрах ОС. Причина в том, что ядро должно создавать резервные копии всех регистров, которые оно использует, в память при каждом аппаратном прерывании, потому что они должны иметь свои первоначальные значения, когда прерванная программа продолжает работу. Поэтому, если ядро использует SIMD-регистры, ему приходится резервировать гораздо больше данных (512-1600 байт), что заметно снижает производительность. Чтобы избежать этого снижения производительности, мы хотим отключить функции `sse` и `mmx` (функция `avx` отключена по умолчанию). Мы можем сделать это через поле `features` в нашей целевой спецификации. Чтобы отключить функции `mmx` и `sse`, мы добавим их с минусом: ```json "features": "-mmx,-sse" ``` ## Числа с плавающей точкой К сожалению для нас, архитектура `x86_64` использует регистры SSE для операций с числами с плавающей точкой. Таким образом, каждое использование чисел с плавающей точкой с отключенным SSE вызовёт ошибку в LLVM. Проблема в том, что библиотека `core` уже использует числа с плавающей точкой (например, в ней реализованы трейты для `f32` и `f64`), поэтому недостаточно избегать чисел с плавающей точкой в нашем ядре. К счастью, LLVM поддерживает функцию `soft-float`, эмулирующую все операции с числавами с плавающей точкой через программные функции, основанные на обычных целых числах. Это позволяет использовать плавающие числа в нашем ядре без SSE, просто это будет немного медленнее. Чтобы включить функцию `soft-float` для нашего ядра, мы добавим ее в строку `features` в спецификации цели с префиксом плюс: ```json "features": "-mmx,-sse,+soft-float" ```