Оптимизация целочисленного деления: Clang vs GCC vs MSVC

Автор блога NukeTheBees решил проверить, как разные компиляторы оптимизируют преобразование 1D-индекса в 3D-координаты сетки. Эта частая задача требует вычисления как частного, так и остатка от деления.
Архитектура x86 позволяет сделать это максимально эффективно - всего двумя инструкциями idiv (она одновременно вычисляет и частное, и остаток, помещая их в разные регистры). Автор протестировал два подхода на C++:
1. Стандартные операторы / и %
2. Использование функции std::div
Что показали компиляторы?
Вариант с операторами (/ и %):
Clang сгенерировал идеальный код: всего 2 инструкции idiv и никаких лишних обращений к памяти.
MSVC оплошал и выдал избыточную третью инструкцию деления при вычислении y.
Вариант с std::div (в надежде помочь компилятору):
- MSVC резко исправился, заинлайнил вызовы и выдал те самые оптимальные 2 idiv.
- Зато Clang и GCC внезапно отказались инлайнить std::div! В итоге они сгенерировали настоящие вызовы функций (call div), что из-за накладных расходов делает этот код медленнее первого варианта.
Ни один из подходов на C++ не смог заставить все три компилятора выдать идеальный машинный код. Поэтому для критически важных участков производительности не стоит слепо доверять компилятору - всегда заглядывайте в сгенерированный ассемблер (например, через Compiler Explorer).
Для просмотра ссылки Войдиили Зарегистрируйся

Автор блога NukeTheBees решил проверить, как разные компиляторы оптимизируют преобразование 1D-индекса в 3D-координаты сетки. Эта частая задача требует вычисления как частного, так и остатка от деления.
Архитектура x86 позволяет сделать это максимально эффективно - всего двумя инструкциями idiv (она одновременно вычисляет и частное, и остаток, помещая их в разные регистры). Автор протестировал два подхода на C++:
1. Стандартные операторы / и %
2. Использование функции std::div
Что показали компиляторы?
Вариант с операторами (/ и %):
Clang сгенерировал идеальный код: всего 2 инструкции idiv и никаких лишних обращений к памяти.
MSVC оплошал и выдал избыточную третью инструкцию деления при вычислении y.
Вариант с std::div (в надежде помочь компилятору):
- MSVC резко исправился, заинлайнил вызовы и выдал те самые оптимальные 2 idiv.
- Зато Clang и GCC внезапно отказались инлайнить std::div! В итоге они сгенерировали настоящие вызовы функций (call div), что из-за накладных расходов делает этот код медленнее первого варианта.
Ни один из подходов на C++ не смог заставить все три компилятора выдать идеальный машинный код. Поэтому для критически важных участков производительности не стоит слепо доверять компилятору - всегда заглядывайте в сгенерированный ассемблер (например, через Compiler Explorer).
Для просмотра ссылки Войди