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

SCM Repository

[diderot] Diff of /trunk/src/compiler/translate/translate.sml
ViewVC logotype

Diff of /trunk/src/compiler/translate/translate.sml

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 190, Sat Jul 31 04:39:18 2010 UTC revision 2483, Mon Oct 14 16:27:24 2013 UTC
# Line 1  Line 1 
1  (* translate.sml  (* translate.sml
2   *   *
3   * COPYRIGHT (c) 2010 The Diderot Project (http://diderot.cs.uchicago.edu)   * COPYRIGHT (c) 2010 The Diderot Project (http://diderot-language.cs.uchicago.edu)
4   * All rights reserved.   * All rights reserved.
5   *   *
6   * Translate Simple-AST code into the IL representation.   * Translate Simple-AST code into the IL representation.  This translation is based on the
7     * algorithm described in
8     *
9     *      Single-pass generation of static single assignment form for structured languages
10     *      ACM TOPLAS, Nov. 1994
11     *      by Brandis and MossenBock.
12   *)   *)
13    
14  structure Translate : sig  structure Translate : sig
# Line 13  Line 18 
18    end = struct    end = struct
19    
20      structure S = Simple      structure S = Simple
21      structure VMap = Var.Map      structure Ty = SimpleTypes
22      structure VSet = Var.Set      structure VMap = SimpleVar.Map
23        structure VSet = SimpleVar.Set
24      structure IL = HighIL      structure IL = HighIL
25        structure Op = HighOps
26        structure DstTy = HighILTypes
27        structure Census = HighILCensus
28    
29        val cvtTy = TranslateTy.tr
30    
31      (* maps from SimpleAST variables to the current corresponding SSA variable *)
32        type env = IL.var VMap.map
33    
34    (* +DEBUG *)
35        fun prEnv (prefix, env) = let
36              val wid = ref 0
37              fun pr s = (print s; wid := !wid + size s)
38              fun nl () = if (!wid > 0) then (print "\n"; wid := 0) else ()
39              fun prElem (src, dst) = let
40                    val s = String.concat [
41                            " ", SimpleVar.uniqueNameOf src, "->", IL.Var.toString dst
42                          ]
43                    in
44                      pr s;
45                      if (!wid >= 100) then (nl(); pr " ") else ()
46                    end
47              in
48                pr prefix; pr " ENV: {"; nl(); pr " ";
49                VMap.appi prElem env;
50                nl(); pr "}"; nl()
51              end
52    (* -DEBUG *)
53    
54      fun lookup env x = (case VMap.find x      fun lookup env x = (case VMap.find (env, x)
55             of SOME x' => x'             of SOME x' => x'
56              | NONE => raise Fail(concat[              | NONE => raise Fail(concat[
57                    "no binding for ", Var.toString x, " in environment"                    "no binding for ", SimpleVar.uniqueNameOf x, " in environment"
58                  ])                  ])
59            (* end case *))            (* end case *))
60    
61    (* create a new instance of a variable *)    (* create a new instance of a variable *)
62      fun newVar x = IL.newVar (Var.nameOf x)      fun newVar x = IL.Var.new (SimpleVar.nameOf x, cvtTy(SimpleVar.typeOf x))
63    
64      (* generate fresh SSA variables and add them to the environment *)
65        fun freshVars (env, xs) = let
66              fun cvtVar (x, (env, xs)) = let
67                    val x' = newVar x
68                    in
69                      (VMap.insert(env, x, x'), x'::xs)
70                    end
71              val (env, xs) = List.foldl cvtVar (env, []) xs
72              in
73                (env, List.rev xs)
74              end
75    
76      (* a pending-join node tracks the phi nodes needed to join the assignments
77       * that flow into the join node.
78       *)
79        datatype join = JOIN of {
80            env : env,                      (* the environment that was current at the conditional *)
81                                            (* associated with this node. *)
82            arity : int ref,                (* actual number of predecessors *)
83            nd : IL.node,                   (* the CFG node for this pending join *)
84            phiMap : IL.phi VMap.map ref,   (* a mapping from Simple AST variables that are assigned *)
85                                            (* to their phi nodes. *)
86            predKill : bool array           (* killed predecessor edges (because of DIE or STABILIZE *)
87          }
88    
89      (* a stack of pending joins.  The first component specifies the path index of the current
90       * path to the join.
91       *)
92        type pending_joins = (int * join) list
93    
94      (* create a new pending-join node *)
95        fun newJoin (env, arity) = JOIN{
96                env = env, arity = ref arity, nd = IL.Node.mkJOIN [], phiMap = ref VMap.empty,
97                predKill = Array.array(arity, false)
98              }
99    
100      (* record that a path to the top join in the stack has been killed because f DIE or STABILIZE *)
101        fun killPath ((i, JOIN{arity, predKill, ...}) :: _) = (
102              arity := !arity - 1;
103              Array.update (predKill, i, true))
104          | killPath _ = ()
105    
106      (* record an assignment to the IL variable dstVar (corresponding to the Simple AST variable
107       * srcVar) in the current pending-join node.  The predIndex specifies which path into the
108       * JOIN node this assignment occurs on.
109       *)
110        fun recordAssign ([], _, _) = ()
111          | recordAssign ((predIndex, JOIN{env, phiMap, predKill, nd, ...})::_, srcVar, dstVar) = let
112              val arity = Array.length predKill (* the original arity before any killPath calls *)
113              val m = !phiMap
114              in
115                case VMap.find (env, srcVar)
116                 of NONE => () (* local temporary *)
117                  | SOME dstVar' => (case VMap.find (m, srcVar)
118                       of NONE => let
119                            val lhs = newVar srcVar
120                            val rhs = List.tabulate (arity, fn i => if (i = predIndex) then dstVar else dstVar')
121                            in
122    (*
123    print(concat["recordAssign: ", SimpleVar.uniqueNameOf srcVar, " --> ", IL.Var.toString lhs,
124    " @ ", IL.Node.toString nd, "\n"]);
125    *)
126                              phiMap := VMap.insert (m, srcVar, (lhs, rhs))
127                            end
128                        | SOME(lhs, rhs) => let
129                            fun update (i, l as x::r) = if (i = predIndex)
130                                  then dstVar::r
131                                  else x::update(i+1, r)
132                              | update _ = raise Fail "invalid predecessor index"
133                            in
134                              phiMap := VMap.insert (m, srcVar, (lhs, update(0, rhs)))
135                            end
136                      (* end case *))
137                (* end case *)
138              end
139    
140      (* complete a pending join operation by filling in the phi nodes from the phi map and
141       * updating the environment.
142       *)
143        fun commitJoin (joinStk, JOIN{env, arity, nd, phiMap, predKill}) = (case !arity
144               of 0 => (env, NONE)
145                | 1 => let
146                  (* there is only one path to the join, so we do not need phi nodes, but
147                   * we still need to propogate assignments to the next join on the stack.
148                   *)
149                    val IL.ND{kind=IL.JOIN{phis, ...}, ...} = nd
150                    val ix = let (* find pred of this join *)
151                          fun find i = if Array.sub(predKill, i) then find(i+1) else i
152                          in
153                            find 0
154                          end
155                    fun doVar (srcVar, (_, xs), env) = let
156                          val dstVar = List.nth(xs, ix)
157                          in
158    (*
159    print(concat["doVar (", SimpleVar.uniqueNameOf srcVar, ", ", IL.phiToString phi, ", _) @ ", IL.Node.toString nd, "\n"]);
160    *)
161                            recordAssign (joinStk, srcVar, dstVar);
162                            VMap.insert (env, srcVar, dstVar)
163                          end
164                    val env = VMap.foldli doVar env (!phiMap)
165                    in
166                      (env, SOME nd)
167                    end
168                | n => if (n = Array.length predKill)
169                    then let
170                      val IL.ND{kind=IL.JOIN{phis, ...}, ...} = nd
171                      fun doVar (srcVar, phi as (dstVar, _), (env, phis)) = (
172    (*
173    print(concat["doVar (", SimpleVar.uniqueNameOf srcVar, ", ", IL.phiToString phi, ", _) @ ", IL.Node.toString nd, "\n"]);
174    *)
175                            recordAssign (joinStk, srcVar, dstVar);
176                            (VMap.insert (env, srcVar, dstVar), phi::phis))
177                      val (env, phis') = VMap.foldli doVar (env, []) (!phiMap)
178                      in
179                        phis := phis';
180                        (env, SOME nd)
181                      end
182                    else raise Fail "FIXME: prune killed paths."
183              (* end case *))
184    
185    (* expression translation *)    (* expression translation *)
186      fun cvtExpr (env, lhs, exp) = (case exp      fun cvtExp (env : env, lhs, exp) = (case exp
187             of S.E_Var x => [(lhs, IL.VAR(lookup env x))]             of S.E_Var x => [IL.ASSGN(lhs, IL.VAR(lookup env x))]
188              | S.E_Lit lit => [(lhs, IL.LIT lit)]              | S.E_Lit lit => [IL.ASSGN(lhs, IL.LIT lit)]
189              | S.E_Tuple xs => raise Fail "E_Tuple not implemeted"              | S.E_Tuple xs => raise Fail "E_Tuple not implemeted"
190              | S.E_Apply(f, tyArgs, args, ty) => let              | S.E_Apply _ => raise Fail "unexpected E_Apply"
191                | S.E_Prim(f, tyArgs, args, ty) => let
192                  val args' = List.map (lookup env) args                  val args' = List.map (lookup env) args
193                  in                  in
194                    TranslateBasis.translate (lhs, f, tyArgs, args')                    TranslateBasis.translate (lhs, f, tyArgs, args')
195                  end                  end
196              | S.E_Cons args => [(lhs, IL.CONS(List.map (lookup env) args))]              | S.E_Cons args => [IL.ASSGN(lhs, IL.CONS(IL.Var.ty lhs, List.map (lookup env) args))]
197                | S.E_Slice(x, indices, ty) => let
198                    val x = lookup env x
199                    val mask = List.map isSome indices
200                    fun cvt NONE = NONE
201                      | cvt (SOME x) = SOME(lookup env x)
202                    val indices = List.mapPartial cvt indices
203                    in
204                      if List.all (fn b => b) mask
205                        then [IL.ASSGN(lhs, IL.OP(Op.TensorSub(IL.Var.ty x), x::indices))]
206                        else [IL.ASSGN(lhs, IL.OP(Op.Slice(IL.Var.ty x, mask), x::indices))]
207                    end
208                | S.E_Coerce{srcTy, dstTy, x} => (case (srcTy, dstTy)
209                     of (Ty.T_Int, Ty.T_Tensor _) =>
210                          [IL.ASSGN(lhs, IL.OP(Op.IntToReal, [lookup env x]))]
211                      | (Ty.T_Field _, Ty.T_Field _) =>
212                        (* change in continuity is a no-op *)
213                          [IL.ASSGN(lhs, IL.VAR(lookup env x))]
214                      | _ => raise Fail(concat[
215                            "unsupported type coercion: ", Ty.toString srcTy,
216                            " ==> ", Ty.toString dstTy
217                          ])
218                    (* end case *))
219                | S.E_Input(_, name, NONE, NONE) =>
220                    [IL.ASSGN(lhs, IL.OP(HighOps.Input(IL.Var.ty lhs, name, ""), []))]
221                | S.E_Input(_, name, SOME desc, NONE) =>
222                    [IL.ASSGN(lhs, IL.OP(HighOps.Input(IL.Var.ty lhs, name, desc), []))]
223                | S.E_Input(_, name, NONE, SOME dflt) =>
224                    [IL.ASSGN(lhs, IL.OP(HighOps.InputWithDefault(IL.Var.ty lhs, name, ""), [lookup env dflt]))]
225                | S.E_Input(_, name, SOME desc, SOME dflt) =>
226                    [IL.ASSGN(lhs, IL.OP(HighOps.InputWithDefault(IL.Var.ty lhs, name, desc), [lookup env dflt]))]
227                | S.E_LoadImage(info, name) => [IL.ASSGN(lhs, IL.OP(HighOps.LoadImage info, [lookup env name]))]
228            (* end case *))            (* end case *))
229    
230      fun cvtBlock (env, S.Block stms) =    (* add nodes to save the strand state, followed by an exit node *)
231        fun saveStrandState (env, (srcState, dstState), exit) = let
232              val stateOut = List.map (lookup env) srcState
233              fun save (x, x', cfg) = IL.CFG.appendNode (cfg, IL.Node.mkSAVE(x, x'))
234              in
235                IL.CFG.appendNode (
236                  ListPair.foldlEq save IL.CFG.empty (dstState, stateOut),
237                  exit)
238              end
239    (*DEBUG*)handle ex => raise ex
240    
241    (* convert a statement, where env is the mapping from Simple AST variables to      fun cvtBlock (state, env : env, joinStk, S.Block stms) = let
242     * their current SSA name, assigned is the set of AST variables assigned to            fun cvt (env : env, cfg, []) = (cfg, env)
243     * in the current context, and stm is the statement to convert.              | cvt (env, cfg, stm::stms) = (case stm
244     *)                   of S.S_Var x => let
     and cvtStmt (env, assigned, stm, preStms, k) = (case stm  
            of S.S_Assign(x, e) => let  
245                  val x' = newVar x                  val x' = newVar x
                 val stms = cvtExp(env, x', e)  
                 val assigned = VSet.add(assigned, x)  
                 val env = VMap.insert(env, x, x')  
246                  in                  in
247                    k (env, assigned, stm::preStms)                          cvt (VMap.insert (env, x, x'), cfg, stms)
248                  end                  end
249              | S.S_IfThenElse(x, b1, b2) => let                    | S.S_Assign(lhs, rhs) => let
250                          val lhs' = newVar lhs
251                          val assigns = cvtExp (env, lhs', rhs)
252                          in
253    (*
254    print "doAssign\n";
255    *)
256                            recordAssign (joinStk, lhs, lhs');
257                            cvt (
258                              VMap.insert(env, lhs, lhs'),
259                              IL.CFG.concat(cfg, IL.CFG.mkBlock assigns),
260                              stms)
261                          end
262                      | S.S_IfThenElse(x, b0, b1) => let
263                  val x' = lookup env x                  val x' = lookup env x
264                  val (b1, env1, assigned1) = block(env, b1)                        val join = newJoin (env, 2)
265                  val (b2, env2, assigned2) = block(env, b2)                        val (cfg0, _) = cvtBlock (state, env, (0, join)::joinStk, b0)
266                  val assigned = VSet.union(assigned1, assigned2)                        val (cfg1, _) = cvtBlock (state, env, (1, join)::joinStk, b1)
267                  val (env, phis) = let                        val cond = IL.Node.mkCOND {
268                        fun mkPhi (x, (env, phis) = let                                cond = x',
269                              val x1 = lookup(env1, x)                                trueBranch = IL.Node.dummy,
270                              val x2 = lookup(env2, x)                                falseBranch = IL.Node.dummy
271                              val x' = newVar x                              }
272                              in                              in
273                                (VMap.insert(env, x, x'), (x', [x1, x2])::phis)                          IL.Node.addEdge (IL.CFG.exit cfg, cond);
274                            case commitJoin (joinStk, join)
275                             of (env, SOME joinNd) => (
276                                  if IL.CFG.isEmpty cfg0
277                                    then (
278                                      IL.Node.setTrueBranch (cond, joinNd);
279                                      IL.Node.setPred (joinNd, cond))
280                                    else (
281                                      IL.Node.setTrueBranch (cond, IL.CFG.entry cfg0);
282                                      IL.Node.setPred (IL.CFG.entry cfg0, cond);
283                                      IL.Node.addEdge (IL.CFG.exit cfg0, joinNd));
284                                  if IL.CFG.isEmpty cfg1
285                                    then (
286                                      IL.Node.setFalseBranch (cond, joinNd);
287                                      IL.Node.setPred (joinNd, cond))
288                                    else (
289                                      IL.Node.setFalseBranch (cond, IL.CFG.entry cfg1);
290                                      IL.Node.setPred (IL.CFG.entry cfg1, cond);
291                                      IL.Node.addEdge (IL.CFG.exit cfg1, joinNd));
292                                  cvt (
293                                    env,
294                                    IL.CFG.concat (
295                                      cfg,
296                                      IL.CFG{entry = cond, exit = joinNd}),
297                                    stms))
298                            (* the join node has only zero predecessors, so
299                             * it was killed.
300                             *)
301                              | (env, NONE) => raise Fail "unimplemented" (* FIXME *)
302                            (* end case *)
303                              end                              end
304                      | S.S_New(strandId, args) => let
305                          val nd = IL.Node.mkNEW{
306                                  strand = strandId,
307                                  args = List.map (lookup env) args
308                                }
309                        in                        in
310                          VSet.foldl mkPhi (env, []) assigned                          cvt (env, IL.CFG.appendNode (cfg, nd), stms)
311                        end                        end
312                      | S.S_Die => (
313                          killPath joinStk;
314                          (IL.CFG.appendNode (cfg, IL.Node.mkDIE ()), env))
315                      | S.S_Stabilize => (
316                          killPath joinStk;
317                          (IL.CFG.concat (cfg, saveStrandState (env, state, IL.Node.mkSTABILIZE())), env))
318                      | S.S_Return _ => raise Fail "unexpected return"
319                      | S.S_Print args => let
320                          val args = List.map (lookup env) args
321                          val nd = IL.Node.mkMASSIGN([], Op.Print(List.map IL.Var.ty args), args)
322                  in                  in
323                            cvt (env, IL.CFG.appendNode (cfg, nd), stms)
324                  end                  end
             | S.S_New(name, xs) =>  
             | S.S_Die =>  
             | S.S_Stabilize =>  
325            (* end case *))            (* end case *))
326              in
327                cvt (env, IL.CFG.empty, stms)
328              end
329    (*DEBUG*)handle ex => raise ex
330    
331      fun newBlock (??, stm) =      fun cvtTopLevelBlock (env, blk, mkExit) = let
332              val (cfg, env) = cvtBlock (([], []), env, [], blk)
333              val cfg = IL.CFG.prependNode (IL.Node.mkENTRY(), cfg)
334              val cfg = IL.CFG.concat (cfg, mkExit env)
335              in
336                (cfg, env)
337              end
338    (*DEBUG*)handle ex => raise ex
339    
340    (* FIXME: the following function could be refactored with cvtTopLevelBlock to share code *)
341        fun cvtFragmentBlock (env0, blk) = let
342              val (cfg, env) = cvtBlock (([], []), env0, [], blk)
343              val entry = IL.Node.mkENTRY ()
344            (* the live variables out are those that were not live coming in *)
345              val liveOut = VMap.foldli
346                    (fn (x, x', xs) => if VMap.inDomain(env0, x) then xs else x'::xs)
347                      [] env
348              val exit = IL.Node.mkFRAGMENT liveOut
349              in
350                if IL.CFG.isEmpty cfg
351                  then IL.Node.addEdge (entry, exit)
352                  else (
353                    IL.Node.addEdge (entry, IL.CFG.entry cfg);
354                    IL.Node.addEdge (IL.CFG.exit cfg, exit));
355                (IL.CFG{entry = entry, exit = exit}, env)
356              end
357    (*DEBUG*)handle ex => raise ex
358    
359      and nextStmt (env, assigned, stm, ??) =      fun cvtMethod (env, name, state, svars, blk) = let
360            (* load the state into fresh variables *)
361              val (env, loadCFG) = let
362                  (* allocate shadow variables for the state variables *)
363                    val (env, stateIn) = freshVars (env, state)
364                    fun load (x, x') = IL.ASSGN(x, IL.STATE x')
365                    in
366                      (env, IL.CFG.mkBlock (ListPair.map load (stateIn, svars)))
367                    end
368            (* convert the body of the method *)
369              val (cfg, env) = cvtBlock ((state, svars), env, [], blk)
370            (* add the entry/exit nodes *)
371              val entry = IL.Node.mkENTRY ()
372              val loadCFG = IL.CFG.prependNode (entry, loadCFG)
373              val exit = (case name
374                     of StrandUtil.Update => IL.Node.mkACTIVE ()
375                      | StrandUtil.Stabilize => IL.Node.mkRETURN []
376                    (* end case *))
377              val body = IL.CFG.concat (loadCFG, cfg)
378    (*DEBUG**val _ = prEnv (StrandUtil.nameToString name, env);*)
379    (* FIXME: the following code doesn't work properly *)
380              val body = if IL.Node.hasSucc(IL.CFG.exit body)
381                    then IL.CFG.concat (body, saveStrandState (env, (state, svars), exit))
382                    else IL.CFG{entry = IL.CFG.entry body, exit = exit}
383              in
384                IL.Method{
385                    name = name,
386                    body = body
387                  }
388              end
389    (*DEBUG*)handle ex => (print(concat["error in cvtMethod(", StrandUtil.nameToString name, ", ...)\n"]); raise ex)
390    
391      (* convert the initially code *)
392        fun cvtInitially (env, S.Initially{isArray, rangeInit, create, iters}) = let
393              val S.C_Create{argInit, name, args} = create
394              fun cvtIter ({param, lo, hi}, (env, iters)) = let
395                    val param' = newVar param
396                    val env = VMap.insert (env, param, param')
397                    val iter = (param', lookup env lo, lookup env hi)
398                    in
399                      (env, iter::iters)
400                    end
401              val (cfg, env) = cvtFragmentBlock (env, rangeInit)
402              val (env, iters) = List.foldl cvtIter (env, []) iters
403              val (argInitCFG, env) = cvtFragmentBlock (env, argInit)
404              in
405                IL.Initially{
406                    isArray = isArray,
407                    rangeInit = cfg,
408                    iters = List.rev iters,
409                    create = (argInitCFG, name, List.map (lookup env) args)
410                  }
411              end
412    
413      (* check strands for properties *)
414        fun checkProps strands = let
415              val hasDie = ref false
416              val hasNew = ref false
417              fun chkStm e = (case e
418                     of S.S_IfThenElse(_, b1, b2) => (chkBlk b1; chkBlk b2)
419                      | S.S_New _ => (hasNew := true)
420                      | S.S_Die => (hasDie := true)
421                      | _ => ()
422                  (* end case *))
423              and chkBlk (S.Block body) = List.app chkStm body
424              fun chkStrand (S.Strand{stateInit, methods, ...}) = let
425                    fun chkMeth (S.Method(_, body)) = chkBlk body
426                    in
427                      chkBlk stateInit;
428                      List.app chkMeth methods
429                    end
430              fun condCons (x, v, l) = if !x then v::l else l
431              in
432                List.app chkStrand strands;
433                condCons (hasDie, StrandUtil.StrandsMayDie,
434                condCons (hasNew, StrandUtil.NewStrands, []))
435              end
436    
437      and join (env      fun translate (S.Program{globals, globalInit, init, strands, ...}) = let
438      fun translate (S.Program{globals, globaInit, actors}) = ??            val (globalInit, env) = let
439                    fun mkExit env = let
440                          val nd = IL.Node.mkRETURN(VMap.listItems env)
441                          in
442                            IL.CFG{entry = nd, exit = nd}
443                          end
444                    in
445                      cvtTopLevelBlock (VMap.empty, globalInit, mkExit)
446                    end
447            (* construct a reduced environment that just defines the globals. *)
448              val env = let
449                    val lookup = lookup env
450                    fun cvtVar (x, env) = VMap.insert(env, x, lookup x)
451                    val env = List.foldl cvtVar VMap.empty globals
452                    in
453                      env
454                    end
455              val init = cvtInitially (env, init)
456              fun cvtStrand (S.Strand{name, params, state, stateInit, methods}) = let
457                  (* extend the global environment with the strand's parameters *)
458                    val (env, params) = let
459                          fun cvtParam (x, (env, xs)) = let
460                                val x' = newVar x
461                                in
462                                  (VMap.insert(env, x, x'), x'::xs)
463                                end
464                          val (env, params) = List.foldl cvtParam (env, []) params
465                          in
466                            (env, List.rev params)
467                          end
468                  (* create the state variables *)
469                    val svars = let
470                          fun newSVar x = IL.StateVar.new (
471                                SimpleVar.kindOf x = S.StrandOutputVar,
472                                SimpleVar.nameOf x, cvtTy(SimpleVar.typeOf x))
473                          in
474                            List.map newSVar state
475                          end
476                  (* convert the state initialization code *)
477                    val (stateInit, env) = let
478                          fun mkExit env = saveStrandState (env, (state, svars), IL.Node.mkSINIT())
479                          in
480                            cvtTopLevelBlock (env, stateInit, mkExit)
481                          end
482                    fun cvtMeth (S.Method(name, blk)) = cvtMethod (env, name, state, svars, blk)
483                    in
484                      IL.Strand{
485                          name = name,
486                          params = params,
487                          state = svars,
488                          stateInit = stateInit,
489                          methods = List.map cvtMeth methods
490                        }
491                    end
492              val prog = IL.Program{
493                      props = checkProps strands,
494                      globalInit = globalInit,
495                      initially = init,
496                      strands = List.map cvtStrand strands
497                    }
498              in
499                Census.init prog;
500                prog
501              end
502    
503    end    end

Legend:
Removed from v.190  
changed lines
  Added in v.2483

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