Отключение 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"