Общие подвыражения – это подвыражения, которые встречаются в нескольких местах программы и вычисляют одно и то же значение.
Пример:
X, Y: ARRAY [1..10, 1..10] OF INTEGER
…
FOR I:=1 TO 10 DO
X[I, 2*J-1]:= Y[I, 2*J]
Терм 2*J является общим подвыражением. Оптимизирующий компилятор должен только один раз сгенерировать код, вычисляющий его, и использовать результат в обоих местах.
Общие подвыражения обычно обнаруживаются при анализе промежуточной формы представления программы.
Примеру соответствует следующая последовательность четверок:
(1):= #1 I {инициализация цикла}
(2) JGT I #10 (20)
(3) - I #1 i1 {вычисление индексов для X}
(4) * i1 #10 i2
(5) * #2 J i3
(6) - i3 #1 i4
(7) - i4 #1 i5
(8) + i2 i5 i6
(9) * i6 #2 i7
(10) - I #1 i8 {вычисление индексов для Y}
(11) * i8 #10 i9
(12) * #2 J i10
(13) - i10 #1 i11
(14) + i9 i11 i12
(15) * i12 #2 i13
(16):= Y[i13] X[i7]
(17) + #1 I i14 {конец цикла}
(18):= i14 I
(19) J (2)
(20) {следующее предложение}
Четверки (5) и (12) совпадают, за исключением имени получаемого промежуточного результата. Операнд J не меняет своего значения между четверками (5) и (12). Таким образом, четверки (5) и (12) вычисляют одно и то же значение. Это означает, что мы можем удалить четверку (12) и заменить любые обращения к ее результату (i10) на обращение к переменной i3.
|
|
После замены i10 на i3 мы обнаружим, что четверки (6) и (13) также совпадают, за исключением имени результата. Следовательно, мы можем удалить четверку (13) и заменить i11 на i4.
Аналогично четверки (10) и (11) также могут быть удалены, поскольку они эквивалентны четверкам (3) и (4).
2. Удаление инвариантов цикла
Так называются подвыражения внутри цикла, результирующие значения которых не изменяются внутри цикла при переходе от одной итерации к другой. Таким образом, эти значения могут быть вычислены только один раз перед входом в тело цикла.
Примером инварианта цикла является вычисление выражения 2*J (четверка 5).
Значение J в цикле не изменяется. Поэтому четверку (5) можно поместить непосредственно перед циклом. Аналогичные соображения справедливы относительно четверок (6) и (7).
Получится:
(1) * #2 J i3 {вычисление инвариантов цикла}
(2) - i3 #1 i4
(3) - i4 #1 i5
(4):= #1 I {инициализация цикла}
(5) JGT I #10 (16)
(6) - I #1 i1 {вычисление индексов для X}
(7) * i1 #10 i2
(8) + i2 i5 i6
(9) * i6 #2 i7
(10) + i2 i4 i12 {вычисление индексов для Y}
(11) * i12 #2 i13
(12):= Y[i13] X[i7]
(13) + #1 I i14 {конец цикла}
(14):= i14 I
(15) J (5)
(16) {следующее предложение}
Количество четверок внутри тела цикла уменьшилось, с 14 до 11. Тело цикла выполняется 10 раз, поэтому общее количество операций, необходимых для выполнения FOR, сократилось со 141 до 114.