Полный контроллер factorial с входной меткой, меткой базового случая, сохраненными продолжениями, общей точкой возврата и возвратом через continue.
Вопрос для размышления
Какое состояние машины заменяет неявный стек вызовов рекурсивной процедуры исходного кода?
Чтение полного ассемблированного списка инструкций для одной рекурсивной процедуры
Определение меток entry, after-call, base-case и done
Сохранение продолжения вызывающей стороны и живого аргумента перед рекурсивным вызовом
Восстановление состояния перед умножением возвращенного значения
Косвенный возврат через регистр continue
Измерение числа входов, количества инструкций, максимальной глубины стека и финального баланса стека
Скомпилированный листинг начинается с factorial-entry. Каждый вызов, кроме базового случая, сохраняет continue и n, уменьшает n, устанавливает after-factorial в качестве нового адреса возврата и переходит обратно к той же метке entry. Базовый случай помещает 1 в val и выполняет возврат через continue. Метка after-factorial восстанавливает состояние вызывающей стороны, умножает n на возвращенное значение val и снова выполняет возврат.
Измерительный запуск начинается с n = 5 и регистром continue, указывающим на done. Наблюдается шесть входов, включая n = 0. Пять приостановленных вызовов хранят по два значения в стеке, поэтому максимальная глубина стека равна 10. Все десять значений восстанавливаются до инструкции halt. 66 выбранных инструкций и точный листинг контроллера измеряют эту конечную скомпилированную процедуру.
Проследите, как continue меняется с done на after-factorial перед каждым рекурсивным переходом. В базовом случае проследите пять косвенных возвратов через один и тот же код after-call. Сопоставьте каждую пару инструкций save с последующими restore и убедитесь, что глубина стека возвращается с 10 до 0 перед тем, как финальный goto достигнет done.
Попробуйте сами
Измените программу и сравните результат.
Переведите рекурсивную процедуру Fibonacci или возведения в степень в такой же явный листинг. Укажите, какие регистры остаются живыми между каждым рекурсивным вызовом, и спрогнозируйте максимальную глубину стека для одного репрезентативного входного значения.
Показать подсказку
Сохраняйте только продолжение и значения, необходимые после возврата рекурсивного результата. Процедура с двумя рекурсивными вызовами должна также сохранять первое возвращенное значение во время вычисления второго.