\( % Latex Preamble definitions here (mostly usepackage) \usepackage% %[dvipsnames] {xcolor} % make sure this is before the loading font packages \newcommand\hmmax{0} \newcommand\bmmax{0} \usepackage{amssymb} \usepackage{amsmath} \usepackage{mathtools} \usepackage %[dvipsnames] {graphicx} \usepackage{float} %\usepackage[numbers]{natbib} \usepackage[document]{ragged2e} % % enumitem doesn't seem to work with beamer %\usepackage[inline]{enumitem} \usepackage{wrapfig} \usepackage{stackrel} % extensible arrows \usepackage{extpfeil} % \usepackage{trfrac} \usepackage{amsthm} \usepackage{tikz} \usepackage{tikz-cd} \usepackage{tikz} \usepackage{tikz-qtree} \usetikzlibrary{automata, positioning, arrows, shapes.geometric} \usepackage{turnstile} \usepackage{comment} %https://tex.stackexchange.com/questions/21334/is-there-a-package-that-has-the-clockwise-gapped-circle-arrow-in-it % \usepackage{mathbx} \usepackage{datetime} \usepackage{datetime2} %% Also See %% http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf %% for general tips \usepackage{listings} \usepackage{subfigure} \usepackage{bm} \usepackage{amsfonts} %% - also included by amssymb \usepackage{mathpazo} %% - because the OP uses mathpazo, optional %\usepackage{tufte-latex} \usepackage{comment} \usepackage{mathtools} \usepackage{bussproofs} \usepackage{hyperref} %\usepackage{cleveref} \)
\( %% Your math definitions here % \newcommand{\alphaequiv}{{\underset{\raise 0.7em\alpha}{=}}} \newcommand{\yields}{\Rightarrow} \newcommand{\derives}{\overset{*}{\yields}} \newcommand{\alphaequiv}{=_{\alpha}} \newcommand{\tto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}} \newcommand{\transitsto}[2]{{\overset{#1}{\underset{#2}{\longrightarrow}}}} \newcommand{\xtransitsto}[2]{{\underset{#2}{\xrightarrow{#1}}}} \newcommand{\xtransitsfrom}[2]{{\underset{#2}{\xleftarrow{#1}}}} \newcommand{\xto}[2]{{\xtransitsto{#1}{#2}}} \newcommand{\xfrom}[2]{{\xtransitsfrom{#1}{#2}}} \newcommand{\xreaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}} \newcommand{\reaches}[2]{{\underset{#2}{\xtwoheadrightarrow{#1}}}} %\newcommand{\reaches}[2]{{\overset{#1}{\underset{#2}{\twoheadrightarrow}}}} %\newcommand{\goesto}[2]{\transitsto{#1}{#2}} %\newcommand{\betareducesto}{{\underset{\beta}{\rightarrow}}} \newcommand{\betareducesto}{\rightarrow_{\beta}} %\newcommand{\etareducesto}{{\underset{\eta}{\rightarrow}}} \newcommand{\etareducesto}{\rightarrow_{\eta}} %\newcommand{\betaetareducesto}{{\underset{\beta\ \eta}{\rightarrow}}} \newcommand{\betaetareducesto}{\rightarrow_{\beta\eta}} \newcommand{\preducesto}{\rhd} \newcommand{\psimplifiesto}{\stackrel{\scriptstyle{*}}{\rhd}} \newcommand{\lreducesto}{\rightsquigarrow} \newcommand{\lsimplifiesto}{\stackrel{\scriptstyle{*}}{\lreducesto}} \newcommand{\rewritesto}{\hookrightarrow} \newcommand{\goesto}[1]{\stackrel{#1}{\rightarrow}} \newcommand{\xgoesto}[1]{\xrightarrow{#1}} \newcommand{\reducesto}{\stackrel{}{\rightarrow}} \newcommand{\simplifiesto}{\stackrel{\scriptstyle{*}}{\rightarrow}} \newcommand{\connected}[1]{\stackrel{#1}{\leftrightarrow}} \newcommand{\joins}{\downarrow} \newcommand{\evaluatesto}{\Longrightarrow} %\newcommand{\lit}[1]{\hbox{\sf{#1}}} \newcommand{\lit}[1]{{\sf{#1}}} \newcommand{\true}{\lit{true}} \newcommand{\false}{\lit{false}} \def\Z{\mbox{${\mathbb Z}$}} \def\N{\mbox{${\mathbb N}$}} \def\P{\mbox{${\mathbb P}$}} \def\R{\mbox{${\mathbb R}$}} \def\T{\mbox{${\mathbb T}$}} \newcommand{\Rp}{{\mathbb{R}}^+} \def\Bool{\mbox{${\mathbb B}$}} \def\Q{\mbox{${\mathbb Q}$}} \def\sA{\mbox{${\cal A}$}} \def\sB{\mbox{${\cal B}$}} \def\sC{\mbox{${\cal C}$}} \def\sD{\mbox{${\cal D}$}} \def\sF{\mbox{${\cal F}$}} \def\sG{\mbox{${\cal G}$}} \def\sL{\mbox{${\cal L}$}} \def\sP{\mbox{${\cal P}$}} \def\sM{\mbox{${\cal M}$}} \def\sN{\mbox{${\cal N}$}} \def\sR{\mbox{${\cal R}$}} \def\sS{\mbox{${\cal S}$}} \def\sO{\mbox{${\cal O}$}} \def\sT{\mbox{${\cal T}$}} \def\sU{\mbox{${\cal U}$}} \def\th{\mbox{$\widetilde{h}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\tP{\mbox{$\widetilde{P}$}} \def\norm{\mbox{$\parallel$}} \def\osum{${{\bigcirc}}\!\!\!\!{\rm s}~$} \def\pf{\noindent {\bf Proof}~~} \def\exec{\mathit{exec}} \def\Act{\mathit{A\!ct}} \def\Traces{\mathit{Traces}} \def\Spec{\mathit{Spec}} \def\uns{\mathit{unless}} \def\ens{\mathit{ensures}} \def\lto{\mathit{leads\!\!-\!\!to}} \def\a{\alpha} \def\b{\beta} \def\c{\gamma} \def\d{\delta} \def\sP{\mbox{${\cal P}$}} \def\sM{\mbox{${\cal M}$}} \def\sA{\mbox{${\cal A}$}} \def\sB{\mbox{${\cal B}$}} \def\sC{\mbox{${\cal C}$}} \def\sI{\mbox{${\cal I}$}} \def\sS{\mbox{${\cal S}$}} \def\sD{\mbox{${\cal D}$}} \def\sF{\mbox{${\cal F}$}} \def\sG{\mbox{${\cal G}$}} \def\sR{\mbox{${\cal R}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\ta{\mbox{$\widetilde{a}$}} \def\tb{\mbox{$\widetilde{b}$}} \def\tc{\mbox{$\widetilde{c}$}} \def\tx{\mbox{$\widetilde{x}$}} \def\ty{\mbox{$\widetilde{y}$}} \def\tz{\mbox{$\widetilde{z}$}} \def\tI{\mbox{$\widetilde{I}$}} \def\norm{\mbox{$\parallel$}} \def\sL{\mbox{${\cal L}$}} \def\sM{\mbox{${\cal M}$}} \def\sN{\mbox{${\cal N}$}} \def\th{\mbox{$\widetilde{h}$}} \def\tg{\mbox{$\widetilde{g}$}} \def\tP{\mbox{$\widetilde{P}$}} \def\norm{\mbox{$\parallel$}} \def\to{\rightarrow} \def\ov{\overline} \def\gets{\leftarrow} \def\too{\longrightarrow} \def\To{\Rightarrow} %\def\points{\mapsto} %\def\yields{\mapsto^{*}} \def\un{\underline} \def\vep{$\varepsilon$} \def\ep{$\epsilon$} \def\tri{$\bigtriangleup$} \def\Fi{$F^{\infty}$} \def\Di{\Delta^{\infty}} \def\ebox\Box \def\emp{\emptyset} \def\leadsto{\rightharpoondown^{*}} \newcommand{\benum}{\begin{enumerate}} \newcommand{\eenum}{\end{enumerate}} \newcommand{\bdes}{\begin{description}} \newcommand{\edes}{\end{description}} \newcommand{\bt}{\begin{theorem}} \newcommand{\et}{\end{theorem}} \newcommand{\bl}{\begin{lemma}} \newcommand{\el}{\end{lemma}} % \newcommand{\bp}{\begin{prop}} % \newcommand{\ep}{\end{prop}} \newcommand{\bd}{\begin{defn}} \newcommand{\ed}{\end{defn}} \newcommand{\brem}{\begin{remark}} \newcommand{\erem}{\end{remark}} \newcommand{\bxr}{\begin{exercise}} \newcommand{\exr}{\end{exercise}} \newcommand{\bxm}{\begin{example}} \newcommand{\exm}{\end{example}} \newcommand{\beqa}{\begin{eqnarray*}} \newcommand{\eeqa}{\end{eqnarray*}} \newcommand{\bc}{\begin{center}} \newcommand{\ec}{\end{center}} \newcommand{\bcent}{\begin{center}} \newcommand{\ecent}{\end{center}} % \newcommand{\la}{\langle} % \newcommand{\ra}{\rangle} \newcommand{\bcor}{\begin{corollary}} \newcommand{\ecor}{\end{corollary}} \newcommand{\bds}{\begin{defns}} \newcommand{\eds}{\end{defns}} \newcommand{\brems}{\begin{remarks}} \newcommand{\erems}{\end{remarks}} \newcommand{\bxrs}{\begin{exercises}} \newcommand{\exrs}{\end{exercises}} \newcommand{\bxms}{\begin{examples}} \newcommand{\exms}{\end{examples}} \newcommand{\bfig}{\begin{figure}} \newcommand{\efig}{\end{figure}} \newcommand{\set}[1]{\{#1\}} \newcommand{\pair}[1]{\langle #1\rangle} \newcommand{\tuple}[1]{\langle #1\rangle} \newcommand{\size}[1]{| #1 |} \newcommand{\union}{\cup} \newcommand{\Union}{\bigcup} \newcommand{\intersection}{\cap} \newcommand{\Intersection}{\bigcap} \newcommand{\B}{\textbf{B}} %\newcommand{\be}[2]{\begin{equation} \label{#1} \tag{#2} \end{equation}} \newcommand{\abs}[1]{{\lvert}#1{\rvert}} \newcommand{\id}[1]{\mathit{#1}} \newcommand{\pfun}{\rightharpoonup} \newcommand{\ra}[1]{\kern-1.5ex\xrightarrow{\ \ #1\ \ }\phantom{}\kern-1.5ex} \newcommand{\ras}[1]{\kern-1.5ex\xrightarrow{\ \ \smash{#1}\ \ }\phantom{}\kern-1.5ex} \newcommand{\da}[1]{\bigg\downarrow\raise.5ex\rlap{\scriptstyle#1}} \newcommand{\ua}[1]{\bigg\uparrow\raise.5ex\rlap{\scriptstyle#1}} % \newcommand{\lift}[1]{#1_{\bot}} \newcommand{\signal}[1]{\tilde{#1}} \newcommand{\ida}{\stackrel{{\sf def}}{=}} \newcommand{\eqn}{\doteq} \newcommand{\deduce}[1]{\sststile{#1}{}} %% These don't sit very well with MathJax %% so we don't plan to use theorem like environments %% in org documents. %% instead we plan to use headings with %% 1. property drawers with a CLASS property identifying %% the environment %% 2. A tag with the same name as the CLASS property %% In LaTeX export, these turn into (sub)sections. %% See http://u.cs.biu.ac.il/~tsaban/Pdf/LaTeXCommonErrs.pdf %% \newtheorem{prop}[thm]{Proposition} %% \theoremstyle{plain}%default %% \newtheorem{theorem}{Theorem}[section] %% \newtheorem{lemma}{Lemma}[section] %% \newtheorem{corollary}{Corollary}[section] %% \newtheorem{definition}{Definition}[section] %% \newtheorem{remark}{Remark}[section] %% \newtheorem{example}{Example}[section] %% \newtheorem{exercise}{Exercise}[section] \newcommand{\less}[1]{#1_{<}} \newcommand{\pfn}{\rightharpoonup} \newcommand{\ffn}{\stackrel{{\sf fin}}{\rightharpoonup}} \newcommand{\stkout}[1]{\ifmmode\text{\sout{\ensuremath{#1}}}\else\sout{#1}\fi} % Caution: Not supported by MathJax! % ---------------------------------- % \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39} % \usepackage{amsfonts} %% <- also included by amssymb % \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39} \usepackage{mathpazo} %% <- because the OP uses mathpazo, optional \newcommand{\mbf}[1]{\mathbf{#1}} \newcommand{\floor}[1]{\left\lfloor #1 \right\rfloor} \newcommand{\ceil}[1]{\left\lceil #1 \right\rceil} \newcommand{\rel}{\twoheadrightarrow} \newcommand{\map}{\rightarrow} %\newcommand{\fixed}{\boldsymbol{\circlearrowleft}} \newcommand{\terminal}{\not\xto{}{}} \newcommand{\fixed}{\bm\circlearrowleft} \newcommand{\imp}{\rightarrow} \newcommand{\dimp}{\leftrightarrow} % double implication \newcommand{\lequiv}{\Longleftrightarrow} % logical equivalence \newcommand{\limplies}{\Rightarrow} \newcommand{\lxor}{\veebar} \)
UP | HOME

Register Machines and Imperative Form

Table of Contents

1 Introduction

The purpose of these notes is to understand an important set of transformations that apply on programs that are already in tail form. Recall that a program is in tail form if every function call in the program is in tail position.

2 Boilerplate   boilerplate

#lang racket
(provide (all-defined-out))
(require rackunit)

3 Example: Factorial

We define and study the transformations on the factorial function.

3.1 Factorial test cases

(check-equal? (! 0) 1 "!:1")
(check-equal? (! 3) 6 "!:2")

4 Factorial: tail form

We start with ! the factorial function defined in tail form.

(define (!/acc n)
  (letrec ([loop (lambda (i a)
		   (if (= 0 i)
		     a
		     (loop (sub1 i) (* a i))))])
    (loop n 1)))

(define ! !/acc)

Notice that ! is in tail form.

5 Imperative form

It is worth examining how the identifiers i and a in the body of loop are created and used. Notice that each call to loop creates a new pair of identifiers i and a. The parameters i and a are used in the inner call to loop. They are, however, never used after the call. This is a consequence of the call to loop being in tail position.

This observation creates an opportunity for the following important transformation: It suffices to use exactly one pair of identifiers across all the invocations of loop. In other words, it is possible to `lift' the formal parameters out of the body of loop and declare them separately via a let. i and a are now mutable variables, i.e., they denote storage locations. In addition loop is now a zero argument function. Parameter passing is now replaced by variable initialization. The resultant program is now said to be in imperative form.

(define (!/imp n)
    (let ([i n] [a 1])
      (letrec ([loop (lambda ()
		       (if (= 0 i)
			   a
			 (begin
			   (set! a (* a i))
			   (set! i (sub1 i))
			   (loop))))])
	(loop))))

(define ! !/imp)

6 Goto form

Also, a zero-argument tail call is akin to a goto, which merely transfers control to another point in the program.

(define (goto f)
  (f))

A further embellishment, done, emphasises the action of returning from the function loop.

(define (done x)
  x)

The register form of the factorial program is obtained by suitably inserting goto's and done's.

(define (!/goto n)
    (let ([i n] [a 1])
      (letrec ([loop (lambda ()
		       (if (= 0 i)
			   (done a) ; instead of a
			 (begin
			   (set! a (* a i))
			   (set! i (sub1 i))
			   (goto loop))))])  ; instead of (loop)
	(goto loop))))

(define ! !/goto)

The program is now essentially a C program, with assignments, and goto's!

7 An equivalent iterative C program

It is easy to transform the Scheme program, almost verbatim, into a C program:

#include<stdio.h>
 int f(int n) {

  int i = n;
  int a = 1;

 loop:

  if (i == 0)
    return a;

  a = a*i;
  i = i-1;
  goto loop;
}

int main() {
  printf("!(0) == %d\n", f(0));
  printf("!(1) == %d\n", f(1));
  printf("!(2) == %d\n", f(2));
  printf("!(3) == %d\n", f(3));
}

8 Register machine form

A further transformation converts the program to register machine form.

Local variables now become global state variables, also called register variables. A special register variable *answer* stores the final answer.

(define uninitialized '_)
(define *n* uninitialized) ; holds the input number
(define *i* uninitialized) ; state variable
(define *a* uninitialized) ; state variable
(define *answer* uninitialized) ; holds the final answer

done now halts the program.

(define (done)
  (void))

All functions now are essentially `basic' blocks of code: They do not take any parameters, nor do they return anything. Execution within a basic block is a sequence of assignment statements or if statements. Control exits the basic block only through a goto or by falling through.

(define (init)
  (begin
    (set! *i* *n*)
    (set! *a* 1)
    (set! *answer* '_) ; uninitialized
    (goto loop)))

(define (loop)
   (if (= 0 *i*)
       (begin
	 (set! *answer* *a*)  
	 (goto done))
       (begin
	 (set! *a* (* *a* *i*))
	 (set! *i* (sub1 *i*))
	 (goto loop))))

8.1 Interface and tests

!/reg begins by initialising the register *n* and then going to init. All register variables, being top-level, are available for inspection.

(define (!/reg n)   ; interface 
  (begin
    (set! *n* n)
    (goto init)))

(define ! !/reg)
;;; unit tests
(begin
  (!/reg 0)
  (check-equal? *answer* 1 "!/reg 0"))

(begin
  (!/reg 1)
  (check-equal? *answer* 1 "!/reg 1"))

(begin
  (!/reg 3)
  (check-equal? *answer* 6 "!/reg 6"))

9 Stepper form

For a program in register form, it is very easy to set up things so that we can step through its execution.

The functions show and step are used as an interface to carry out the stepping:

show
A function of no argument that displays the state of the computation.
step
A function of no argument that takes the computation one `step' forward.

9.1 Program Counter

The key observation is to introduce a new state variable register variable called pc, the program counter.

(define *pc* uninitialized)

The program counter points to the current code block. There are three code blocks in the above example: init, loop and done.

9.2 show displays computation state

show displays all the registers at any given point of time in the computation.

(define show
  (lambda ()
    (printf "*n*: ~a~n" *n*)
    (printf "*i*: ~a~n" *i*)
    (printf "*a*: ~a~n" *a*)
    (printf "*pc*: ~a~n" *pc*)
    (printf "*answer*: ~a~n~n" *answer*)
    (list *n* *i* *a* *pc* *answer*)))

9.3 goto updates the program counter

The role of goto now is to merely update the program counter and yield control back to the top level.

(define (goto l)
  (set! *pc* l))

9.4 step executes one code block

step carries out a transition by executing the code pointed to by *pc*.

(define (step)
  (*pc*))

The definitions of the code blocks init, loop and done are unchanged.

9.5 Interface

The interface

(define (!/stepper n)   ; interface, same !/reg
  (begin
    (set! *n* n)
    (goto init)))

(define ! !/stepper)

9.6 Tests

;;; unit tests

(test-case "(! 0)"
  (! 0)
  (check-equal? (show) 
		(list 0  ; *n*
		      '_  ; *i*
		      '_  ; *a*
		      init ; *pc*
		      '_ ; *answer*
		      ))
  (step)
  (check-equal? (show) 
		(list 0  ; *n*
		      0  ; *i*
		      1  ; *a*
		      loop ; *pc*
		      '_ ; answer
		      ))
  (step)
  (check-equal? (show)
		(list 0  ; *n*
		      0  ; *i*
		      1  ; *a*
		      done ; *pc*
		      1 ; answer
		      )))

10 Conclusion

Accumulator style programs are in tail form. We have seen how a program in tail form may be systematically transformed into an imperative form which closely resembles an iterative C program. The imperative form can further be transformed into a register machine form where all program variables are registers (i.e., global variables), all procedures are top level and they neither take arguments nor return values. The register form program may be transformed to a stepper form that allows one to step through the execution of the program, one basic block at a time.

Author: choppell

Created: 2023-11-25 Sat 09:15

Validate