Writing an OS in Rust

Philipp Oppermann's blog

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

Comments

Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's code of conduct. This comment thread directly maps to a discussion on GitHub, so you can also comment there if you prefer.

Instead of authenticating the giscus application, you can also comment directly on GitHub.