1 : |
jhr |
137 |
(* translate.sml
|
2 : |
|
|
*
|
3 : |
jhr |
435 |
* COPYRIGHT (c) 2010 The Diderot Project (http://diderot-language.cs.uchicago.edu)
|
4 : |
jhr |
137 |
* All rights reserved.
|
5 : |
|
|
*
|
6 : |
jhr |
1116 |
* 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 : |
jhr |
137 |
*)
|
13 : |
|
|
|
14 : |
|
|
structure Translate : sig
|
15 : |
|
|
|
16 : |
jhr |
176 |
val translate : Simple.program -> HighIL.program
|
17 : |
jhr |
137 |
|
18 : |
|
|
end = struct
|
19 : |
|
|
|
20 : |
jhr |
176 |
structure S = Simple
|
21 : |
jhr |
394 |
structure Ty = Types
|
22 : |
jhr |
137 |
structure VMap = Var.Map
|
23 : |
jhr |
189 |
structure VSet = Var.Set
|
24 : |
jhr |
168 |
structure IL = HighIL
|
25 : |
jhr |
1640 |
structure Op = HighOps
|
26 : |
jhr |
394 |
structure DstTy = HighILTypes
|
27 : |
jhr |
1116 |
structure Census = HighILCensus
|
28 : |
jhr |
137 |
|
29 : |
jhr |
1640 |
val cvtTy = TranslateTy.tr
|
30 : |
|
|
|
31 : |
jhr |
1116 |
(* maps from SimpleAST variables to the current corresponding SSA variable *)
|
32 : |
jhr |
511 |
type env = IL.var VMap.map
|
33 : |
|
|
|
34 : |
jhr |
1640 |
(* +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 : |
|
|
" ", Var.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 : |
jhr |
197 |
fun lookup env x = (case VMap.find (env, x)
|
55 : |
jhr |
176 |
of SOME x' => x'
|
56 : |
|
|
| NONE => raise Fail(concat[
|
57 : |
jhr |
197 |
"no binding for ", Var.uniqueNameOf x, " in environment"
|
58 : |
jhr |
176 |
])
|
59 : |
|
|
(* end case *))
|
60 : |
|
|
|
61 : |
jhr |
189 |
(* create a new instance of a variable *)
|
62 : |
jhr |
394 |
fun newVar x = IL.Var.new (Var.nameOf x, cvtTy(Var.monoTypeOf x))
|
63 : |
jhr |
189 |
|
64 : |
jhr |
1116 |
(* 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 : |
jhr |
1232 |
env : env, (* the environment that was current at the conditional *)
|
81 : |
|
|
(* associated with this node. *)
|
82 : |
jhr |
1116 |
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 : |
jhr |
1232 |
fun newJoin (env, arity) = JOIN{
|
96 : |
|
|
env = env, arity = ref arity, nd = IL.Node.mkJOIN [], phiMap = ref VMap.empty,
|
97 : |
jhr |
1116 |
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 : |
jhr |
1232 |
fun recordAssign ([], _, _) = ()
|
111 : |
|
|
| recordAssign ((predIndex, JOIN{env, phiMap, predKill, nd, ...})::_, srcVar, dstVar) = let
|
112 : |
jhr |
1116 |
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 : |
jhr |
1232 |
(*
|
123 : |
|
|
print(concat["recordAssign: ", Var.uniqueNameOf srcVar, " --> ", IL.Var.toString lhs,
|
124 : |
|
|
" @ ", IL.Node.toString nd, "\n"]);
|
125 : |
|
|
*)
|
126 : |
jhr |
1116 |
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 : |
jhr |
1232 |
fun commitJoin (joinStk, JOIN{env, arity, nd, phiMap, predKill}) = (case !arity
|
144 : |
jhr |
1116 |
of 0 => (env, NONE)
|
145 : |
|
|
| 1 => (* there is only one path to the join, so we do not need phi nodes *)
|
146 : |
|
|
(env, SOME nd)
|
147 : |
|
|
| n => if (n = Array.length predKill)
|
148 : |
|
|
then let
|
149 : |
|
|
val IL.ND{kind=IL.JOIN{phis, ...}, ...} = nd
|
150 : |
|
|
fun doVar (srcVar, phi as (dstVar, _), (env, phis)) = (
|
151 : |
jhr |
1232 |
(*
|
152 : |
|
|
print(concat["doVar (", Var.uniqueNameOf srcVar, ", ", IL.phiToString phi, ", _) @ ", IL.Node.toString nd, "\n"]);
|
153 : |
|
|
*)
|
154 : |
|
|
recordAssign (joinStk, srcVar, dstVar);
|
155 : |
jhr |
1116 |
(VMap.insert (env, srcVar, dstVar), phi::phis))
|
156 : |
|
|
val (env, phis') = VMap.foldli doVar (env, []) (!phiMap)
|
157 : |
|
|
in
|
158 : |
|
|
phis := phis';
|
159 : |
|
|
(env, SOME nd)
|
160 : |
|
|
end
|
161 : |
|
|
else raise Fail "FIXME: prune killed paths."
|
162 : |
|
|
(* end case *))
|
163 : |
|
|
|
164 : |
jhr |
168 |
(* expression translation *)
|
165 : |
jhr |
1116 |
fun cvtExp (env : env, lhs, exp) = (case exp
|
166 : |
jhr |
1640 |
of S.E_Var x => [IL.ASSGN(lhs, IL.VAR(lookup env x))]
|
167 : |
|
|
| S.E_Lit lit => [IL.ASSGN(lhs, IL.LIT lit)]
|
168 : |
lamonts |
1832 |
| S.E_RadiusQuery (S.E_Lit lit) => [IL.ASSGN(lhs,IL.RQUERY lit)]
|
169 : |
jhr |
176 |
| S.E_Tuple xs => raise Fail "E_Tuple not implemeted"
|
170 : |
jhr |
188 |
| S.E_Apply(f, tyArgs, args, ty) => let
|
171 : |
|
|
val args' = List.map (lookup env) args
|
172 : |
|
|
in
|
173 : |
|
|
TranslateBasis.translate (lhs, f, tyArgs, args')
|
174 : |
|
|
end
|
175 : |
jhr |
1640 |
| S.E_Cons args => [IL.ASSGN(lhs, IL.CONS(IL.Var.ty lhs, List.map (lookup env) args))]
|
176 : |
jhr |
400 |
| S.E_Slice(x, indices, ty) => let
|
177 : |
|
|
val x = lookup env x
|
178 : |
|
|
val mask = List.map isSome indices
|
179 : |
|
|
fun cvt NONE = NONE
|
180 : |
|
|
| cvt (SOME x) = SOME(lookup env x)
|
181 : |
|
|
val indices = List.mapPartial cvt indices
|
182 : |
|
|
in
|
183 : |
|
|
if List.all (fn b => b) mask
|
184 : |
jhr |
1640 |
then [IL.ASSGN(lhs, IL.OP(HighOps.TensorSub(IL.Var.ty x), x::indices))]
|
185 : |
|
|
else [IL.ASSGN(lhs, IL.OP(HighOps.Slice(IL.Var.ty lhs, mask), x::indices))]
|
186 : |
jhr |
400 |
end
|
187 : |
jhr |
1301 |
| S.E_Input(_, name, desc, NONE) =>
|
188 : |
jhr |
1640 |
[IL.ASSGN(lhs, IL.OP(HighOps.Input(IL.Var.ty lhs, name, desc), []))]
|
189 : |
jhr |
1301 |
| S.E_Input(_, name, desc, SOME dflt) =>
|
190 : |
jhr |
1640 |
[IL.ASSGN(lhs, IL.OP(HighOps.InputWithDefault(IL.Var.ty lhs, name, desc), [lookup env dflt]))]
|
191 : |
|
|
| S.E_LoadImage(info, name) => [IL.ASSGN(lhs, IL.OP(HighOps.LoadImage info, [lookup env name]))]
|
192 : |
jhr |
176 |
(* end case *))
|
193 : |
jhr |
168 |
|
194 : |
jhr |
1640 |
(* add nodes to save the strand state, followed by an exit node *)
|
195 : |
|
|
fun saveStrandState (env, (srcState, dstState), exit) = let
|
196 : |
|
|
val stateOut = List.map (lookup env) srcState
|
197 : |
|
|
fun save (x, x', cfg) = IL.CFG.appendNode (cfg, IL.Node.mkSAVE(x, x'))
|
198 : |
|
|
in
|
199 : |
|
|
IL.CFG.appendNode (
|
200 : |
|
|
ListPair.foldlEq save IL.CFG.empty (dstState, stateOut),
|
201 : |
|
|
exit)
|
202 : |
|
|
end
|
203 : |
|
|
handle ex => raise ex
|
204 : |
|
|
|
205 : |
jhr |
1116 |
fun cvtBlock (state, env : env, joinStk, S.Block stms) = let
|
206 : |
|
|
fun cvt (env : env, cfg, []) = (cfg, env)
|
207 : |
|
|
| cvt (env, cfg, stm::stms) = (case stm
|
208 : |
|
|
of S.S_Var x => let
|
209 : |
|
|
val x' = newVar x
|
210 : |
|
|
in
|
211 : |
|
|
cvt (VMap.insert (env, x, x'), cfg, stms)
|
212 : |
|
|
end
|
213 : |
|
|
| S.S_Assign(lhs, rhs) => let
|
214 : |
|
|
val lhs' = newVar lhs
|
215 : |
|
|
val assigns = cvtExp (env, lhs', rhs)
|
216 : |
|
|
in
|
217 : |
jhr |
1232 |
(*
|
218 : |
|
|
print "doAssign\n";
|
219 : |
|
|
*)
|
220 : |
|
|
recordAssign (joinStk, lhs, lhs');
|
221 : |
jhr |
1116 |
cvt (
|
222 : |
|
|
VMap.insert(env, lhs, lhs'),
|
223 : |
|
|
IL.CFG.concat(cfg, IL.CFG.mkBlock assigns),
|
224 : |
|
|
stms)
|
225 : |
|
|
end
|
226 : |
|
|
| S.S_IfThenElse(x, b0, b1) => let
|
227 : |
jhr |
192 |
val x' = lookup env x
|
228 : |
jhr |
1232 |
val join = newJoin (env, 2)
|
229 : |
jhr |
1116 |
val (cfg0, _) = cvtBlock (state, env, (0, join)::joinStk, b0)
|
230 : |
|
|
val (cfg1, _) = cvtBlock (state, env, (1, join)::joinStk, b1)
|
231 : |
|
|
val cond = IL.Node.mkCOND {
|
232 : |
|
|
cond = x',
|
233 : |
|
|
trueBranch = IL.Node.dummy,
|
234 : |
|
|
falseBranch = IL.Node.dummy
|
235 : |
|
|
}
|
236 : |
jhr |
190 |
in
|
237 : |
jhr |
1116 |
IL.Node.addEdge (IL.CFG.exit cfg, cond);
|
238 : |
jhr |
1232 |
case commitJoin (joinStk, join)
|
239 : |
jhr |
1116 |
of (env, SOME joinNd) => (
|
240 : |
|
|
if IL.CFG.isEmpty cfg0
|
241 : |
|
|
then (
|
242 : |
|
|
IL.Node.setTrueBranch (cond, joinNd);
|
243 : |
|
|
IL.Node.setPred (joinNd, cond))
|
244 : |
|
|
else (
|
245 : |
|
|
IL.Node.setTrueBranch (cond, IL.CFG.entry cfg0);
|
246 : |
|
|
IL.Node.setPred (IL.CFG.entry cfg0, cond);
|
247 : |
|
|
IL.Node.addEdge (IL.CFG.exit cfg0, joinNd));
|
248 : |
|
|
if IL.CFG.isEmpty cfg1
|
249 : |
|
|
then (
|
250 : |
|
|
IL.Node.setFalseBranch (cond, joinNd);
|
251 : |
|
|
IL.Node.setPred (joinNd, cond))
|
252 : |
|
|
else (
|
253 : |
|
|
IL.Node.setFalseBranch (cond, IL.CFG.entry cfg1);
|
254 : |
|
|
IL.Node.setPred (IL.CFG.entry cfg1, cond);
|
255 : |
|
|
IL.Node.addEdge (IL.CFG.exit cfg1, joinNd));
|
256 : |
|
|
cvt (
|
257 : |
|
|
env,
|
258 : |
jhr |
1339 |
IL.CFG.concat (
|
259 : |
|
|
cfg,
|
260 : |
|
|
IL.CFG{entry = cond, exit = joinNd}),
|
261 : |
jhr |
1116 |
stms))
|
262 : |
|
|
(* the join node has only zero predecessors, so
|
263 : |
|
|
* it was killed.
|
264 : |
|
|
*)
|
265 : |
|
|
| (env, NONE) => raise Fail "unimplemented" (* FIXME *)
|
266 : |
jhr |
192 |
(* end case *)
|
267 : |
jhr |
190 |
end
|
268 : |
lamonts |
1832 |
| S.S_Foreach(x, e, blk) => let
|
269 : |
|
|
val x' = lookup env x
|
270 : |
lamonts |
1854 |
val (IL.ASSGN(lhs,rhs)::rest) = cvtExp (env, x', e)
|
271 : |
lamonts |
1832 |
val join = newJoin (env, 1)
|
272 : |
|
|
val (cfg, _) = cvtBlock (state, env, (0, join)::joinStk, blk)
|
273 : |
|
|
in
|
274 : |
lamonts |
1848 |
cvt(env,
|
275 : |
lamonts |
1854 |
IL.CFG.appendNode(cfg,IL.Node.mkFOREACH((x',rhs),IL.CFG.entry cfg)),
|
276 : |
lamonts |
1848 |
stms)
|
277 : |
lamonts |
1832 |
end
|
278 : |
|
|
|
279 : |
jhr |
1116 |
| S.S_New(strandId, args) => let
|
280 : |
|
|
val nd = IL.Node.mkNEW{
|
281 : |
|
|
strand = strandId,
|
282 : |
|
|
args = List.map (lookup env) args
|
283 : |
|
|
}
|
284 : |
jhr |
192 |
in
|
285 : |
jhr |
1116 |
cvt (env, IL.CFG.appendNode (cfg, nd), stms)
|
286 : |
jhr |
194 |
end
|
287 : |
jhr |
1116 |
| S.S_Die => (
|
288 : |
|
|
killPath joinStk;
|
289 : |
|
|
(IL.CFG.appendNode (cfg, IL.Node.mkDIE ()), env))
|
290 : |
jhr |
1640 |
| S.S_Stabilize => (
|
291 : |
|
|
killPath joinStk;
|
292 : |
|
|
(IL.CFG.concat (cfg, saveStrandState (env, state, IL.Node.mkSTABILIZE())), env))
|
293 : |
|
|
| S.S_Print args => let
|
294 : |
|
|
val args = List.map (lookup env) args
|
295 : |
|
|
val nd = IL.Node.mkMASSIGN([], Op.Print(List.map IL.Var.ty args), args)
|
296 : |
|
|
in
|
297 : |
|
|
cvt (env, IL.CFG.appendNode (cfg, nd), stms)
|
298 : |
|
|
end
|
299 : |
jhr |
192 |
(* end case *))
|
300 : |
|
|
in
|
301 : |
jhr |
1116 |
cvt (env, IL.CFG.empty, stms)
|
302 : |
jhr |
192 |
end
|
303 : |
jhr |
1339 |
(*DEBUG*)handle ex => raise ex
|
304 : |
jhr |
168 |
|
305 : |
jhr |
1232 |
fun cvtTopLevelBlock (env, blk, mkExit) = let
|
306 : |
jhr |
1640 |
val (cfg, env) = cvtBlock (([], []), env, [], blk)
|
307 : |
|
|
val cfg = IL.CFG.prependNode (IL.Node.mkENTRY(), cfg)
|
308 : |
|
|
val cfg = IL.CFG.concat (cfg, mkExit env)
|
309 : |
jhr |
256 |
in
|
310 : |
jhr |
1640 |
(cfg, env)
|
311 : |
jhr |
256 |
end
|
312 : |
jhr |
1339 |
(*DEBUG*)handle ex => raise ex
|
313 : |
jhr |
256 |
|
314 : |
jhr |
1116 |
(* FIXME: the following function could be refactored with cvtTopLevelBlock to share code *)
|
315 : |
jhr |
1232 |
fun cvtFragmentBlock (env0, blk) = let
|
316 : |
jhr |
1640 |
val (cfg, env) = cvtBlock (([], []), env0, [], blk)
|
317 : |
jhr |
1116 |
val entry = IL.Node.mkENTRY ()
|
318 : |
jhr |
1232 |
(* the live variables out are those that were not live coming in *)
|
319 : |
|
|
val liveOut = VMap.foldli
|
320 : |
|
|
(fn (x, x', xs) => if VMap.inDomain(env0, x) then xs else x'::xs)
|
321 : |
|
|
[] env
|
322 : |
|
|
val exit = IL.Node.mkFRAGMENT liveOut
|
323 : |
jhr |
1116 |
in
|
324 : |
|
|
if IL.CFG.isEmpty cfg
|
325 : |
|
|
then IL.Node.addEdge (entry, exit)
|
326 : |
|
|
else (
|
327 : |
|
|
IL.Node.addEdge (entry, IL.CFG.entry cfg);
|
328 : |
jhr |
1232 |
IL.Node.addEdge (IL.CFG.exit cfg, exit));
|
329 : |
jhr |
1116 |
(IL.CFG{entry = entry, exit = exit}, env)
|
330 : |
|
|
end
|
331 : |
jhr |
1339 |
(*DEBUG*)handle ex => raise ex
|
332 : |
jhr |
1116 |
|
333 : |
jhr |
1640 |
fun cvtMethod (env, name, state, svars, blk) = let
|
334 : |
|
|
(* load the state into fresh variables *)
|
335 : |
|
|
val (env, loadCFG) = let
|
336 : |
|
|
(* allocate shadow variables for the state variables *)
|
337 : |
|
|
val (env, stateIn) = freshVars (env, state)
|
338 : |
|
|
fun load (x, x') = IL.ASSGN(x, IL.STATE x')
|
339 : |
|
|
in
|
340 : |
|
|
(env, IL.CFG.mkBlock (ListPair.map load (stateIn, svars)))
|
341 : |
|
|
end
|
342 : |
jhr |
1116 |
(* convert the body of the method *)
|
343 : |
jhr |
1640 |
val (cfg, env) = cvtBlock ((state, svars), env, [], blk)
|
344 : |
jhr |
1116 |
(* add the entry/exit nodes *)
|
345 : |
|
|
val entry = IL.Node.mkENTRY ()
|
346 : |
jhr |
1640 |
val loadCFG = IL.CFG.prependNode (entry, loadCFG)
|
347 : |
jhr |
1444 |
val exit = (case name
|
348 : |
jhr |
1640 |
of StrandUtil.Update => IL.Node.mkACTIVE ()
|
349 : |
|
|
| StrandUtil.Stabilize => IL.Node.mkRETURN []
|
350 : |
jhr |
1444 |
(* end case *))
|
351 : |
jhr |
1640 |
val body = IL.CFG.concat (loadCFG, cfg)
|
352 : |
|
|
(*DEBUG**val _ = prEnv (StrandUtil.nameToString name, env);*)
|
353 : |
|
|
(* FIXME: the following code doesn't work properly *)
|
354 : |
|
|
val body = if IL.Node.hasSucc(IL.CFG.exit body)
|
355 : |
|
|
then IL.CFG.concat (body, saveStrandState (env, (state, svars), exit))
|
356 : |
|
|
else IL.CFG{entry = IL.CFG.entry body, exit = exit}
|
357 : |
jhr |
1116 |
in
|
358 : |
|
|
IL.Method{
|
359 : |
|
|
name = name,
|
360 : |
jhr |
1640 |
body = body
|
361 : |
jhr |
1116 |
}
|
362 : |
|
|
end
|
363 : |
jhr |
1640 |
(*DEBUG*)handle ex => (print(concat["error in cvtMethod(", StrandUtil.nameToString name, ", ...)\n"]); raise ex)
|
364 : |
jhr |
1116 |
|
365 : |
|
|
(* convert the initially code *)
|
366 : |
|
|
fun cvtInitially (env, S.Initially{isArray, rangeInit, create, iters}) = let
|
367 : |
|
|
val S.C_Create{argInit, name, args} = create
|
368 : |
|
|
fun cvtIter ({param, lo, hi}, (env, iters)) = let
|
369 : |
|
|
val param' = newVar param
|
370 : |
|
|
val env = VMap.insert (env, param, param')
|
371 : |
|
|
val iter = (param', lookup env lo, lookup env hi)
|
372 : |
jhr |
256 |
in
|
373 : |
jhr |
1116 |
(env, iter::iters)
|
374 : |
jhr |
256 |
end
|
375 : |
jhr |
1116 |
val (cfg, env) = cvtFragmentBlock (env, rangeInit)
|
376 : |
|
|
val (env, iters) = List.foldl cvtIter (env, []) iters
|
377 : |
|
|
val (argInitCFG, env) = cvtFragmentBlock (env, argInit)
|
378 : |
jhr |
256 |
in
|
379 : |
jhr |
1116 |
IL.Initially{
|
380 : |
|
|
isArray = isArray,
|
381 : |
|
|
rangeInit = cfg,
|
382 : |
|
|
iters = List.rev iters,
|
383 : |
|
|
create = (argInitCFG, name, List.map (lookup env) args)
|
384 : |
|
|
}
|
385 : |
jhr |
256 |
end
|
386 : |
|
|
|
387 : |
jhr |
1640 |
(* check strands for properties *)
|
388 : |
|
|
fun checkProps strands = let
|
389 : |
|
|
val hasDie = ref false
|
390 : |
|
|
val hasNew = ref false
|
391 : |
|
|
fun chkStm e = (case e
|
392 : |
|
|
of S.S_IfThenElse(_, b1, b2) => (chkBlk b1; chkBlk b2)
|
393 : |
|
|
| S.S_New _ => (hasNew := true)
|
394 : |
|
|
| S.S_Die => (hasDie := true)
|
395 : |
|
|
| _ => ()
|
396 : |
|
|
(* end case *))
|
397 : |
|
|
and chkBlk (S.Block body) = List.app chkStm body
|
398 : |
|
|
fun chkStrand (S.Strand{stateInit, methods, ...}) = let
|
399 : |
|
|
fun chkMeth (S.Method(_, body)) = chkBlk body
|
400 : |
|
|
in
|
401 : |
|
|
chkBlk stateInit;
|
402 : |
|
|
List.app chkMeth methods
|
403 : |
|
|
end
|
404 : |
|
|
fun condCons (x, v, l) = if !x then v::l else l
|
405 : |
|
|
in
|
406 : |
|
|
List.app chkStrand strands;
|
407 : |
|
|
condCons (hasDie, StrandUtil.StrandsMayDie,
|
408 : |
|
|
condCons (hasNew, StrandUtil.NewStrands, []))
|
409 : |
|
|
end
|
410 : |
|
|
|
411 : |
jhr |
1116 |
fun translate (S.Program{globals, globalInit, init, strands}) = let
|
412 : |
jhr |
1640 |
val (globalInit, env) = let
|
413 : |
|
|
fun mkExit env = let
|
414 : |
|
|
val nd = IL.Node.mkRETURN(VMap.listItems env)
|
415 : |
|
|
in
|
416 : |
|
|
IL.CFG{entry = nd, exit = nd}
|
417 : |
|
|
end
|
418 : |
|
|
in
|
419 : |
|
|
cvtTopLevelBlock (VMap.empty, globalInit, mkExit)
|
420 : |
|
|
end
|
421 : |
jhr |
1116 |
(* construct a reduced environment that just defines the globals. *)
|
422 : |
|
|
val env = let
|
423 : |
jhr |
200 |
val lookup = lookup env
|
424 : |
jhr |
1116 |
fun cvtVar (x, env) = VMap.insert(env, x, lookup x)
|
425 : |
|
|
val env = List.foldl cvtVar VMap.empty globals
|
426 : |
jhr |
200 |
in
|
427 : |
jhr |
1116 |
env
|
428 : |
jhr |
200 |
end
|
429 : |
jhr |
1116 |
val init = cvtInitially (env, init)
|
430 : |
jhr |
511 |
fun cvtStrand (S.Strand{name, params, state, stateInit, methods}) = let
|
431 : |
jhr |
1232 |
(* extend the global environment with the strand's parameters *)
|
432 : |
jhr |
200 |
val (env, params) = let
|
433 : |
|
|
fun cvtParam (x, (env, xs)) = let
|
434 : |
|
|
val x' = newVar x
|
435 : |
|
|
in
|
436 : |
|
|
(VMap.insert(env, x, x'), x'::xs)
|
437 : |
|
|
end
|
438 : |
|
|
val (env, params) = List.foldl cvtParam (env, []) params
|
439 : |
|
|
in
|
440 : |
|
|
(env, List.rev params)
|
441 : |
|
|
end
|
442 : |
jhr |
1640 |
(* create the state variables *)
|
443 : |
|
|
val svars = let
|
444 : |
|
|
fun newSVar x = IL.StateVar.new (
|
445 : |
|
|
Var.kindOf x = S.StrandOutputVar,
|
446 : |
|
|
Var.nameOf x, cvtTy(Var.monoTypeOf x))
|
447 : |
|
|
in
|
448 : |
|
|
List.map newSVar state
|
449 : |
|
|
end
|
450 : |
jhr |
1232 |
(* convert the state initialization code *)
|
451 : |
|
|
val (stateInit, env) = let
|
452 : |
jhr |
1640 |
fun mkExit env = saveStrandState (env, (state, svars), IL.Node.mkSINIT())
|
453 : |
jhr |
1232 |
in
|
454 : |
|
|
cvtTopLevelBlock (env, stateInit, mkExit)
|
455 : |
|
|
end
|
456 : |
jhr |
1640 |
fun cvtMeth (S.Method(name, blk)) = cvtMethod (env, name, state, svars, blk)
|
457 : |
jhr |
200 |
in
|
458 : |
jhr |
511 |
IL.Strand{
|
459 : |
jhr |
200 |
name = name,
|
460 : |
|
|
params = params,
|
461 : |
jhr |
1640 |
state = svars,
|
462 : |
jhr |
200 |
stateInit = stateInit,
|
463 : |
jhr |
1116 |
methods = List.map cvtMeth methods
|
464 : |
jhr |
200 |
}
|
465 : |
|
|
end
|
466 : |
jhr |
511 |
val prog = IL.Program{
|
467 : |
jhr |
1640 |
props = checkProps strands,
|
468 : |
jhr |
1116 |
globalInit = globalInit,
|
469 : |
|
|
initially = init,
|
470 : |
|
|
strands = List.map cvtStrand strands
|
471 : |
|
|
}
|
472 : |
jhr |
511 |
in
|
473 : |
|
|
Census.init prog;
|
474 : |
|
|
prog
|
475 : |
jhr |
200 |
end
|
476 : |
jhr |
176 |
|
477 : |
jhr |
137 |
end
|