184 lines
6.2 KiB
Standard ML
184 lines
6.2 KiB
Standard ML
|
|
signature CANON =
|
||
|
|
sig
|
||
|
|
val linearize : Tree.stm -> Tree.stm list
|
||
|
|
(* From an arbitrary Tree statement, produce a list of cleaned trees
|
||
|
|
satisfying the following properties:
|
||
|
|
1. No SEQ's or ESEQ's
|
||
|
|
2. The parent of every CALL is an EXP(..) or a MOVE(TEMP t,..)
|
||
|
|
*)
|
||
|
|
|
||
|
|
val basicBlocks : Tree.stm list -> (Tree.stm list list * Tree.label)
|
||
|
|
(* From a list of cleaned trees, produce a list of
|
||
|
|
basic blocks satisfying the following properties:
|
||
|
|
1. and 2. as above;
|
||
|
|
3. Every block begins with a LABEL;
|
||
|
|
4. A LABEL appears only at the beginning of a block;
|
||
|
|
5. Any JUMP or CJUMP is the last stm in a block;
|
||
|
|
6. Every block ends with a JUMP or CJUMP;
|
||
|
|
Also produce the "label" to which control will be passed
|
||
|
|
upon exit.
|
||
|
|
*)
|
||
|
|
|
||
|
|
val traceSchedule : Tree.stm list list * Tree.label -> Tree.stm list
|
||
|
|
(* From a list of basic blocks satisfying properties 1-6,
|
||
|
|
along with an "exit" label,
|
||
|
|
produce a list of stms such that:
|
||
|
|
1. and 2. as above;
|
||
|
|
7. Every CJUMP(_,t,f) is immediately followed by LABEL f.
|
||
|
|
The blocks are reordered to satisfy property 7; also
|
||
|
|
in this reordering as many JUMP(T.NAME(lab)) statements
|
||
|
|
as possible are eliminated by falling through into T.LABEL(lab).
|
||
|
|
*)
|
||
|
|
end
|
||
|
|
|
||
|
|
structure Canon : CANON =
|
||
|
|
struct
|
||
|
|
|
||
|
|
structure T = Tree
|
||
|
|
|
||
|
|
fun linearize(stm0: T.stm) : T.stm list =
|
||
|
|
let
|
||
|
|
infix %
|
||
|
|
fun (T.EXP(T.CONST _)) % x = x
|
||
|
|
| x % (T.EXP(T.CONST _)) = x
|
||
|
|
| x % y = T.SEQ(x,y)
|
||
|
|
|
||
|
|
fun commute(T.EXP(T.CONST _), _) = true
|
||
|
|
| commute(_, T.NAME _) = true
|
||
|
|
| commute(_, T.CONST _) = true
|
||
|
|
| commute _ = false
|
||
|
|
|
||
|
|
val nop = T.EXP(T.CONST 0)
|
||
|
|
|
||
|
|
fun reorder ((e as T.CALL _ )::rest) =
|
||
|
|
let val t = Temp.newtemp()
|
||
|
|
in reorder(T.ESEQ(T.MOVE(T.TEMP t, e), T.TEMP t) :: rest)
|
||
|
|
end
|
||
|
|
| reorder (a::rest) =
|
||
|
|
let val (stms,e) = do_exp a
|
||
|
|
val (stms',el) = reorder rest
|
||
|
|
in if commute(stms',e)
|
||
|
|
then (stms % stms',e::el)
|
||
|
|
else let val t = Temp.newtemp()
|
||
|
|
in (stms % T.MOVE(T.TEMP t, e) % stms', T.TEMP t :: el)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
| reorder nil = (nop,nil)
|
||
|
|
|
||
|
|
and reorder_exp(el,build) = let val (stms,el') = reorder el
|
||
|
|
in (stms, build el')
|
||
|
|
end
|
||
|
|
|
||
|
|
and reorder_stm(el,build) = let val (stms,el') = reorder (el)
|
||
|
|
in stms % build(el')
|
||
|
|
end
|
||
|
|
|
||
|
|
and do_stm(T.SEQ(a,b)) =
|
||
|
|
do_stm a % do_stm b
|
||
|
|
| do_stm(T.JUMP(e,labs)) =
|
||
|
|
reorder_stm([e],fn [e] => T.JUMP(e,labs))
|
||
|
|
| do_stm(T.CJUMP(p,a,b,t,f)) =
|
||
|
|
reorder_stm([a,b], fn[a,b]=> T.CJUMP(p,a,b,t,f))
|
||
|
|
| do_stm(T.MOVE(T.TEMP t,T.CALL(e,el))) =
|
||
|
|
reorder_stm(e::el,fn e::el => T.MOVE(T.TEMP t,T.CALL(e,el)))
|
||
|
|
| do_stm(T.MOVE(T.TEMP t,b)) =
|
||
|
|
reorder_stm([b],fn[b]=>T.MOVE(T.TEMP t,b))
|
||
|
|
| do_stm(T.MOVE(T.MEM e,b)) =
|
||
|
|
reorder_stm([e,b],fn[e,b]=>T.MOVE(T.MEM e,b))
|
||
|
|
| do_stm(T.MOVE(T.ESEQ(s,e),b)) =
|
||
|
|
do_stm(T.SEQ(s,T.MOVE(e,b)))
|
||
|
|
| do_stm(T.EXP(T.CALL(e,el))) =
|
||
|
|
reorder_stm(e::el,fn e::el => T.EXP(T.CALL(e,el)))
|
||
|
|
| do_stm(T.EXP e) =
|
||
|
|
reorder_stm([e],fn[e]=>T.EXP e)
|
||
|
|
| do_stm s = reorder_stm([],fn[]=>s)
|
||
|
|
|
||
|
|
and do_exp(T.BINOP(p,a,b)) =
|
||
|
|
reorder_exp([a,b], fn[a,b]=>T.BINOP(p,a,b))
|
||
|
|
| do_exp(T.MEM(a)) =
|
||
|
|
reorder_exp([a], fn[a]=>T.MEM(a))
|
||
|
|
| do_exp(T.ESEQ(s,e)) =
|
||
|
|
let val stms = do_stm s
|
||
|
|
val (stms',e) = do_exp e
|
||
|
|
in (stms%stms',e)
|
||
|
|
end
|
||
|
|
| do_exp(T.CALL(e,el)) =
|
||
|
|
reorder_exp(e::el, fn e::el => T.CALL(e,el))
|
||
|
|
| do_exp e = reorder_exp([],fn[]=>e)
|
||
|
|
|
||
|
|
(* linear gets rid of the top-level SEQ's, producing a list *)
|
||
|
|
fun linear(T.SEQ(a,b),l) = linear(a,linear(b,l))
|
||
|
|
| linear(s,l) = s::l
|
||
|
|
|
||
|
|
in (* body of linearize *)
|
||
|
|
linear(do_stm stm0, nil)
|
||
|
|
end
|
||
|
|
|
||
|
|
type block = T.stm list
|
||
|
|
|
||
|
|
(* Take list of statements and make basic blocks satisfying conditions
|
||
|
|
3 and 4 above, in addition to the extra condition that
|
||
|
|
every block ends with a JUMP or CJUMP *)
|
||
|
|
|
||
|
|
fun basicBlocks stms =
|
||
|
|
let val done = Temp.newlabel()
|
||
|
|
fun blocks((head as T.LABEL _) :: tail, blist) =
|
||
|
|
let fun next((s as (T.JUMP _))::rest, thisblock) =
|
||
|
|
endblock(rest, s::thisblock)
|
||
|
|
| next((s as (T.CJUMP _))::rest, thisblock) =
|
||
|
|
endblock(rest,s::thisblock)
|
||
|
|
| next(stms as (T.LABEL lab :: _), thisblock) =
|
||
|
|
next(T.JUMP(T.NAME lab,[lab]) :: stms, thisblock)
|
||
|
|
| next(s::rest, thisblock) = next(rest, s::thisblock)
|
||
|
|
| next(nil, thisblock) =
|
||
|
|
next([T.JUMP(T.NAME done, [done])], thisblock)
|
||
|
|
|
||
|
|
and endblock(stms, thisblock) =
|
||
|
|
blocks(stms, rev thisblock :: blist)
|
||
|
|
|
||
|
|
in next(tail, [head])
|
||
|
|
end
|
||
|
|
| blocks(nil, blist) = rev blist
|
||
|
|
| blocks(stms, blist) = blocks(T.LABEL(Temp.newlabel())::stms, blist)
|
||
|
|
in (blocks(stms,nil), done)
|
||
|
|
end
|
||
|
|
|
||
|
|
fun enterblock(b as (T.LABEL s :: _), table) = Symbol.enter(table,s,b)
|
||
|
|
| enterblock(_, table) = table
|
||
|
|
|
||
|
|
fun splitlast([x]) = (nil,x)
|
||
|
|
| splitlast(h::t) = let val (t',last) = splitlast t in (h::t', last) end
|
||
|
|
|
||
|
|
fun trace(table,b as (T.LABEL lab :: _),rest) =
|
||
|
|
let val table = Symbol.enter(table, lab, nil)
|
||
|
|
in case splitlast b
|
||
|
|
of (most,T.JUMP(T.NAME lab, _)) =>
|
||
|
|
(case Symbol.look(table, lab)
|
||
|
|
of SOME(b' as _::_) => most @ trace(table, b', rest)
|
||
|
|
| _ => b @ getnext(table,rest))
|
||
|
|
| (most,T.CJUMP(opr,x,y,t,f)) =>
|
||
|
|
(case (Symbol.look(table,t), Symbol.look(table,f))
|
||
|
|
of (_, SOME(b' as _::_)) => b @ trace(table, b', rest)
|
||
|
|
| (SOME(b' as _::_), _) =>
|
||
|
|
most @ [T.CJUMP(T.notRel opr,x,y,f,t)]
|
||
|
|
@ trace(table, b', rest)
|
||
|
|
| _ => let val f' = Temp.newlabel()
|
||
|
|
in most @ [T.CJUMP(opr,x,y,t,f'),
|
||
|
|
T.LABEL f', T.JUMP(T.NAME f,[f])]
|
||
|
|
@ getnext(table,rest)
|
||
|
|
end)
|
||
|
|
| (most, T.JUMP _) => b @ getnext(table,rest)
|
||
|
|
end
|
||
|
|
|
||
|
|
and getnext(table,(b as (T.LABEL lab::_))::rest) =
|
||
|
|
(case Symbol.look(table, lab)
|
||
|
|
of SOME(_::_) => trace(table,b,rest)
|
||
|
|
| _ => getnext(table,rest))
|
||
|
|
| getnext(table,nil) = nil
|
||
|
|
|
||
|
|
fun traceSchedule(blocks,done) =
|
||
|
|
getnext(foldr enterblock Symbol.empty blocks, blocks)
|
||
|
|
@ [T.LABEL done]
|
||
|
|
|
||
|
|
end
|