Web page for IU Compiler Course for Fall 2020
View the Project on GitHub IUCompilerCourse/IU-P423-P523-E313-E513-Fall-2020
Example program:
(let ([sum 0])
(let ([i 5])
(begin
(while (> i 0)
(begin
(set! sum (+ sum i))
(set! i (- i 1))))
sum)))
An example that involves lambda
:
(let ([x 0])
(let ([y 0])
(let ([z 20])
(let ([f (lambda: ([a : Integer]) : Integer (+ a (+ x z)))])
(begin
(set! x 10)
(set! y 12)
(f y))))))
Yet another example:
(define (f [x : Integer]) : (Vector ( -> Integer) ( -> Void))
(vector
(lambda: () : Integer x)
(lambda: () : Void (set! x (+ 1 x)))))
(let ([counter (f 0)])
(let ([get (vector-ref counter 0)])
(let ([inc (vector-ref counter 1)])
(begin
(inc)
(get)))))
To extend the lifetime of variables, we can “box” them, that is, put them on the heap.
If a variable is never on the LHS of a set!
, then there is no need
to box it. We can copy its value into a closure to extend its life.
If a variable is not free in any lambda
, then there is also no need
to box it, even if it is assigned-to. We can translate set!
into
assignment in C7.
So for this example, we box x
but not y
, z
, and a
.
(let ([x 0])
(let ([y 0])
(let ([z 20])
(let ([f (lambda: ([a : Integer]) : Integer (+ a (+ x z)))])
(begin
(set! x 10)
(set! y 12)
(f y))))))
==>
(define (main) : Integer
(let ([x0 (vector 0)])
(let ([y1 0])
(let ([z2 20])
(let ([f4 (lambda: ([a3 : Integer]) : Integer
(+ a3 (+ (vector-ref x0 0) z2)))])
(begin
(vector-set! x0 0 10)
(set! y1 12)
(f4 y1)))))))
To determine which variables to box, create a auxiliary function
assigned&free
that returns the set of variables that are
assigned-to, the set of variables that are free-in-a-lambda, and an
updated expression in which the bound variables that are both
assigned-to and free-in-a-lambda have been marked with the
AssignedFree
AST node.
Recipe for boxing a variable:
initialize the variable with a one-element vector containing the original initializer.
(Let (AssignedFree x) e body)
==>
(Let x (Prim 'vector (list e')) body')
change uses of the variable to vector-ref
.
(Var x)
==>
(Prim 'vector-ref (list (Var x) (Int 0)))
change set!
with the variable on the LHS to a vector-set!
.
(SetBang x e)
==>
(Prim 'vector-set! (list (Var x) (Int 0) e'))
The while
, set!
, and begin
expressions are all complex,
so they should be let-bound to temporary variables.
Their subexpressions are allowed to be complex.
(let ([x0 10])
(let ([y1 0])
(+ (+ (begin (set! y1 (read)) x0)
(begin (set! x0 (read)) y1))
x0)))
==>
(let ([x0 10])
(let ([y1 0])
(let ([tmp1 (begin (set! y1 (read)) x0)]) ;; GOOD!
(let ([tmp2 (begin (set! x0 (read)) y1)])
(+ (+ tmp1 tmp2)
x0)))))
or??
(let ([x0 10])
(let ([y1 0])
(begin
(set! y1 (read)) ;;; WRONG!
(set! x0 (read))
(+ (+ x0 y1) x0))))
(rco-atom (Begin es body))
=
(values (Var tmp)
(tmp . (Begin es^ body^)))
where
es^ = (map rco-exp es)
body^ = (rco-exp body)
To handle begin
, we need a new auxiliary function:
explicate-effect
. It takes an expression and a continuation block
and produces a block that performs the effects in the expression
followed by the block.
(explicate-effect (Int n) cont)
==>
cont
(explicate-effect (SetBang x e) cont)
==>
(explicate-assign x e cont)
(explicate-effect (Begin es body) cont)
==>
es'
where
body' = (explicate-effect body cont)
and es'
is the reslult of applying explicate-effect
to each
expression in es
, back-to-front, using body'
as the initial
continuation. (Hint: use for/foldr
.)
(explicate-tail (Begin es body))
===>
body^ = (explicate-tail body)
(for/foldr ([cont body^]) ([e es])
(explicate-effect e cont))
(explicate-effect (Call e es) cont)
==>
(Seq (Call e es) (force cont))
There are three new kinds of statements in C7:
Call
read
vector-set!
(explicate-effect (Prim '+ args) cont)
===>
cont
Add cases for the three new statements: Call
, read
, and
vector-set!
by adapting the code generation for those forms in
assignment position.
Use dataflow analysis in uncover-live
.