Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /trunk/src/compiler/tree-il/low-to-tree-fn.sml
ViewVC logotype

Annotation of /trunk/src/compiler/tree-il/low-to-tree-fn.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1301 - (view) (download)

1 : jhr 1115 (* low-to-tree-fn.sml
2 :     *
3 :     * COPYRIGHT (c) 2011 The Diderot Project (http://diderot-language.cs.uchicago.edu)
4 :     * All rights reserved.
5 :     *
6 :     * This module translates the LowIL representation of a program (i.e., a pure CFG) to
7 :     * a block-structured AST with nested expressions.
8 :     *
9 :     * NOTE: this translation is pretty dumb about variable coalescing (i.e., it doesn't do any).
10 :     *)
11 :    
12 :     functor LowToTreeFn (Target : sig
13 :    
14 :     (* tests for whether various expression forms can appear inline *)
15 :     val inlineCons : int -> bool (* can n'th-order tensor construction appear inline *)
16 :     val inlineMatrixExp : bool (* can matrix-valued expressions appear inline? *)
17 :    
18 :     end) : sig
19 :    
20 :     val translate : LowIL.program -> TreeIL.program
21 :    
22 :     end = struct
23 :    
24 :     structure IL = LowIL
25 :     structure Ty = LowILTypes
26 :     structure V = LowIL.Var
27 :     structure Op = LowOps
28 :     structure Nd = LowIL.Node
29 :     structure CFG = LowIL.CFG
30 :     structure T = TreeIL
31 :     structure VA = VarAnalysis
32 :    
33 :     (* create new tree IL variables *)
34 :     local
35 :     fun newVar (name, kind, ty) = T.V{
36 :     name = name,
37 :     id = Stamp.new(),
38 :     kind = kind,
39 :     ty = ty
40 :     }
41 :     val cnt = ref 0
42 :     fun genName prefix = let
43 :     val n = !cnt
44 :     in
45 :     cnt := n+1;
46 :     String.concat[prefix, "_", Int.toString n]
47 :     end
48 :     in
49 :     fun newGlobal x = newVar ("G_" ^ V.name x, T.VK_Global, V.ty x)
50 :     fun newStateVar (strand, x) =
51 :     newVar (concat[Atom.toString strand, "_", V.name x], T.VK_State strand, V.ty x)
52 :     fun newParam x = newVar (genName("p_" ^ V.name x), T.VK_Local, V.ty x)
53 :     fun newLocal x = newVar (genName("l_" ^ V.name x), T.VK_Local, V.ty x)
54 :     fun newIter x = newVar (genName("i_" ^ V.name x), T.VK_Local, V.ty x)
55 :     end
56 :    
57 :     fun mkBlock stms = T.Block{locals=[], body=stms}
58 :     fun mkIf (x, stms, []) = T.S_IfThen(x, mkBlock stms)
59 :     | mkIf (x, stms1, stms2) = T.S_IfThenElse(x, mkBlock stms1, mkBlock stms2)
60 :    
61 :     (* an environment that tracks bindings of variables to target expressions and the list
62 :     * of locals that have been defined.
63 :     *)
64 :     local
65 :     structure VT = V.Tbl
66 :     fun decCount (IL.V{useCnt, ...}) = let
67 :     val n = !useCnt - 1
68 :     in
69 :     useCnt := n; (n <= 0)
70 :     end
71 :     datatype target_binding
72 :     = GLOB of T.var (* variable is global *)
73 :     | TREE of T.exp (* variable bound to target expression tree *)
74 :     | DEF of T.exp (* either a target variable or constant for a defined variable *)
75 :     datatype env = E of {
76 :     tbl : target_binding VT.hash_table,
77 :     locals : T.var list
78 :     }
79 :     in
80 :     (* DEBUG *)
81 :     fun bindToString binding = (case binding
82 :     of GLOB y => "GLOB " ^ T.Var.name y
83 :     | TREE e => "TREE"
84 :     | DEF(T.E_Var y) => "DEF " ^ T.Var.name y
85 :     | DEF e => "DEF"
86 :     (* end case *))
87 :     fun dumpEnv (E{tbl, ...}) = let
88 :     fun prEntry (x, binding) =
89 :     print(concat[" ", IL.Var.toString x, " --> ", bindToString binding, "\n"])
90 :     in
91 :     print "*** dump environment\n";
92 :     VT.appi prEntry tbl;
93 :     print "***\n"
94 :     end
95 :     (* DEBUG *)
96 :    
97 :     fun newEnv () = E{tbl = VT.mkTable (512, Fail "tbl"), locals=[]}
98 :    
99 :     (* use a variable. If it is a pending expression, we remove it from the table *)
100 :     fun useVar (env as E{tbl, ...}) x = (case VT.find tbl x
101 :     of SOME(GLOB x') => T.E_Var x'
102 :     | SOME(TREE e) => (
103 :     (*print(concat["useVar ", V.toString x, " ==> TREE\n"]);*)
104 :     ignore(VT.remove tbl x);
105 :     e)
106 :     | SOME(DEF e) => (
107 :     (*print(concat["useVar ", V.toString x, " ==> ", bindToString(DEF e), "; use count = ", Int.toString(V.useCount x), "\n"]);*)
108 :     (* if this is the last use of x, then remove it from the table *)
109 :     if (decCount x) then ignore(VT.remove tbl x) else ();
110 :     e)
111 :     | NONE => (
112 :     dumpEnv env;
113 :     raise Fail(concat ["useVar(", V.toString x, ")"])
114 :     )
115 :     (* end case *))
116 :    
117 :     (* record a local variable *)
118 :     fun addLocal (E{tbl, locals}, x) = E{tbl=tbl, locals=x::locals}
119 :    
120 :     fun global (E{tbl, ...}, x, x') = VT.insert tbl (x, GLOB x')
121 :    
122 :     (* insert a pending expression into the table. Note that x should only be used once! *)
123 :     fun insert (env as E{tbl, ...}, x, exp) = (
124 :     VT.insert tbl (x, TREE exp);
125 :     env)
126 :    
127 :     fun rename (env as E{tbl, ...}, x, x') = (
128 :     VT.insert tbl (x, DEF(T.E_Var x'));
129 :     env)
130 :    
131 :     fun peekGlobal (E{tbl, ...}, x) = (case VT.find tbl x
132 :     of SOME(GLOB x') => SOME x'
133 :     | _ => NONE
134 :     (* end case *))
135 :    
136 :     fun bindLocal (env, lhs, rhs) = if (V.useCount lhs = 1)
137 :     then (insert(env, lhs, rhs), [])
138 :     else let
139 :     val t = newLocal lhs
140 :     in
141 :     (rename(addLocal(env, t), lhs, t), [T.S_Assign(t, rhs)])
142 :     end
143 :    
144 :     fun bind (env, lhs, rhs) = (case peekGlobal (env, lhs)
145 :     of SOME x => (env, [T.S_Assign(x, rhs)])
146 :     | NONE => bindLocal (env, lhs, rhs)
147 :     (* end case *))
148 :    
149 :     (* set the definition of a variable, where the RHS is either a literal constant or a variable *)
150 :     fun bindSimple (env as E{tbl, ...}, lhs, rhs) = (
151 :     case peekGlobal (env, lhs)
152 :     of SOME x => (env, [T.S_Assign(x, rhs)])
153 :     | NONE => (VT.insert tbl (lhs, DEF rhs); (env, []))
154 :     (* end case *))
155 :    
156 :     (* at the end of a block, we need to assign any pending expressions to locals. The
157 :     * blkStms list and the resulting statement list are in reverse order.
158 :     *)
159 :     fun flushPending (E{tbl, locals}, blkStms) = let
160 :     fun doVar (x, TREE e, (locals, stms)) = let
161 :     val t = newLocal x
162 :     in
163 :     VT.insert tbl (x, DEF(T.E_Var t));
164 :     (t::locals, T.S_Assign(t, e)::stms)
165 :     end
166 :     | doVar (_, _, acc) = acc
167 :     val (locals, stms) = VT.foldi doVar (locals, blkStms) tbl
168 :     in
169 :     (E{tbl=tbl, locals=locals}, stms)
170 :     end
171 :    
172 :     fun doPhi ((lhs, rhs), (env, predBlks : T.stm list list)) = let
173 :     (* t will be the variable in the continuation of the JOIN *)
174 :     val t = newLocal lhs
175 :     val predBlks = ListPair.map
176 :     (fn (x, stms) => T.S_Assign(t, useVar env x)::stms)
177 :     (rhs, predBlks)
178 :     in
179 :     (rename (addLocal(env, t), lhs, t), predBlks)
180 :     end
181 :    
182 :     fun endScope (E{locals, ...}, stms) = T.Block{
183 :     locals = List.rev locals,
184 :     body = stms
185 :     }
186 :    
187 :     end
188 :    
189 :     (* Certain IL operators cannot be compiled to inline expressions. Return
190 :     * false for those and true for all others.
191 :     *)
192 :     fun isInlineOp rator = let
193 :     fun chkTensorTy (Ty.TensorTy[]) = true
194 :     | chkTensorTy (Ty.TensorTy[_]) = true
195 :     | chkTensorTy (Ty.TensorTy _) = Target.inlineMatrixExp
196 :     | chkTensorTy _ = true
197 :     in
198 :     case rator
199 :     of Op.LoadVoxels(_, 1) => true
200 :     | Op.LoadVoxels _ => false
201 :     | Op.Add ty => chkTensorTy ty
202 :     | Op.Sub ty => chkTensorTy ty
203 :     | Op.Neg ty => chkTensorTy ty
204 :     | Op.Scale ty => chkTensorTy ty
205 :     | Op.MulMatMat _ => Target.inlineMatrixExp
206 :     | Op.Identity _ => Target.inlineMatrixExp
207 :     | Op.Zero _ => Target.inlineMatrixExp
208 :     | Op.TensorToWorldSpace(_, ty) => chkTensorTy ty
209 :     | _ => true
210 :     (* end case *)
211 :     end
212 :    
213 :     (* translate a LowIL assignment to a list of zero or more target statements *)
214 :     fun doAssign (env, (lhs, rhs)) = let
215 :     fun doLHS () = (case peekGlobal(env, lhs)
216 :     of SOME lhs' => (env, lhs')
217 :     | NONE => let
218 :     val t = newLocal lhs
219 :     in
220 :     (rename (addLocal(env, t), lhs, t), t)
221 :     end
222 :     (* end case *))
223 :     (* for expressions that are going to be compiled to a call statement *)
224 :     fun assignExp (env, exp) = let
225 :     (* operations that return matrices may not be supported inline *)
226 :     val (env, t) = doLHS()
227 :     in
228 :     (env, [T.S_Assign(t, exp)])
229 :     end
230 :     in
231 :     case rhs
232 :     of IL.VAR x => bindSimple (env, lhs, useVar env x)
233 :     | IL.LIT lit => bindSimple (env, lhs, T.E_Lit lit)
234 :     | IL.OP(Op.LoadImage info, [a]) => let
235 :     val (env, t) = doLHS()
236 :     in
237 :     (env, [T.S_LoadImage(t, ImageInfo.dim info, useVar env a)])
238 :     end
239 : jhr 1301 | IL.OP(Op.Input(ty, name, desc), []) => let
240 : jhr 1115 val (env, t) = doLHS()
241 :     in
242 : jhr 1301 (env, [T.S_Input(t, name, desc, NONE)])
243 : jhr 1115 end
244 : jhr 1301 | IL.OP(Op.InputWithDefault(ty, name, desc), [a]) => let
245 : jhr 1115 val (env, t) = doLHS()
246 :     in
247 : jhr 1301 (env, [T.S_Input(t, name, desc, SOME(useVar env a))])
248 : jhr 1115 end
249 :     | IL.OP(rator, args) => let
250 :     val exp = T.E_Op(rator, List.map (useVar env) args)
251 :     in
252 :     if isInlineOp rator
253 :     then bind (env, lhs, exp)
254 :     else assignExp (env, exp)
255 :     end
256 :     | IL.APPLY(f, args) =>
257 :     bind (env, lhs, T.E_Apply(f, List.map (useVar env) args))
258 :     | IL.CONS(ty, args) => let
259 :     val inline = (case ty
260 :     of Ty.IVecTy _ => true
261 :     | Ty.TensorTy dd => Target.inlineCons(List.length dd)
262 :     (* end case *))
263 :     val exp = T.E_Cons(ty, List.map (useVar env) args)
264 :     in
265 :     if inline
266 :     then bind (env, lhs, exp)
267 :     else assignExp (env, exp)
268 :     end
269 :     (* end case *)
270 :     end
271 :    
272 :     (* In order to reconstruct the block-structure from the CFG, we keep a stack of open ifs.
273 :     * the items on this stack distinguish between when we are processing the then and else
274 :     * branches of the if.
275 :     *)
276 :     datatype open_if
277 :     (* working on the "then" branch. The fields are statments that preceed the if, the condition,
278 :     * and the else-branch node.
279 :     *)
280 :     = THEN_BR of T.stm list * T.exp * IL.node
281 :     (* working on the "else" branch. The fields are statments that preceed the if, the condition,
282 :     * the "then" branch statements, and the node that terminated the "then" branch (will be
283 :     * a JOIN, DIE, or STABILIZE).
284 :     *)
285 :     | ELSE_BR of T.stm list * T.exp * T.stm list * IL.node_kind
286 :    
287 :     fun trCFG (env, prefix, finish, cfg) = let
288 :     fun join (env, [], _, IL.JOIN _) = raise Fail "JOIN with no open if"
289 :     | join (env, [], stms, _) = endScope (env, prefix @ List.rev stms)
290 :     | join (env, THEN_BR(stms1, cond, elseBr)::stk, thenBlk, k) = let
291 :     val (env, thenBlk) = flushPending (env, thenBlk)
292 :     in
293 :     doNode (env, ELSE_BR(stms1, cond, thenBlk, k)::stk, [], elseBr)
294 :     end
295 :     | join (env, ELSE_BR(stms, cond, thenBlk, k1)::stk, elseBlk, k2) = let
296 :     val (env, elseBlk) = flushPending (env, elseBlk)
297 :     in
298 :     case (k1, k2)
299 :     of (IL.JOIN{phis, succ, ...}, IL.JOIN _) => let
300 :     val (env, [thenBlk, elseBlk]) =
301 :     List.foldl doPhi (env, [thenBlk, elseBlk]) (!phis)
302 :     val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk)
303 :     in
304 :     doNode (env, stk, stm::stms, !succ)
305 :     end
306 :     | (IL.JOIN{phis, succ, ...}, _) => let
307 :     val (env, [thenBlk]) = List.foldl doPhi (env, [thenBlk]) (!phis)
308 :     val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk)
309 :     in
310 :     doNode (env, stk, stm::stms, !succ)
311 :     end
312 :     | (_, IL.JOIN{phis, succ, ...}) => let
313 :     val (env, [elseBlk]) = List.foldl doPhi (env, [elseBlk]) (!phis)
314 :     val stm = mkIf(cond, List.rev thenBlk, List.rev elseBlk)
315 :     in
316 :     doNode (env, stk, stm::stms, !succ)
317 :     end
318 :     | (_, _) => raise Fail "no path to exit unimplemented" (* FIXME *)
319 :     (* end case *)
320 :     end
321 :     and doNode (env, ifStk : open_if list, stms, nd) = (
322 :     case Nd.kind nd
323 :     of IL.NULL => raise Fail "unexpected NULL"
324 :     | IL.ENTRY{succ} => doNode (env, ifStk, stms, !succ)
325 :     | k as IL.JOIN{phis, succ, ...} => join (env, ifStk, stms, k)
326 :     | IL.COND{cond, trueBranch, falseBranch, ...} => let
327 :     val cond = useVar env cond
328 :     val (env, stms) = flushPending (env, stms)
329 :     in
330 :     doNode (env, THEN_BR(stms, cond, !falseBranch)::ifStk, [], !trueBranch)
331 :     end
332 :     | IL.COM {text, succ, ...} =>
333 :     doNode (env, ifStk, T.S_Comment text :: stms, !succ)
334 :     | IL.ASSIGN{stm, succ, ...} => let
335 :     val (env, stms') = doAssign (env, stm)
336 :     in
337 :     doNode (env, ifStk, stms' @ stms, !succ)
338 :     end
339 :     | IL.NEW{strand, args, succ, ...} => raise Fail "NEW unimplemented"
340 :     | k as IL.EXIT{kind, live, ...} => (case kind
341 :     of ExitKind.FRAGMENT =>
342 :     endScope (env, prefix @ List.revAppend(stms, finish env))
343 : jhr 1232 | ExitKind.SINIT => let
344 :     (* FIXME: we should probably call flushPending here! *)
345 :     val suffix = finish env @ [T.S_Exit(List.map (useVar env) live)]
346 :     in
347 :     endScope (env, prefix @ List.revAppend(stms, suffix))
348 :     end
349 : jhr 1115 | ExitKind.RETURN => let
350 :     (* FIXME: we should probably call flushPending here! *)
351 :     val suffix = finish env @ [T.S_Exit(List.map (useVar env) live)]
352 :     in
353 :     endScope (env, prefix @ List.revAppend(stms, suffix))
354 :     end
355 :     | ExitKind.ACTIVE => let
356 :     (* FIXME: we should probably call flushPending here! *)
357 :     val suffix = finish env @ [T.S_Active(List.map (useVar env) live)]
358 :     in
359 :     endScope (env, prefix @ List.revAppend(stms, suffix))
360 :     end
361 :     | ExitKind.STABILIZE => let
362 :     (* FIXME: we should probably call flushPending here! *)
363 :     val stms = T.S_Stabilize(List.map (useVar env) live) :: stms
364 :     in
365 :     (* FIXME: we should probably call flushPending here! *)
366 :     join (env, ifStk, stms, k)
367 :     end
368 :     | ExitKind.DIE => join (env, ifStk, T.S_Die :: stms, k)
369 :     (* end case *))
370 :     (* end case *))
371 :     in
372 :     doNode (env, [], [], CFG.entry cfg)
373 :     end
374 :    
375 :     fun trInitially (env, IL.Initially{isArray, rangeInit, iters, create=(createInit, strand, args)}) =
376 :     let
377 :     val iterPrefix = trCFG (env, [], fn _ => [], rangeInit)
378 :     fun cvtIter ((param, lo, hi), (env, iters)) = let
379 :     val param' = newIter param
380 :     val env = rename (env, param, param')
381 :     in
382 :     (env, (param', useVar env lo, useVar env hi)::iters)
383 :     end
384 :     val (env, iters) = List.foldr cvtIter (env, []) iters
385 :     val createPrefix = trCFG (env, [], fn _ => [], createInit)
386 :     in {
387 :     isArray = isArray,
388 :     iterPrefix = iterPrefix,
389 :     iters = iters,
390 :     createPrefix = createPrefix,
391 :     strand = strand,
392 :     args = List.map (useVar env) args
393 :     } end
394 :    
395 :     fun trMethod (env, stateVars) (IL.Method{name, stateIn, body}) = let
396 :     fun bindStateVar (x, T.SV{var, ...}, (env, stms)) = let
397 :     val (env, stms') = bindLocal(env, x, T.E_Var var)
398 :     in
399 :     (env, stms' @ stms)
400 :     end
401 :     val (env, stms) = ListPair.foldrEq bindStateVar (env, []) (stateIn, stateVars)
402 :     in
403 :     T.Method{name = name, body = trCFG (env, stms, fn _ => [], body)}
404 :     end
405 :    
406 :     fun trStrand env (IL.Strand{name, params, state, stateInit, methods}) = let
407 :     val params' = List.map newParam params
408 :     val env = ListPair.foldlEq (fn (x, x', env) => rename(env, x, x')) env (params, params')
409 :     val stateVars = let
410 :     fun cvtVar (isOut, x) = T.SV{
411 :     varying = (case VA.varScope x
412 :     of VA.StrandConstState => false
413 :     | VA.StrandState => true
414 :     | s => raise Fail(concat[
415 :     "state variable ", IL.Var.toString x,
416 :     " has bogus scope annotation ", VA.scopeToString s
417 :     ])
418 :     (* end case *)),
419 :     output = isOut, var = newStateVar(name, x)
420 :     }
421 :     in
422 :     List.map cvtVar state
423 :     end
424 :     in
425 :     T.Strand{
426 :     name = name,
427 :     params = params',
428 :     state = stateVars,
429 :     stateInit = trCFG (env, [], fn _ => [], stateInit),
430 :     methods = List.map (trMethod(env, stateVars)) methods
431 :     }
432 :     end
433 :    
434 : jhr 1131 fun checkProps strands = let
435 :     val hasDie = ref false
436 :     val hasNew = ref false
437 :     fun chkStm e = (case e
438 :     of T.S_IfThen(_, b) => chkBlk b
439 :     | T.S_IfThenElse(_, b1, b2) => (chkBlk b1; chkBlk b2)
440 :     | T.S_New _ => (hasNew := true)
441 :     | T.S_Die => (hasDie := true)
442 :     | _ => ()
443 :     (* end case *))
444 :     and chkBlk (T.Block{body, ...}) = List.app chkStm body
445 :     fun chkStrand (T.Strand{stateInit, methods, ...}) = let
446 :     fun chkMeth (T.Method{body, ...}) = chkBlk body
447 :     in
448 :     chkBlk stateInit;
449 :     List.app chkMeth methods
450 :     end
451 :     fun condCons (x, v, l) = if !x then v::l else l
452 :     in
453 :     List.app chkStrand strands;
454 :     condCons (hasDie, T.StrandsMayDie,
455 :     condCons (hasNew, T.NewStrands, []))
456 :     end
457 :    
458 : jhr 1301 (* split the globalInit into the part that specifies the inputs and the rest of
459 :     * the global initialization.
460 :     *)
461 :     fun splitGlobalInit globalInit = let
462 :     fun walk (nd, lastInput, live) = (case Nd.kind nd
463 :     of IL.ENTRY{succ} => walk (!succ, lastInput, live)
464 :     | IL.COM{succ, ...} => walk (!succ, lastInput, live)
465 :     | IL.ASSIGN{stm=(lhs, rhs), succ, ...} => (case rhs
466 :     of IL.OP(Op.Input _, _) => walk (!succ, nd, lhs::live)
467 :     | IL.OP(Op.InputWithDefault _, _) => walk (!succ, nd, lhs::live)
468 :     | _ => walk (!succ, lastInput, live)
469 :     (* end case *))
470 :     | _ => if Nd.isNULL lastInput
471 :     then let (* no inputs *)
472 :     val entry = Nd.mkENTRY()
473 :     val exit = Nd.mkEXIT(ExitKind.RETURN, [])
474 :     in
475 :     Nd.addEdge (entry, exit);
476 :     {inputInit = IL.CFG{entry=entry, exit=exit}, globalInit = globalInit}
477 :     end
478 :     else let (* split at lastInput *)
479 :     val inputExit = Nd.mkEXIT(ExitKind.RETURN, live)
480 :     val globalEntry = Nd.mkENTRY()
481 :     val [gFirst] = Nd.succs lastInput
482 :     in
483 :     Nd.replaceInEdge {src = lastInput, oldDst = gFirst, dst = inputExit};
484 :     Nd.replaceOutEdge {oldSrc = lastInput, src = globalEntry, dst = gFirst};
485 :     {
486 :     inputInit = IL.CFG{entry = IL.CFG.entry globalInit, exit = inputExit},
487 :     globalInit = IL.CFG{entry = globalEntry, exit = IL.CFG.exit globalInit}
488 :     }
489 :     end
490 :     (* end case *))
491 :     in
492 :     walk (IL.CFG.entry globalInit, Nd.dummy, [])
493 :     end
494 :    
495 : jhr 1115 fun translate prog = let
496 :     (* first we do a variable analysis pass on the Low IL *)
497 :     val prog as IL.Program{globalInit, initially, strands} = VA.optimize prog
498 :     (* FIXME: here we should do a contraction pass to eliminate unused variables that VA may have created *)
499 : jhr 1232 val _ = (* DEBUG *)
500 :     LowPP.output (Log.logFile(), "LowIL after variable analysis", prog)
501 : jhr 1115 val env = newEnv()
502 :     val globals = List.map
503 :     (fn x => let val x' = newGlobal x in global(env, x, x'); x' end)
504 :     (IL.CFG.liveAtExit globalInit)
505 : jhr 1301 val {inputInit, globalInit} = splitGlobalInit globalInit
506 : jhr 1131 val strands = List.map (trStrand env) strands
507 : jhr 1115 in
508 :     T.Program{
509 : jhr 1131 props = checkProps strands,
510 : jhr 1115 globals = globals,
511 : jhr 1301 inputInit = trCFG (env, [], fn _ => [], inputInit),
512 : jhr 1115 globalInit = trCFG (env, [], fn _ => [], globalInit),
513 : jhr 1131 strands = strands,
514 : jhr 1115 initially = trInitially (env, initially)
515 :     }
516 :     end
517 :    
518 :     end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0