stringtranslate.com

Постоянное складывание

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

Постоянное складывание

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

 я = 320 * 200 * 32 ;      

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

Сворачивание констант может использовать арифметические тождества. Если xявляется числовым, значение 0 * xравно нулю, даже если компилятор не знает значение x(обратите внимание, что это недопустимо для чисел с плавающей точкой IEEE, поскольку xможет быть Infinity или NaN . Тем не менее, некоторые среды, которые способствуют производительности, такие как шейдеры 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 - ( a / 5 ); int c = b * 4 ; если ( c > 10 ) { c = c - 10 ; } вернуть c * ( 60 / a );                                   

Применение постоянного распространения один раз, а затем постоянного свертывания дает:

 int a = 30 ; int b = 3 ; int c = b * 4 ; если ( c > 10 ) { c = c - 10 ; } вернуть c * 2 ;                             

Повторение обоих шагов дважды дает:

 int a = 30 ; int b = 3 ; int c = 12 ; если ( истина ) { c = 2 ; } вернуть c * 2 ;                       

Заменив все использования переменных aконстантами b, компилятор применяет к этим переменным функцию устранения мертвого кода , оставляя:

 int c = 12 ;    если ( истина ) { c = 2 ; } вернуть c * 2 ;          

(Булевы конструкции различаются в зависимости от языка и компилятора, но их детали — такие как статус, происхождение и представление истины — не влияют на эти принципы оптимизации.)

Традиционное распространение констант не приводит к дальнейшей оптимизации; оно не реструктурирует программы.

Однако, аналогичная оптимизация, sparse conditional constant propagation , идет дальше, выбирая соответствующую условную ветвь, [2] и удаляя всегда истинный условный тест. Таким образом, переменная cстановится избыточной, и остается только операция над константой:

 возврат 4 ; 

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

Смотрите также

Ссылки

  1. ^ Стивен Мучник; Muchnick and Associates (15 августа 1997 г.). Advanced Compiler Design Implementation . Морган Кауфманн. ISBN 978-1-55860-320-2постоянное распространение ИЛИ постоянное сворачивание.
  2. ^ Вегман, Марк Н.; Задек, Ф. Кеннет (апрель 1991 г.), «Константное распространение с условными ветвями», ACM Transactions on Programming Languages ​​and Systems , 13 (2): 181–210, CiteSeerX 10.1.1.130.3532 , doi :10.1145/103135.103136, S2CID  52813828 

Дальнейшее чтение