Санкт-Петербургский государственный университет
Опубликован: 11.10.2012 | Доступ: свободный | Студентов: 955 / 173 | Длительность: 05:14:00
Лекция 9:

Компиляторы

Удаление инвариантных выражений из тела цикла

Выражения, не зависящие от счетчика цикла (инварианты цикла), целесообразно выносить за пределы цикла, так как это позволяет уменьшить количество операций:

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/

и другие.