Компиляторы
Удаление инвариантных выражений из тела цикла
Выражения, не зависящие от счетчика цикла (инварианты цикла), целесообразно выносить за пределы цикла, так как это позволяет уменьшить количество операций:
for (i = 0; i < 10; i++) { a[i] = b * i + 0.35; }
преобразуется следующим образом:
temp = b * 2.0 + 0.35; for (i = 0; i < 10; i++) { a[i] = temp;}
Подстановка функций
Это преобразование заключается в замене обращения к функции ее кодом. Выигрыш в производительности может быть получен благодаря уменьшению накладных расходов на вызов функции и возвращение из нее, а также на передачу параметров.
Часто подстановка функции увеличивает эффективность использования кэш-памяти, так как код становится непрерывным.
Недостатком является увеличение размера программы, которое тем более заметно, чем больше размер функции и чем больше число обращений к ней.
Свертка и распространение констант
Подвыражение, содержащее только константы, вычисляется, а результат его вычисления подставляется в код программы:
a = b + 2.0 / 3.0;
Компилятор заменит данный код следующим:
a = b + 0.666666666666666666667;
Первый вариант более удобен для программиста, поскольку улучшает читаемость кода.
Упростить свертку констант компилятором можно, разместив константное выражение в скобках.
Исключение указателей
При автоматической оптимизации указатель или ссылка могут быть удалены, если известен их адресат:
void sub(int * p) { *p = *p - 5;} int main() { int a; a = 10; sub(&a);
В результате преобразования генерируется следующий код:
a = 10; a -= 5;
Объединение ветвей
Этот вид оптимизации заключается в объединении одинаковых фрагментов кода, например фрагмент кода:
if (b) { y = x*x; z = y * 1.5; } else { y = sin(x); z = y * 1.5; }
после оптимизации будет выглядеть следующим образом:
if (b) { y = x*x; } else { y = sin(x); } z = y * 1.5;
Алгебраическая редукция
Алгебраическая редукция заключается в упрощении алгебраических выражений. Компиляторы могут выполнять редукцию относительно простых выражений, хотя и с определенными ограничениями.
a * b + a * c = a * (b + c) A + a + a + a = a * 4 -(-a) = a A - a = 0 (-a) * (-b) = a * b a * 1 = a a / a = 1 …
Следует обращать внимание на корректность программы после оптимизации с использованием алгебраической редукции.
Редукция логических выражений
Эквивалентные преобразования логических выражений, приводящие к понижению их сложности. Примеры:
!(!a) = a (a&&b) || (a&&c) = a&&(b||c) !a && !b = !(a || b) a && !a = false, a || !a = true a && true = a, a || false = a a && false = false, a || true = true a && a = a (a&&b) || (!a&&c) = a ? b : c
Управление точностью вычислений
Примеры ключей управления точностью:
/fp:precise (-fp-model precise)
/fp:source (-fp-model source)
/fp:fast (-fp-model fast
Исключение переходов Объединение ветвей условного оператора Использование регистровых переменных Использование индуктивных переменных Изменение последовательности выполнения операций
При выполнении арифметических операций с плавающей точкой изменение последовательности операндов может привести к изменению результата пвычисления арифметического выражения. В примере:
float a = -1.0E8, b = 1.0E8, c = 1.23456, y; y = a + b + c; printf("%f\n", y); y = b + c + a; printf("%f", y);
оба результата – разные. ...
Другие виды автоматической оптимизации
- Оптимизация под архитектуру
- Распараллеливание
- Оптимизация с профилированием
- Межпроцедурная оптимизация.
и т.д.
При автоматической оптимизации может измениться поведение программы
Пример изменения поведения программы после оптимизации уровня /O2
bool func() { int a(1000), b(0); for(int i = 0; i < 10000; i++) b = (a-i)/(a-i)*b; return false; }
Компиляторы
Intel - компиляторы C/C++, Fortran. Включены в состав различных пакетов ПО для профессионального разработчика.
Поддерживаются платформы Microsoft Windows и Linux.
Поддерживается работа с оптимизированными библиотеками: Intel®MKL, Intel®IPP.
Эффективная оптимизация для архитектур Intel.
Улучшенная поддержка векторизации (увеличенная разрядность векторных инструкций).
Поддержка Fortran 2008.
Интеграция с Microsoft Visual Studio.
Ссылка на ресурс: http://software.intel.com
GNU Compiler Collection (GCC) - компиляторы C/C++, Объектный C, Fortran, Ada, Java. Поддерживается платформа Linux. Распространяется свободно, в том числе в исходных кодах.
Поддерживаются различные варианты оптимизации, отладки, кодогенерации, компиляции для разных платформ.
Поддерживается Intel® CilkTM Plus.
Ссылка на ресурс: http://gcc.gnu.org/
Oracle Solaris Studio - компиляторы C/C++ и Fortran. Поддерживаются платформы Linux и Solaris, архитектуры x86 и SPARC.
Поддерживаются различные варианты оптимизации, отладки, кодогенерации.
Ссылка на ресурс: http://www.oracle.com
PGI Workstation - компиляторы C/C++ и Fortran. Поддерживаются платформы Linux, Microsoft Windows и MacOS, архитектуры x86, AMD и CUDA.
Поддерживаются различные варианты оптимизации, автоматического распараллеливания, отладки, интеграция с Microsoft Visual Studio.
Fortran 2003.
Ссылка на ресурс: http://www.pgroup.com/
NAG (Numerical Algorithms Group) Fortran Compiler - компилятор Fortran. Поддерживаются платформы Unix, Microsoft Windows и MacOS.
Поддерживаются различные варианты оптимизации, автоматического распараллеливания, отладки.
Fortran 2003/2008.
Ссылка на ресурс: http://www.nag.co.uk
Microsoft Visual C++ - поддерживается платформа Microsoft Windows.
Интеграция в Microsoft Visual Studio.
Ссылка на ресурс: http://www.microsoft.com
Другие компиляторы (в том числе в статусе исследовательских проектов)
Open64
Ссылка на ресурс: http://www.open64.net
Clang
Ссылка на ресурс: http://clang.llvm.org
Portable C compiler
Ссылка на ресурс: http://pcc.ludd.ltu.se/
и другие.