Анализ живых переменных - Live variable analysis
В компиляторы, анализ живых переменных (или просто анализ живучести) это классика анализ потока данных рассчитать переменные которые жить в каждой точке программы. Переменная жить в какой-то момент, если он содержит значение, которое может понадобиться в будущем, или, что эквивалентно, если его значение может быть прочитано до следующей записи переменной.
Пример
Рассмотрим следующую программу:
b = 3c = 5a = f (b * c)
Набор текущих переменных между строками 2 и 3 равен {б
, c
} потому что оба используются в умножении в строке 3. Но набор живых переменных после строки 1 равен только {б
}, поскольку переменная c
обновляется позже, в строке 2. Значение переменной а
не используется в этом коде.
Обратите внимание, что присвоение а
могут быть исключены как а
не используется позже, но недостаточно информации, чтобы оправдать удаление всей строки 3 как ж
могут иметь побочные эффекты (печать до н.э
, возможно).
Выражение в терминах уравнений потока данных
Анализ жизнеспособности - это анализ «назад может». Анализ проводится в назад порядок и поток данных оператор слияния является установить союз. Другими словами, если применить анализ жизнеспособности к функции с определенным количеством логических ветвей внутри нее, анализ выполняется, начиная с конца функции, двигаясь к началу (отсюда «назад»), и переменная считается действующей, если любая из ветвей, движущихся вперед внутри функции, потенциально может (следовательно, «может») нуждаться в текущем значении переменной. Это контрастирует с анализом «обратная обязанность», который вместо этого применяет это условие ко всем ветвям, движущимся вперед.
Уравнения потока данных, используемые для данного базового блока s и выход из блока ж в анализе живых переменных следующие:
- : Набор переменных, которые используются в s перед любым назначением.
- : Набор переменных, которым присвоено значение в s (во многих книгах[требуется разъяснение ], KILL (s) также определяется как набор переменных, которым присвоено значение в s перед любым использованием, но это не меняет решения уравнения потока данных):
Состояние блока - это набор переменных, которые действуют в начале блока. Его исходное состояние - это набор переменных, которые находятся в его конце. Out-State - это объединение in-состояний наследников блока. Передаточная функция оператора применяется, делая записанные переменные мертвыми, а затем делая переменные, которые читаются, активными.
Второй пример
// in: {} b1: a = 3; b = 5; d = 4; х = 100; // x никогда не используется позже, поэтому не в исходном наборе {a, b, d} if a> b then // out: {a, b, d} // объединение всех (входящих) наследников b1 => b2: {a, b} и b3: {b, d} // in: {a, b} b2: c = a + b; d = 2; // out: {b, d} // in: {b, d} b3: endif c = 4; return b * d + c; // выход: {} |
В состоянии b3 содержится только б и d, поскольку c была написана. Выходное состояние b1 - это объединение внутренних состояний b2 и b3. Определение c в b2 можно удалить, так как c не жить сразу после заявления.
Решение уравнений потока данных начинается с инициализации всех входящих и исходящих состояний пустым набором. Список работ инициализируется путем вставки точки выхода (b3) в список работ (типично для обратного потока). Его вычисленное состояние in-state отличается от предыдущего, поэтому вставляются его предшественники b1 и b2, и процесс продолжается. Прогресс суммирован в таблице ниже.
обработка | за пределами штата | старый в штате | новый в штате | список работ |
---|---|---|---|---|
b3 | {} | {} | {б, г} | (b1, b2) |
b1 | {б, г} | {} | {} | (Би 2) |
Би 2 | {б, г} | {} | {а, б} | (b1) |
b1 | {а, б, г} | {} | {} | () |
Обратите внимание, что b1 был введен в список перед b2, что привело к принудительной обработке b1 дважды (b1 был повторно введен как предшественник b2). Вставка b2 перед b1 позволила бы завершить выполнение раньше.
Инициализация с пустым набором - оптимистическая инициализация: все переменные начинаются как мертвые. Обратите внимание, что исходящие состояния не могут сокращаться от одной итерации к следующей, хотя исходное состояние может быть меньше внутреннего. Это видно из того факта, что после первой итерации выходное состояние может измениться только изменением входящего состояния. Поскольку состояние in-state начинается с пустого набора, оно может только увеличиваться в следующих итерациях.