Presentation is loading. Please wait.

Presentation is loading. Please wait.

Tim Sheard Oregon Graduate Institute Lecture 4: Staging Interpreters CSE 510 Section FSC Winter 2004 Winter 2004.

Similar presentations


Presentation on theme: "Tim Sheard Oregon Graduate Institute Lecture 4: Staging Interpreters CSE 510 Section FSC Winter 2004 Winter 2004."— Presentation transcript:

1 Tim Sheard Oregon Graduate Institute Lecture 4: Staging Interpreters CSE 510 Section FSC Winter 2004 Winter 2004

2 2Cse583 Winterl 2002 Languages and Calculation The calculator language datatype Exp = Var of string | Add of Exp*Exp | Mult of Exp*Exp | Const of int | Local of string*Exp*Exp; The calculator program (un-staged) fun calc term bindings = case term of Var s => lookup s bindings | Add(x,y) => (calc x bindings) + (calc y bindings) | Mult(x,y) => (calc x bindings) * (calc y bindings) | Const n => n | Local(s,x,y) => calc y ((s,calc x bindings)::bindings);

3 3Cse583 Winterl 2002 Staged solution 1 Just add annoations fun calc2 term bindings = case term of Var s => lookup s bindings | Add(x,y) => | Mult(x,y) => | Const n => lift n | Local(s,x,y) => calc2 y ((s,calc2 x bindings)::bindings); Note how the local “let” is inlined.

4 4Cse583 Winterl 2002 Results 1 val term = Local("x",Add(Const 3, Const 4), Local("y",Mult(Const 6,Var "x"), Add(Var "y",Const 12))); val ans2 = calc2 term []; -| ans2; val it = : Note how the let structure has disappeared

5 5Cse583 Winterl 2002 Staged solution 2 fun calc3 term bindings = case term of Var s => lookup s bindings | Add(x,y) => | Mult(x,y) => | Const n => lift n | Local(s,x,y) => <let val w = ~(calc3 x bindings) in ~(calc3 y ((s, )::bindings)) end>; val ans3 = calc3 term []; val ans3 = <let val a = 3 %+ 4 val b = 6 %* a in b %+ 12 end> :

6 6Cse583 Winterl 2002 Why Stage Interpreters? Interpreters are the classic example for using staging. Interpreter takes a program, its data, and returns the result of applying the program to its data. In transformer style  interp: program -> -> In generator style  interp: program -> result> Avoids the overhead of manipulating the data that represents the program each time it is applied. Dramatic speedups are possible. Abstract way of building a compiler.

7 7Cse583 Winterl 2002 Interpreter Characteristics Recursive descent over the syntax of the language. Ideally, the meaning of an “expression” in a language should depend only on the meaning of its constituent “sub-expressions”. Structure of the “syntax” is what guides the interpreter. One “case” for each kind of expression or statement The use of an environment abstract datatype encodes the meaning of variables encodes the “scope” of binding constructs The use of a “value” or semantic meaning type as the return type of the interpreter.

8 8Cse583 Winterl 2002 The Language datatype Exp = Constant of int (* 5 *) | Variable of string (* x *) | Minus of (Exp * Exp) (* x - 5 *) | Greater of (Exp * Exp) (* x > 1 *) | Times of (Exp * Exp) ; (* x * 4 *) datatype Com = Assign of (string * Exp) (* x := 1 *) | Seq of (Com * Com) (* { x := 1; y := 2 } *) | Cond of (Exp * Com * Com) (* if x then x := 1 else y := 0 *) | While of (Exp * Com) (* while x>0 do x := x - 1 *) | Dec of (string * Exp * Com) (* Dec x = 1 in x := x - 1 *)

9 9Cse583 Winterl 2002 Environment ADT Lookup: string -> env -> int Set: string -> int -> env -> env Ext: string -> int -> env -> env Remove: env -> env type env = (string * int) list ; fun lookup x [] = error ("variable not found: "^x) | lookup x ((y,v)::zs) = if x=y then v else lookup x zs; fun set name v [] = error ("name not found: "^name) | set name v ((z as (y,_))::zs) = if name=y then (y,v)::zs else z::(set name v zs); fun ext nm v zs = (nm,v)::zs; fun remove (z::zs) = zs;

10 10Cse583 Winterl 2002 Simple unstaged interpeters Eval0 :: Exp -> env -> int Value = env -> int The meaning of an exp is a value fun eval0 exp env = case exp of Constant n => n | Variable s => lookup s env | Minus(x,y) => let val a = eval0 x env val b = eval0 y env in a - b end | Greater(x,y) => let val a = eval0 x env val b = eval0 y env in if a '>' b then 1 else 0 end | Times(x,y) => let val a = eval0 x env val b = eval0 y env in a * b end;

11 11Cse583 Winterl 2002 Interp0 : Com -> env -> env fun interpret0 stmt env = case stmt of Assign(name,e) => let val v = eval0 e env in set name v env end | Seq(s1,s2) => let val env1 = interpret0 s1 env val env2 = interpret0 s2 env1 in env2 end | If(e,s1,s2) => let val x = eval0 e env in if x=1 then interpret0 s1 env else interpret0 s2 env end | While(e,body) => let val v = eval0 e env in if v=0 then env else interpret0 (While(e,body))(interpret0 body env) end | Declare(nm,e,stmt) => let val v = eval0 e env val env1 = ext nm v env in remove(interpret0 stmt env1) end; The meaning of a Com is an env transformer.

12 12Cse583 Winterl 2002 Getting ready to stage What is the structure of the source language? Exp and Com What is the structure of the target language? MetaML with “let” and operations on environments and arithmetic What are the staging issues? What is completely known at compile-time  Exp, Com, part of the environment (the names but not the values) How do I connect the structure of the source and target languages.

13 13Cse583 Winterl 2002 Staging (Binding time) improvements type env = (string * int) list; Note the string and the “spine” of the list are known, but the int’s are not. Separate env into two parts. An index (the string and its position in the spine), and a stack (the int’s) type location = int; type index = string list; type stack = int list; eval1 : Exp -> index -> stack -> int interp1: Com -> index -> stack -> stack

14 14Cse583 Winterl 2002 Recoding up environments type location = int; type index = string list; type stack = int list; pos :: string -> index -> location get : location -> stack -> value put: location -> value -> stack -> stack fun get 1 (x::xs) = x | get 0 _ = error "No value at index 0." | get n (x::xs) = get (n-1) xs | get n [] = error "Stack is empty"; fun put 1 v (x::xs) = (v::xs) | put 0 v _ = error "No value at index 0." | put n v (x::xs) = x :: (put (n-1) v xs) | put n v [] = error "Stack is empty";

15 15Cse583 Winterl 2002 eval1 fun eval1 exp index stack = case exp of Constant n => n | Variable s => get (pos s index) stack | Minus(x,y) => let val a = eval1 x index stack val b = eval1 y index stack in a - b end | Greater(x,y) => let val a = eval1 x index stack val b = eval1 y index stack in if a '>' b then 1 else 0 end | Times(x,y) => let val a = eval1 x index stack val b = eval1 y index stack in a * b end;

16 16Cse583 Winterl 2002 interp1 fun interp1 stmt index stack = case stmt of Assign(name,e) => let val v = eval1 e index stack val loc = pos name index in put loc v stack end | Seq(s1,s2) => let val stack1 = interp1 s1 index stack val stack2 = interp1 s2 index stack1 in stack2 end | If(e,s1,s2) => let val x = eval1 e index stack in if x=1 then interp1 s1 index stack else interp1 s2 index stack end

17 17Cse583 Winterl 2002 Interp1 (cont.) fun interp1 stmt index stack = case stmt of... | While(e,body) => let val v = eval1 e index stack in if v=0 then stack else interp1 (While(e,body)) index (interp1 body index stack) end | Declare(nm,e,stmt) => let val v = eval1 e index stack val stack1 = v :: stack in tl (interp1 stmt (nm::index) stack1) end;

18 18Cse583 Winterl 2002 Adding staging annotations fun eval2 exp index stack = case exp of Constant n => lift n | Variable s => | Minus(x,y) => <let val a = ~(eval2 x index stack) val b = ~(eval2 y index stack) in a - b end> | Greater(x,y) => <let val a = ~(eval2 x index stack) val b = ~(eval2 y index stack) in if a '>' b then 1 else 0 end> | Times(x,y) => <let val a = ~(eval2 x index stack) val b = ~(eval2 y index stack) in a * b end>;

19 19Cse583 Winterl 2002 interp2 fun interp2 stmt index stack = case stmt of Assign(name,e) => <let val v = ~(eval2 e index stack) in put ~(lift (pos name index)) v ~stack end> | Seq(s1,s2) => <let val stack1 = ~(interp2 s1 index stack) val stack2 = ~(interp2 s2 index ) in stack2 end> | If(e,s1,s2) => <let val x = ~(eval2 e index stack) in if x=1 then ~(interp2 s1 index stack) else ~(interp2 s2 index stack) end>

20 20Cse583 Winterl 2002 Interp2 (cont) fun interp2 stmt index stack = case stmt of... | While(e,body) => <let val v = ~(eval2 e index stack) in if v=0 then ~stack else ~(interp2 (While(e,body)) index (interp2 body index stack)) end> | Declare(nm,e,stmt) => <let val v = ~(eval2 e index stack) val stack1 = v :: ~stack in tl ~(interp2 stmt (nm::index) ) end>;

21 21Cse583 Winterl 2002 Using the staged code val s0 = Declare("x",Constant 150, Declare("y",Constant 200, Seq(Assign("x",Minus(Variable "x",Constant 1)), Assign("y",Minus(Variable "y",Constant 1))))); val ans2 = ~(interp2 s0 [] )>;

22 22Cse583 Winterl 2002 Results -| val ans2 = let val b = 150 val c = b :: a in %tl (let val d = 200 val e = d :: c in %tl (let val f = %get 1 e val g = 1 val h = f %- g val i = %put 1 h e val j = %get 0 i val k = 1 val l = j %- k val m = %put 0 l i in m end) end) end)> : int list>

23 23Cse583 Winterl 2002 Beware val s1 = Declare("x",Constant 150, Declare("y",Constant 200, While(Greater(Variable "x",Constant 0), Seq(Assign("x",Minus(Variable "x",Constant 1)), Assign("y",Minus(Variable "y",Constant 1)))))); val ans3 = ~(interp2 s1 [] )>; fun interp2 stmt index stack = case stmt of... | While(e,body) => <let val v = ~(eval2 e index stack) in if v=0 then ~stack else ~(interp2 (While(e,body)) index (interp2 body index stack)) end>

24 24Cse583 Winterl 2002 Compare | While(e,body) => <let fun loop stk0 = let val v = ~(eval2 e index ) in if v=0 then stk0 else let val stk1 = ~(interp2 body index ) in loop stk1 end end in loop ~stack end> | While(e,body) => <let val v = ~(eval2 e index stack) in if v=0 then ~stack else ~(interp2 (While(e,body)) index (interp2 body index stack)) end>

25 25Cse583 Winterl 2002 Finally, results! -| val ans3 = %tl (%tl (let fun b c = let val d = %get 1 c val e = if d %'>' 0 then 1 else 0 in if e %= 0 then c else let val f = %get 1 c val g = f %- 1 val h = %put 1 g c val i = %get 0 h val j = i %- 1 val k = %put 0 j h in b k end end in b (200 :: 150 :: a) end)))> : int list>

26 26Cse583 Winterl 2002 Generate and optimize vs Generate optimal code -| dotprod' 3 [0,1,2]; val it = (0 %* %nth 0 a) %+ (1 %* %nth 1 a) %+ (2 %* %nth 2 a) %+ 0)> Rules 1*x = x 0*x = 0 x+0 = x 0 %+ (%nth 1 a) %+ (2 %* %nth 2 a)>

27 27Cse583 Winterl 2002 Writing an optimizer is not easy! (* rule 1: x+0 = x *) (* rule 2: 0*x = 0 *) (* rule 3: 1*x = x *) fun opt ~(g ) + 0> = opt ~(g )> | opt ~(g ) + 0 + ~(h )> = opt ~(g ) + ~(h )> | opt 0 + ~(g )> = opt ~(g )> | opt 0 * ~(g ) + ~(h )> = opt ~(h )> | opt ~(e ) + 0 * ~(g )> = opt ~(e )> | opt ~(e ) + 0 * ~(g ) + ~(h )> = opt ~(e ) + ~(h )> | opt 1 * ~(g ) + ~(h )> = opt ~(g ) + ~(h )> | opt ~(e ) + 1 * ~(g )> = opt ~(e ) + ~(g )> | opt ~(e ) + 1 * ~(g ) + ~(h )> = opt ~(e ) + ~(g ) + ~(h )> | opt x = x;

28 28Cse583 Winterl 2002 Optimal Generation vs Post Generation Optimizing Complexity from several sources. Walking deep over the tree Complexity of pattern matching against code (vs matching against values) Dealing with binding occurrences Optimal generation can be directed by values at generation time.

29 29Cse583 Winterl 2002 Better Approach fun dpopt n [] ys = | dpopt n [0] ys = | dpopt n [1] ys = | dpopt n [x] ys = | dpopt n (0::xs) ys = | dpopt n (1::xs) ys = | dpopt n (x::xs) ys = ; fun gen n xs = ~(dpopt n xs )>; val ans0 = gen 5 [2,0,1,0,4]; 2 %* %nth 5 a %+ %nth 7 a %+ 4 %* %nth 9 a)>

30 30Cse583 Winterl 2002 Conclusion Interpreters need binding time improvements Split partially static data structures into two parts. E.g. Env = index + stack Split recursion so that it depends only on structure of the data being interpreted Use transformer style for easy construction Let lifting makes code look nice.

31 31Cse583 Winterl 2002 Things to think about Code not very modular What if we wanted to add “print” or some other feature.


Download ppt "Tim Sheard Oregon Graduate Institute Lecture 4: Staging Interpreters CSE 510 Section FSC Winter 2004 Winter 2004."

Similar presentations


Ads by Google