Определение максимальной глубины стека

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

У меня есть программа, и ее вход является игрушечным языком. Например, я получаю последовательность

Push 1
Push 1
Pop
Pop

В этом случае максимальный стек был бы 2. Более сложный пример использовал бы ответвления.

Push 1
Push true
If   .success
Pop
Jump .continue
.success:
Push 1
Push 1
Pop
Pop
Pop
.continue:

В этом случае максимальный стек был бы 3. Однако не возможно получить максимальный стек путем обхода от начала до конца как показано в этом случае, так как это привело бы к ошибке выхода за нижнюю границу стека на самом деле.

CFGs к спасению можно создать график и обойти каждый возможный путь базисных блоков, которые Вы имеете. Однако, так как количество путей может вырасти быстро для n вершин, которые Вы получаете (n-1)! возможные пути.

Мой текущий подход должен упростить график как можно больше и иметь менее возможные пути. Это работает, но я считал бы это ужасным. Есть ли лучшее (чтение: быстрее) способ приняться за решение этой проблемы? Хорошо, если алгоритм производит глубину стека, которая не оптимальна. Если корректный размер стека является m затем, мое единственное ограничение состоит в том, что результатом n является n> = m. Существует ли, возможно, жадный алгоритм, доступный, который привел бы к хорошему результату здесь?

Обновление: Я знаю о циклах и инварианте, что все слияния потока controlf имеют ту же глубину стека. Я думал, что записываю простой игрушечный язык для иллюстрирования проблемы. В основном у меня есть детерминированный стековый язык (байт-код JVM), таким образом, каждая операция имеет известную дельту стека.

Обратите внимание на то, что у меня действительно есть рабочее решение этой проблемы, которая приводит к хорошим результатам (упростил cfg), но я ищу лучший/быстрее подход.

1
задан Jonathan Leffler 23 March 2013 в 05:44
поделиться

2 ответа

Обычно вы хотите, чтобы глубина стека была инвариантной для скачков и циклов.

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

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

Еще одна вещь, которую вы должны учитывать, - это сделать эффект стека всех кодов операций детерминированным. Примером недетерминированного кода операции может быть: POP IF TopOfStack == 0.

Изменить:

Если у вас есть детерминированный набор кодов операций и инвариант глубины стека, нет необходимости посещать все возможные пути программы. Достаточно выполнить DFS / BFS через CFG, чтобы определить максимальную глубину стека. Это можно сделать за линейное время (в зависимости от количества инструкций), но не быстрее.

Оценка того, нужно ли оценивать базовые блоки, в которых все еще должны быть оценены исходящие края текущего базового блока, не должна иметь отношения к производительности. Даже в худшем случае каждая инструкция представляет собой ЕСЛИ , будет необходимо оценить только 2 * N ребер.

0
ответ дан 3 September 2019 в 00:52
поделиться

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

Что касается вашей аргументации по поводу пути: Имейте в виду, что прыжки допускают циклы, следовательно, без дальнейшего анализа цикл может означать незавершение и переполнение стека (т.е. размер стека увеличивается после каждого выполнения цикла). [n узлов все еще означает бесконечно много путей, если есть цикл]

Вместо фактического выполнения кода вы можете сделать некоторую форму абстрактной интерпретации.

Относительно комментария IVlad: простое подсчитывание толчков неверно из-за существования возможных циклов.

Я не уверен, какова семантика ваших if-выражений, поэтому это тоже может быть полезно: Предположим, что метка if-выражения может быть только прямой меткой (т.е. вы никогда не можете перепрыгнуть назад в коде). В этом случае ваш аргумент о подсчете путей оживает. По сути, результирующая CFG будет деревом (или DAG, если вы не копируете код). В этом случае вы можете сделать приблизительный подсчет, вычисляя количество переходов снизу вверх и затем беря максимальное количество переходов для обеих ветвей в случае if-выражения. Это все еще не оптимальный правильный результат, но дает лучшее приближение, чем простой подсчет push-выражений.

2
ответ дан 3 September 2019 в 00:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: