SCM Repository
View of /branches/pure-cfg/src/compiler/codegen/low-to-tree.sml
Parent Directory
|
Revision Log
Revision 562 -
(download)
(annotate)
Wed Feb 23 15:17:44 2011 UTC (9 years, 10 months ago) by jhr
File size: 11407 byte(s)
Wed Feb 23 15:17:44 2011 UTC (9 years, 10 months ago) by jhr
File size: 11407 byte(s)
Working on code generation.
(* low-to-tree.sml * * COPYRIGHT (c) 2011 The Diderot Project (http://diderot-language.cs.uchicago.edu) * All rights reserved. * * This module translates the LowIL representation of a program (i.e., a pure CFG) to * a block-structured AST with nested expressions. * * NOTE: this translation is pretty dumb about variable coalescing (i.e., it doesn't do any). *) structure LowToTree : sig val translate : LowIL.program -> TreeIL.program end = struct structure IL = LowIL structure Ty = LowILTypes structure V = LowIL.Var structure Op = LowOps structure Nd = LowIL.Node structure CFG = LowIL.CFG structure T = TreeIL (* create new tree IL variables *) local fun newVar (name, kind, ty) = T.V{ name = name, id = Stamp.new(), kind = kind, ty = ty } val cnt = ref 0 fun genName prefix = let val n = !cnt in cnt := n+1; String.concat[prefix, "_", Int.toString n] end in fun newGlobal x = newVar ("G_" ^ V.name x, T.VK_Global, V.ty x) fun newStateVar (strand, x) = newVar (concat[Atom.toString strand, "_", V.name x], T.VK_State strand, V.ty x) fun newParam x = newVar (genName("p_" ^ V.name x), T.VK_Local, V.ty x) fun newLocal x = newVar (genName("l_" ^ V.name x), T.VK_Local, V.ty x) end fun mkBlock stms = T.Block{locals=[], body=stms} fun mkIf (x, stms, []) = T.S_IfThen(x, mkBlock stms) | mkIf (x, stms1, stms2) = T.S_IfThenElse(x, mkBlock stms1, mkBlock stms2) (* an environment that tracks bindings of variables to target expressions and the list * of locals that have been defined. *) local structure VT = V.Tbl fun decCount (IL.V{useCnt, ...}) = let val n = !useCnt - 1 in useCnt := n; (n <= 0) end datatype target_binding = GLOB of T.var (* variable is global *) | TREE of T.exp (* variable bound to target expression tree *) | DEF of T.exp (* either a target variable or constant for a defined variable *) datatype env = E of { tbl : target_binding VT.hash_table, locals : T.var list } in fun newEnv () = E{tbl = VT.mkTable (512, Fail "tbl"), locals=[]} fun newScope (E{tbl, ...}) = E{tbl=tbl, locals=[]} (* use a variable. If it is a pending expression, we decrement its use count *) fun useVar (E{tbl, ...}) x = (case VT.find tbl x of SOME(GLOB x') => T.E_Var x' | SOME(TREE e) => ( if (decCount x) then ignore(VT.remove tbl x) else (); e) | SOME(DEF e) => e | NONE => raise Fail(concat ["useVar(", V.toString x, ")"]) (* end case *)) (* record a local variable *) fun addLocal (E{tbl, locals}, x) = E{tbl=tbl, locals=x::locals} fun global (E{tbl, ...}, x, x') = VT.insert tbl (x, GLOB x') fun insert (env as E{tbl, ...}, x, exp) = ( VT.insert tbl (x, TREE exp); env) fun rename (env as E{tbl, ...}, x, x') = ( VT.insert tbl (x, DEF(T.E_Var x')); env) fun peekGlobal (E{tbl, ...}, x) = (case VT.find tbl x of SOME(GLOB x') => SOME x' | _ => NONE (* end case *)) fun bindLocal (env, lhs, rhs) = if (V.useCount lhs = 1) then (insert(env, lhs, rhs), []) else let val t = newLocal lhs in (rename(addLocal(env, t), lhs, t), [T.S_Assign(t, rhs)]) end fun bind (env, lhs, rhs) = (case peekGlobal (env, lhs) of SOME x => (rename(env, lhs, x), [T.S_Assign(x, rhs)]) | NONE => bindLocal (env, lhs, rhs) (* end case *)) fun setDef (env, lhs, rhs) = (case peekGlobal (env, lhs) of SOME x => (rename(env, lhs, x), [T.S_Assign(x, rhs)]) | NONE => (insert(env, lhs, rhs), []) (* end case *)) (* at the end of a block, we need to assign any pending expressions to locals. The * blkStms list and the resulting statement list are in reverse order. *) fun endBlock (E{tbl, locals}, blkStms) = let fun doVar (x, TREE e, (locals, stms)) = let val t = newLocal x in VT.insert tbl (x, DEF(T.E_Var t)); (t::locals, T.S_Assign(t, e)::stms) end | doVar (_, _, acc) = acc val (locals, stms) = VT.foldi doVar (locals, blkStms) tbl in (E{tbl=tbl, locals=locals}, stms) end fun doPhi ((lhs, rhs), (env, predBlks : T.stm list list)) = let val t = newLocal lhs val predBlks = ListPair.map (fn (x, stms) => T.S_Assign(t, useVar env x)::stms) (rhs, predBlks) in (rename (addLocal(env, t), lhs, t), predBlks) end fun endScope (E{locals, ...}, stms) = T.Block{ locals = List.rev locals, body = stms } end (* translate a LowIL assignment to a list of zero or more target statements *) fun doAssign (env, (lhs, rhs)) = let fun doLHS () = (case peekGlobal(env, lhs) of SOME lhs' => (env, lhs') | NONE => let val t = newLocal lhs in (rename (addLocal(env, t), lhs, t), t) end (* end case *)) in case rhs of IL.VAR x => setDef (env, lhs, useVar env x) | IL.LIT lit => setDef (env, lhs, T.E_Lit lit) | IL.OP(Op.LoadImage info, [a]) => let val (env, t) = doLHS() in (env, [T.S_LoadImage(t, ImageInfo.dim info, useVar env a)]) end | IL.OP(Op.Input(ty, name), []) => let val (env, t) = doLHS() in (env, [T.S_Input(t, name, NONE)]) end | IL.OP(Op.InputWithDefault(ty, name), [a]) => let val (env, t) = doLHS() in (env, [T.S_Input(t, name, SOME(useVar env a))]) end | IL.OP(rator as Op.LoadVoxels(_, 1), [a]) => bind (env, lhs, T.E_Op(rator, [useVar env a])) | IL.OP(Op.LoadVoxels(info, n), [a]) => let (* loading multiple values from memory may not be supported inline *) val (env, t) = doLHS() in (env, [T.S_LoadVoxels(t, n, useVar env a)]) end | IL.OP(rator, args) => bind (env, lhs, T.E_Op(rator, List.map (useVar env) args)) | IL.CONS args => let (* we give cons expressions names, since not all targets support them inline *) val (env, t) = doLHS() val rhs = List.map (useVar env) args in (env, [T.S_Cons(t, rhs)]) end (* end case *) end datatype open_if (* working on the "then" branch. The fields are statments that preceed the if, the condition, * and the else-branch node. *) = THEN_BR of T.stm list * T.exp * IL.node (* working on the "else" branch. The fields are statments that preceed the if, the condition, * the "then" branch statements, and the node that terminated the "then" branch (will be * a JOIN, DIE, or STABILIZE). *) | ELSE_BR of T.stm list * T.exp * T.stm list * IL.node_kind fun trCFG (env, prefix, onExit, onStabilize, cfg) = let fun join (env, [], _, IL.JOIN _) = raise Fail "JOIN with no open if" | join (env, [], _, _) = raise Fail "no path to exit unimplemented" (* FIXME *) | join (env, THEN_BR(stms1, cond, elseBr)::stk, stms, k) = doNode (env, ELSE_BR(stms1, cond, stms, k)::stk, [], elseBr) | join (env, ELSE_BR(stms, cond, stms1, k1)::stk, stms2, k2) = let val (env, thenBlk) = endBlock (env, stms1) val (env, elseBlk) = endBlock (env, stms2) in case (k1, k2) of (IL.JOIN{phis, succ, ...}, IL.JOIN _) => let val (env, [thenBlk, elseBlk]) = List.foldl doPhi (env, [thenBlk, elseBlk]) (!phis) val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk) in doNode (env, stk, stm::stms, !succ) end | (IL.JOIN{phis, succ, ...}, _) => let val (env, [thenBlk]) = List.foldl doPhi (env, [thenBlk]) (!phis) val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk) in doNode (env, stk, stm::stms, !succ) end | (_, IL.JOIN{phis, succ, ...}) => let val (env, [elseBlk]) = List.foldl doPhi (env, [elseBlk]) (!phis) val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk) in doNode (env, stk, stm::stms, !succ) end | (_, _) => raise Fail "no path to exit unimplemented" (* FIXME *) (* end case *) end and doNode (env, ifStk : open_if list, stms, nd) = ( case Nd.kind nd of IL.NULL => raise Fail "unexpected NULL" | IL.ENTRY{succ} => doNode (env, ifStk, stms, !succ) | k as IL.JOIN{phis, succ, ...} => join (env, ifStk, stms, k) | IL.COND{cond, trueBranch, falseBranch, ...} => doNode (env, THEN_BR(stms, useVar env cond, !falseBranch)::ifStk, [], !trueBranch) | IL.COM {text, succ, ...} => doNode (env, ifStk, T.S_Comment text :: stms, !succ) | IL.ASSIGN{stm, succ, ...} => let val (env, stms') = doAssign (env, stm) in doNode (env, ifStk, stms' @ stms, !succ) end | IL.NEW{strand, args, succ, ...} => raise Fail "NEW unimplemented" | k as IL.DIE _ => join (env, ifStk, T.S_Die :: stms, k) | k as IL.STABILIZE _ => let val suffix = onStabilize env in join (env, ifStk, List.revAppend(suffix, stms), k) end | IL.EXIT _ => let val suffix = onExit env in endScope (env, prefix @ List.revAppend(stms, suffix)) end (* end case *)) in doNode (env, [], [], CFG.entry cfg) end val updateAtom = Atom.atom "update" (* finish the update method. The stateVars are the target names for the state variables and * stateOut is the list of Low IL state variables at the end of the update. *) fun finishUpdate (stateVars, stateOut, isExit) env = let fun saveStateVar (x, x', stms) = let val stm = T.S_Assign(x, useVar env x') in stm :: stms end val stms = if isExit then [T.S_Exit] else [] in ListPair.foldrEq saveStateVar stms (stateVars, stateOut) end fun trMethod (env, stateVars) (IL.Method{name, stateIn, stateOut, body}) = let fun bindStateVar (x, x', (env, stms)) = let val (env, stms') = bindLocal(env, x, T.E_Var x') in (env, stms' @ stms) end val (env, stms) = ListPair.foldrEq bindStateVar (env, []) (stateIn, stateVars) val (onExit, onStabilize) = if Atom.same(name, updateAtom) then (finishUpdate (stateVars, stateOut, true), finishUpdate (stateVars, stateOut, false)) else (fn _ => [], fn _ => raise Fail "unexpected stabilize") in T.Method{name = name, body = trCFG (env, stms, onExit, onStabilize, body)} end fun trStrand env (IL.Strand{name, params, state, stateInit, methods}) = let val params' = List.map newParam params val env = ListPair.foldlEq (fn (x, x', env) => rename(env, x, x')) env (params, params') val stateVars = List.map (fn x => newStateVar(name, x)) state (* finish the strand initialization code by initializing the state variables *) fun finishInit env = let fun initVar (x, x') = T.S_Assign(x', useVar env x) in ListPair.mapEq initVar (state, stateVars) end in T.Strand{ name = name, params = params', state = stateVars, stateInit = trCFG (env, [], finishInit, fn _ => raise Fail "unexpected stabilize", stateInit), methods = List.map (trMethod(env, stateVars)) methods } end fun translate (IL.Program{globals, globalInit, strands}) = let val env = newEnv() val globals = List.map (fn x => let val x' = newGlobal x in global(env, x, x'); x' end) globals in T.Program{ globals = globals, globalInit = trCFG (env, [], fn _ => [], fn _ => raise Fail "unexpected stabilize", globalInit), strands = List.map (trStrand env) strands } end end
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |