Сворачивание констант

редактировать
Тип оптимизации компилятора

Сворачивание констант и распространение констант связаны компилятор оптимизации, используемые многими современными компиляторами. Расширенная форма распространения констант, известная как разреженное распространение условных констант, позволяет более точно распространять константы и одновременно удалять мертвый код.

Содержание

  • 1 Сворачивание констант
  • 2 Сворачивание констант и кросс-компиляция
  • 3 Постоянное распространение
  • 4 Оптимизация в действии
  • 5 См. Также
  • 6 Ссылки
  • 7 Дополнительная литература

Постоянное сворачивание

Постоянное сворачивание - это процесс распознавания и оценка констант выражений во время компиляции вместо их вычисления во время выполнения. Термины в постоянных выражениях обычно являются простыми литералами, такими как целочисленный литерал 2, но они также могут быть переменными, значения которых известны во время компиляции. Рассмотрим инструкцию:

i = 320 * 200 * 32;

Большинство компиляторов фактически не генерируют две инструкции умножения и хранилище для этого оператора. Вместо этого они идентифицируют такие конструкции и заменяют вычисленные значения во время компиляции (в данном случае 2,048,000).

Постоянное сворачивание может использовать арифметические тождества. Если xявляется числовым, значение 0 * xравно нулю, даже если компилятор не знает значение x(обратите внимание, что это недопустимо для IEEE float, поскольку xможет быть бесконечным или NotANumber. Тем не менее, некоторые языки, которые поддерживают производительность, например GLSL, допускают это для констант, которые может иногда вызывать ошибки).

Постоянное сворачивание может применяться не только к числам. Объединение строковых литералов и константных строк может быть свернуто констант. Такой код, как "abc" + "def", можно заменить на "abcdef".

Сворачивание констант и кросс-компиляция

При реализации кросс-компилятора необходимо следить за тем, чтобы поведение арифметических операций в архитектуре хоста соответствовало таковому в целевой архитектуре, поскольку в противном случае включение сворачивания констант изменит поведение программы. Это особенно важно в случае операций с плавающей запятой, точная реализация которых может сильно различаться.

Распространение констант

Распространение констант - это процесс подстановки значений известных констант в выражения во время компиляции. К таким константам относятся константы, определенные выше, а также внутренние функции , применяемые к постоянным значениям. Рассмотрим следующий псевдокод:

int x = 14; int y = 7 - x / 2; вернуть y * (28 / x + 2);

Распространение x дает:

int x = 14; int y = 7 - 14/2; вернуть y * (28/14 + 2);

Продолжение распространения дает следующее (которое, вероятно, будет дополнительно оптимизировано с помощью устранения мертвого кода как для x, так и для y.)

int x = 14; int y = 0; возврат 0;

Постоянное распространение реализовано в компиляторах с использованием достижения результатов анализа определения. Если все определения достижения переменной являются одним и тем же назначением, которое присваивает одну и ту же константу переменной, тогда переменная имеет постоянное значение и может быть заменена константой.

Распространение констант также может привести к упрощению условных переходов до одного или нескольких безусловных операторов, когда условное выражение может быть оценено как истинное или ложное во время компиляции, чтобы определить единственно возможный результат.

Оптимизация в действии

Постоянное сворачивание и распространение обычно используются вместе для достижения множества упрощений и сокращений путем их итеративного чередования до тех пор, пока не перестанут происходить изменения. Рассмотрим этот неоптимизированный псевдокод, который возвращает случайное число :

int a = 30; int b = 9 - (а / 5); int c; с = Ь * 4; если (c>10) {c = c - 10; } return c * (60 / a);

Однократное применение распространения константы с последующим сворачиванием констант дает:

int a = 30; int b = 3; int c; с = Ь * 4; если (c>10) {c = c - 10; } return c * 2;

Двойное повторение обоих шагов приводит к следующему:

int a = 30; int b = 3; int c; c = 12; если (правда) {c = 2; } return c * 2;

Поскольку aи bбыли упрощены до констант и их значения заменялись везде, где они встречались, компилятор теперь применяет удаление мертвого кода, чтобы отбросить их, уменьшая код далее:

int c; c = 12; если (правда) {c = 2; } return c * 2;

В приведенном выше коде вместо trueэто может быть 1 или любая другая логическая конструкция в зависимости от структуры компилятора. С традиционным постоянным распространением мы получим только такую ​​оптимизацию. Это не может изменить структуру программы.

Существует еще одна подобная оптимизация, называемая разреженным условным распространением констант, которая выбирает соответствующую ветвь на основе if-condition. Теперь компилятор может определить, что оператор ifвсегда будет оценивать значение true., cсам по себе может быть исключен, еще больше уменьшив код:

return 4;

Если этот псевдокод составляет тело функции, компилятор может дополнительно воспользоваться знанием того, что он вычисляет постоянное целое число 4, чтобы исключить ненужные вызовы функции, что приведет к дальнейшему увеличению производительности.

См. Также

Ссылки

Дополнительная литература

Последняя правка сделана 2021-05-15 10:19:54
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте