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

SCM Repository

[diderot] Annotation of /branches/pure-cfg/src/compiler/translate/translate.sml
ViewVC logotype

Annotation of /branches/pure-cfg/src/compiler/translate/translate.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1017 - (view) (download)

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 494 * 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 394 structure DstTy = HighILTypes
26 : jhr 539 structure Census = HighILCensus
27 : jhr 137
28 : jhr 648 (* maps from SimpleAST variables to the current corresponding SSA variable *)
29 : jhr 494 type env = IL.var VMap.map
30 :    
31 : jhr 197 fun lookup env x = (case VMap.find (env, x)
32 : jhr 176 of SOME x' => x'
33 :     | NONE => raise Fail(concat[
34 : jhr 197 "no binding for ", Var.uniqueNameOf x, " in environment"
35 : jhr 176 ])
36 :     (* end case *))
37 :    
38 : jhr 394 fun cvtTy ty = (case TypeUtil.prune ty
39 :     of Ty.T_Bool => DstTy.BoolTy
40 :     | Ty.T_Int => DstTy.IntTy
41 :     | Ty.T_String => DstTy.StringTy
42 :     | Ty.T_Kernel _ => DstTy.KernelTy
43 : jhr 426 | Ty.T_Tensor(Ty.Shape dd) => let
44 :     fun cvtDim (Ty.DimConst 1) = NONE
45 :     | cvtDim (Ty.DimConst d) = SOME d
46 :     in
47 :     DstTy.TensorTy(List.mapPartial cvtDim dd)
48 :     end
49 : jhr 548 | Ty.T_Image{dim=Ty.DimConst d, shape} => DstTy.ImageTy d
50 :     | Ty.T_Field fld => DstTy.FieldTy
51 : jhr 394 | ty => raise Fail("cvtTy: unexpected " ^ TypeUtil.toString ty)
52 :     (* end case *))
53 :    
54 : jhr 189 (* create a new instance of a variable *)
55 : jhr 394 fun newVar x = IL.Var.new (Var.nameOf x, cvtTy(Var.monoTypeOf x))
56 : jhr 189
57 : jhr 563 (* generate fresh SSA variables and add them to the environment *)
58 :     fun freshVars (env, xs) = let
59 :     fun cvtVar (x, (env, xs)) = let
60 :     val x' = newVar x
61 :     in
62 :     (VMap.insert(env, x, x'), x'::xs)
63 :     end
64 :     val (env, xs) = List.foldl cvtVar (env, []) xs
65 :     in
66 :     (env, List.rev xs)
67 :     end
68 :    
69 : jhr 498 (* a pending-join node tracks the phi nodes needed to join the assignments
70 :     * that flow into the join node.
71 : jhr 494 *)
72 :     datatype join = JOIN of {
73 : jhr 670 arity : int ref, (* actual number of predecessors *)
74 : jhr 494 nd : IL.node, (* the CFG node for this pending join *)
75 : jhr 496 phiMap : IL.phi VMap.map ref, (* a mapping from Simple AST variables that are assigned *)
76 : jhr 494 (* to their phi nodes. *)
77 : jhr 670 predKill : bool array (* killed predecessor edges (because of DIE or STABILIZE *)
78 : jhr 494 }
79 :    
80 : jhr 498 (* a stack of pending joins. The first component specifies the path index of the current
81 :     * path to the join.
82 :     *)
83 :     type pending_joins = (int * join) list
84 :    
85 : jhr 494 (* create a new pending-join node *)
86 : jhr 496 fun newJoin arity = JOIN{
87 : jhr 670 arity = ref arity, nd = IL.Node.mkJOIN [], phiMap = ref VMap.empty,
88 :     predKill = Array.array(arity, false)
89 : jhr 496 }
90 : jhr 494
91 : jhr 670 (* record that a path to the top join in the stack has been killed because f DIE or STABILIZE *)
92 :     fun killPath ((i, JOIN{arity, predKill, ...}) :: _) = (
93 :     arity := !arity - 1;
94 :     Array.update (predKill, i, true))
95 : jhr 497 | killPath _ = ()
96 : jhr 496
97 : jhr 494 (* record an assignment to the IL variable dstVar (corresponding to the Simple AST variable
98 :     * srcVar) in the current pending-join node. The predIndex specifies which path into the
99 :     * JOIN node this assignment occurs on.
100 :     *)
101 : jhr 501 fun recordAssign (_, [], _, _) = ()
102 : jhr 670 | recordAssign (env, (predIndex, JOIN{phiMap, predKill, ...})::_, srcVar, dstVar) = let
103 :     val arity = Array.length predKill (* the original arity before any killPath calls *)
104 : jhr 494 val m = !phiMap
105 :     in
106 : jhr 509 case VMap.find (env, srcVar)
107 : jhr 506 of NONE => () (* local temporary *)
108 : jhr 509 | SOME dstVar' => (case VMap.find (m, srcVar)
109 :     of NONE => let
110 :     val lhs = newVar srcVar
111 :     val rhs = List.tabulate (arity, fn i => if (i = predIndex) then dstVar else dstVar')
112 :     in
113 :     phiMap := VMap.insert (m, srcVar, (lhs, rhs))
114 :     end
115 :     | SOME(lhs, rhs) => let
116 :     fun update (i, l as x::r) = if (i = predIndex)
117 :     then dstVar::r
118 :     else x::update(i+1, r)
119 :     | update _ = raise Fail "invalid predecessor index"
120 :     in
121 :     phiMap := VMap.insert (m, srcVar, (lhs, update(0, rhs)))
122 :     end
123 :     (* end case *))
124 : jhr 506 (* end case *)
125 : jhr 494 end
126 :    
127 :     (* complete a pending join operation by filling in the phi nodes from the phi map and
128 :     * updating the environment.
129 :     *)
130 : jhr 670 fun commitJoin (env, joinStk, JOIN{arity, nd, phiMap, predKill}) = (case !arity
131 :     of 0 => (env, NONE)
132 :     | 1 => (* there is only one path to the join, so we do not need phi nodes *)
133 :     (env, SOME nd)
134 :     | n => if (n = Array.length predKill)
135 :     then let
136 :     val IL.ND{kind=IL.JOIN{phis, ...}, ...} = nd
137 :     fun doVar (srcVar, phi as (dstVar, _), (env, phis)) = (
138 :     recordAssign (env, joinStk, srcVar, dstVar);
139 :     (VMap.insert (env, srcVar, dstVar), phi::phis))
140 :     val (env, phis') = VMap.foldli doVar (env, []) (!phiMap)
141 :     in
142 :     phis := phis';
143 :     (env, SOME nd)
144 :     end
145 :     else raise Fail "FIXME: prune killed paths."
146 :     (* end case *))
147 : jhr 494
148 : jhr 168 (* expression translation *)
149 : jhr 501 fun cvtExp (env : env, lhs, exp) = (case exp
150 : jhr 188 of S.E_Var x => [(lhs, IL.VAR(lookup env x))]
151 :     | S.E_Lit lit => [(lhs, IL.LIT lit)]
152 : jhr 176 | S.E_Tuple xs => raise Fail "E_Tuple not implemeted"
153 : jhr 188 | S.E_Apply(f, tyArgs, args, ty) => let
154 :     val args' = List.map (lookup env) args
155 :     in
156 :     TranslateBasis.translate (lhs, f, tyArgs, args')
157 :     end
158 : jhr 736 | S.E_Cons args => [(lhs, IL.CONS(IL.Var.ty lhs, List.map (lookup env) args))]
159 : jhr 400 | S.E_Slice(x, indices, ty) => let
160 :     val x = lookup env x
161 :     val mask = List.map isSome indices
162 :     fun cvt NONE = NONE
163 :     | cvt (SOME x) = SOME(lookup env x)
164 :     val indices = List.mapPartial cvt indices
165 :     in
166 :     if List.all (fn b => b) mask
167 :     then [(lhs, IL.OP(HighOps.Subscript(IL.Var.ty x), x::indices))]
168 :     else [(lhs, IL.OP(HighOps.Slice(IL.Var.ty lhs, mask), x::indices))]
169 :     end
170 : jhr 407 | S.E_Input(_, name, NONE) =>
171 :     [(lhs, IL.OP(HighOps.Input(IL.Var.ty lhs, name), []))]
172 : jhr 229 | S.E_Input(_, name, SOME dflt) =>
173 : jhr 407 [(lhs, IL.OP(HighOps.InputWithDefault(IL.Var.ty lhs, name), [lookup env dflt]))]
174 : jhr 517 | S.E_LoadImage(info, name) => [(lhs, IL.OP(HighOps.LoadImage info, [lookup env name]))]
175 : jhr 176 (* end case *))
176 : jhr 168
177 : jhr 563 fun cvtBlock (state, env : env, joinStk, S.Block stms) = let
178 : jhr 502 fun cvt (env : env, cfg, []) = (cfg, env)
179 : jhr 497 | cvt (env, cfg, stm::stms) = (case stm
180 : jhr 648 of S.S_Var x => let
181 :     val x' = newVar x
182 :     in
183 :     cvt (VMap.insert (env, x, x'), cfg, stms)
184 :     end
185 :     | S.S_Assign(lhs, rhs) => let
186 : jhr 501 val lhs' = newVar lhs
187 :     val assigns = cvtExp (env, lhs', rhs)
188 : jhr 497 in
189 : jhr 501 recordAssign (env, joinStk, lhs, lhs');
190 : jhr 506 cvt (
191 :     VMap.insert(env, lhs, lhs'),
192 :     IL.CFG.concat(cfg, IL.CFG.mkBlock assigns),
193 :     stms)
194 : jhr 497 end
195 :     | S.S_IfThenElse(x, b0, b1) => let
196 : jhr 192 val x' = lookup env x
197 : jhr 497 val join = newJoin 2
198 : jhr 563 val (cfg0, _) = cvtBlock (state, env, (0, join)::joinStk, b0)
199 :     val (cfg1, _) = cvtBlock (state, env, (1, join)::joinStk, b1)
200 : jhr 497 val cond = IL.Node.mkCOND {
201 :     cond = x',
202 : jhr 501 trueBranch = IL.Node.dummy,
203 :     falseBranch = IL.Node.dummy
204 : jhr 497 }
205 : jhr 190 in
206 : jhr 506 IL.Node.addEdge (IL.CFG.exit cfg, cond);
207 : jhr 497 case commitJoin (env, joinStk, join)
208 :     of (env, SOME joinNd) => (
209 : jhr 500 if IL.CFG.isEmpty cfg0
210 : jhr 507 then (
211 :     IL.Node.setTrueBranch (cond, joinNd);
212 :     IL.Node.setPred (joinNd, cond))
213 : jhr 501 else (
214 :     IL.Node.setTrueBranch (cond, IL.CFG.entry cfg0);
215 : jhr 507 IL.Node.setPred (IL.CFG.entry cfg0, cond);
216 : jhr 501 IL.Node.addEdge (IL.CFG.exit cfg0, joinNd));
217 : jhr 500 if IL.CFG.isEmpty cfg1
218 : jhr 507 then (
219 :     IL.Node.setFalseBranch (cond, joinNd);
220 :     IL.Node.setPred (joinNd, cond))
221 : jhr 501 else (
222 :     IL.Node.setFalseBranch (cond, IL.CFG.entry cfg1);
223 : jhr 507 IL.Node.setPred (IL.CFG.entry cfg1, cond);
224 : jhr 501 IL.Node.addEdge (IL.CFG.exit cfg1, joinNd));
225 : jhr 500 cvt (
226 :     env,
227 : jhr 501 IL.CFG{entry = IL.CFG.entry cfg, exit = joinNd},
228 : jhr 500 stms))
229 : jhr 541 (* the join node has only zero predecessors, so
230 : jhr 500 * it was killed.
231 :     *)
232 : jhr 504 | (env, NONE) => raise Fail "unimplemented" (* FIXME *)
233 : jhr 192 (* end case *)
234 : jhr 190 end
235 : jhr 497 | S.S_New(strandId, args) => let
236 : jhr 498 val nd = IL.Node.mkNEW{
237 :     strand = strandId,
238 :     args = List.map (lookup env) args
239 :     }
240 : jhr 192 in
241 : jhr 497 cvt (env, IL.CFG.appendNode (cfg, nd), stms)
242 : jhr 194 end
243 : jhr 497 | S.S_Die => (
244 :     killPath joinStk;
245 : jhr 502 (IL.CFG.appendNode (cfg, IL.Node.mkDIE ()), env))
246 : jhr 563 | S.S_Stabilize => let
247 :     val stateOut = List.map (lookup env) state
248 :     in
249 :     killPath joinStk;
250 :     (IL.CFG.appendNode (cfg, IL.Node.mkSTABILIZE stateOut), env)
251 :     end
252 : jhr 192 (* end case *))
253 :     in
254 : jhr 500 cvt (env, IL.CFG.empty, stms)
255 : jhr 192 end
256 : jhr 168
257 : jhr 256 fun cvtTopLevelBlock (env, blk) = let
258 : jhr 563 val (cfg, env) = cvtBlock ([], env, [], blk)
259 : jhr 502 val entry = IL.Node.mkENTRY ()
260 : jhr 1017 val exit = IL.Node.mkRETURN (VMap.listItems env)
261 : jhr 256 in
262 : jhr 541 if IL.CFG.isEmpty cfg
263 :     then IL.Node.addEdge (entry, exit)
264 :     else (
265 :     IL.Node.addEdge (entry, IL.CFG.entry cfg);
266 :     (* NOTE: this addEdge could fail if all control paths end in DIE or STABILIZE,
267 :     * so we wrap it in a handler
268 :     *)
269 :     IL.Node.addEdge (IL.CFG.exit cfg, exit) handle _ => ());
270 : jhr 502 (IL.CFG{entry = entry, exit = exit}, env)
271 : jhr 256 end
272 :    
273 : jhr 624 (* FIXME: the following function could be refactored with cvtTopLevelBlock to share code *)
274 :     fun cvtFragmentBlock (env, blk) = let
275 :     val (cfg, env) = cvtBlock ([], env, [], blk)
276 :     val entry = IL.Node.mkENTRY ()
277 :     val exit = IL.Node.mkFRAGMENT []
278 :     in
279 :     if IL.CFG.isEmpty cfg
280 :     then IL.Node.addEdge (entry, exit)
281 :     else (
282 :     IL.Node.addEdge (entry, IL.CFG.entry cfg);
283 :     (* NOTE: this addEdge could fail if all control paths end in DIE or STABILIZE,
284 :     * so we wrap it in a handler
285 :     *)
286 :     IL.Node.addEdge (IL.CFG.exit cfg, exit) handle _ => ());
287 :     (IL.CFG{entry = entry, exit = exit}, env)
288 :     end
289 :    
290 : jhr 563 fun cvtMethod (env, name, state, blk) = let
291 :     (* allocate fresh variables for the state variables *)
292 :     val (env, stateIn) = freshVars (env, state)
293 :     (* convert the body of the method *)
294 :     val (cfg, env) = cvtBlock (state, env, [], blk)
295 :     (* add the entry/exit nodes *)
296 :     val stateOut = List.map (lookup env) state
297 :     val entry = IL.Node.mkENTRY ()
298 :     val exit = IL.Node.mkACTIVE stateOut
299 : jhr 256 in
300 : jhr 563 if IL.CFG.isEmpty cfg
301 :     then IL.Node.addEdge (entry, exit)
302 :     else (
303 :     IL.Node.addEdge (entry, IL.CFG.entry cfg);
304 :     (* NOTE: this addEdge could fail if all control paths end in DIE or STABILIZE,
305 :     * so we wrap it in a handler
306 :     *)
307 :     IL.Node.addEdge (IL.CFG.exit cfg, exit) handle _ => ());
308 :     IL.Method{
309 :     name = name,
310 :     stateIn = stateIn,
311 :     body = IL.CFG{entry = entry, exit = exit}
312 :     }
313 : jhr 256 end
314 :    
315 : jhr 613 (* convert the initially code *)
316 : jhr 621 fun cvtInitially (env, S.Initially{isArray, rangeInit, create, iters}) = let
317 :     val S.C_Create{argInit, name, args} = create
318 :     fun cvtIter ({param, lo, hi}, (env, iters)) = let
319 : jhr 613 val param' = newVar param
320 :     val env = VMap.insert (env, param, param')
321 : jhr 621 val iter = (param', lookup env lo, lookup env hi)
322 : jhr 613 in
323 :     (env, iter::iters)
324 :     end
325 : jhr 624 val (cfg, env) = cvtFragmentBlock (env, rangeInit)
326 : jhr 613 val (env, iters) = List.foldl cvtIter (env, []) iters
327 : jhr 624 val (argInitCFG, env) = cvtFragmentBlock (env, argInit)
328 : jhr 613 in
329 :     IL.Initially{
330 :     isArray = isArray,
331 : jhr 621 rangeInit = cfg,
332 :     iters = List.rev iters,
333 :     create = (argInitCFG, name, List.map (lookup env) args)
334 : jhr 613 }
335 :     end
336 :    
337 : jhr 609 fun translate (S.Program{globals, globalInit, init, strands}) = let
338 : jhr 256 val (globalInit, env) = cvtTopLevelBlock (VMap.empty, globalInit)
339 : jhr 1017 (* construct a reduced environment that just defines the globals. *)
340 :     val env = let
341 : jhr 200 val lookup = lookup env
342 : jhr 1017 fun cvtVar (x, env) = VMap.insert(env, x, lookup x)
343 :     val env = List.foldl cvtVar VMap.empty globals
344 : jhr 200 in
345 : jhr 1017 env
346 : jhr 200 end
347 : jhr 621 val init = cvtInitially (env, init)
348 : jhr 500 fun cvtStrand (S.Strand{name, params, state, stateInit, methods}) = let
349 : jhr 200 val (env, params) = let
350 :     fun cvtParam (x, (env, xs)) = let
351 :     val x' = newVar x
352 :     in
353 :     (VMap.insert(env, x, x'), x'::xs)
354 :     end
355 :     val (env, params) = List.foldl cvtParam (env, []) params
356 :     in
357 :     (env, List.rev params)
358 :     end
359 : jhr 256 val (stateInit, env) = cvtTopLevelBlock (env, stateInit)
360 : jhr 654 val state' = let
361 :     fun cvtStateVar x = (Var.kindOf x = S.StrandOutputVar, lookup env x)
362 :     in
363 :     List.map cvtStateVar state
364 :     end
365 :     fun cvtMeth (S.Method(name, blk)) = cvtMethod (env, name, state, blk)
366 : jhr 200 in
367 : jhr 500 IL.Strand{
368 : jhr 200 name = name,
369 :     params = params,
370 : jhr 256 state = state',
371 : jhr 200 stateInit = stateInit,
372 : jhr 563 methods = List.map cvtMeth methods
373 : jhr 200 }
374 :     end
375 : jhr 508 val prog = IL.Program{
376 :     globalInit = globalInit,
377 : jhr 613 initially = init,
378 : jhr 508 strands = List.map cvtStrand strands
379 :     }
380 : jhr 200 in
381 : jhr 508 Census.init prog;
382 :     prog
383 : jhr 200 end
384 : jhr 176
385 : jhr 137 end

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