Home My Page Projects Code Snippets Project Openings diderot

SCM Repository

[diderot] View of /branches/charisee/src/compiler/IL/value-numbering-fn.sml
 [diderot] / branches / charisee / src / compiler / IL / value-numbering-fn.sml

View of /branches/charisee/src/compiler/IL/value-numbering-fn.sml

Fri May 23 18:57:58 2014 UTC (6 years, 8 months ago) by jhr
File size: 17615 byte(s)
```  various changes
```
```(* value-numbering-fn.sml
*
* COPYRIGHT (c) 2011 The Diderot Project (http://diderot-language.cs.uchicago.edu)
*
* This file contains an implementation of the hash-based value numbering
* algorithm described in
*
*      Value Numbering
*      by Preston Briggs, Keith Cooper, and Taylor Simpson
*      CRPC-TR94517-S
*      November 1994
*)

functor ValueNumberingFn (D : DOMINANCE_TREE) : sig

structure IL : SSA

val transform : IL.program -> IL.program

end = struct

structure IL = D.IL
structure E = ExprFn (IL)
structure ValueMap = E.Map
structure ST = Stats
structure HE=hashEin
structure PE=Printer

type expr = E.expr

(********** Counters for statistics **********)
val cntMeaninglessPhi       = ST.newCounter (IL.ilName ^ ":meaningless-phi")
val cntRedundantPhi         = ST.newCounter (IL.ilName ^ ":redundant-phi")
val cntRedundantAssign      = ST.newCounter (IL.ilName ^ ":redundant-assign")

(* adjust a variable's use count *)
fun incUse (IL.V{useCnt, ...}) = (useCnt := !useCnt + 1)
fun decUse (IL.V{useCnt, ...}) = (useCnt := !useCnt - 1)

local
(* property for mapping variables to their value number (VN), which is represented as a
* SSA variable.  If their VN is different from themselves, then they are redundant.
*)
val {getFn=getVN, setFn=setVN, clrFn=clrVN, ...} = IL.Var.newProp (fn x => x)

(* property for mapping value numbers to hash-consed expressions. *)
val {getFn=getExp : IL.var -> expr, setFn=setExp, clrFn=clrExp, ...} =
IL.Var.newProp (fn x => raise Fail(concat["getExp(", IL.Var.toString x, ")"]))

datatype env = ENV of {
avail : IL.var ValueMap.map   (* map from expressions to their value numbers, which *)
(* are represented as SSA vars.  The domain are those *)
(* expressions that are available. *)
}
in
val emptyEnv = ENV{avail = ValueMap.empty}
(* map variables to their hash-consed definition *)
val getVN = getVN
val setVN = setVN
fun varToExp x = ((*print "\n VarToExp"; print(IL.Var.toString x);*)getExp(getVN x))
fun bindVarToExp (ENV{avail}, x, e) = (
(*DEBUG**Log.msg()*)

(*print (concat["** bindVarToExp: ", IL.Var.toString x, " --> ", E.toString e, "\n"]);*)
setVN(x, x); setExp(x, e);
ENV{avail = ValueMap.insert(avail, e, x)})
fun expToVN (ENV{avail}, e) = ValueMap.find(avail, e)
(* rename a variable if it's value number is different than itself *)
fun rename x = let
val x' = getVN x
in
if IL.Var.same(x, x')
then x
else (
(*DEBUG**Log.msg(concat["** rename ", IL.Var.toString x, " to ", IL.Var.toString x', "\n"]);*)
decUse x; incUse x';
x')
end
(* does a variable change; i.e., get replaced by another variable? *)
fun changed x = not(IL.Var.same(x, getVN x))
(* clear the properties of a variable *)
fun clearVar x = (clrVN x; clrExp x)
(* clear the properties from the variables of a node *)
fun clearNode nd = List.app clearVar (IL.Node.defs nd)
end (* local *)

fun rewriteCFG cfg = let
(* in case the exit node get rewritten, we need to reset it *)
val exitNd = ref(IL.CFG.exit cfg)
(* rewrite or delete a node, if necessary.  Note that we have already rewritten the JOIN nodes *)
fun doNode nd = (case IL.Node.kind nd
of IL.COND{pred, cond, trueBranch, falseBranch} =>
if changed cond
then let
val newNd = IL.Node.mkCOND {
cond = rename cond,
trueBranch = !trueBranch,
falseBranch = !falseBranch
}
in
IL.Node.replaceInEdge {src = !pred, oldDst = nd, dst = newNd};
IL.Node.replaceOutEdge {oldSrc = nd, src = newNd, dst = !trueBranch};
IL.Node.replaceOutEdge {oldSrc = nd, src = newNd, dst = !falseBranch}
end
else ()
| IL.ASSIGN{stm=(y, rhs), succ, ...} =>
if changed y
then (
(* deleting redundant assignment *)
IL.RHS.app decUse rhs;
IL.CFG.deleteNode nd)
else if (List.exists changed (IL.RHS.vars rhs))
(* rewrite node to rename variables *)
then IL.CFG.replaceNode(nd, IL.Node.mkASSIGN(y, IL.RHS.map rename rhs))
else ()
| IL.MASSIGN{stm=([], rator, xs), succ, ...} =>
if (List.exists changed xs)
(* rewrite node to rename variables *)
then IL.CFG.replaceNode(nd, IL.Node.mkMASSIGN([], rator, List.map rename xs))
else ()
| IL.MASSIGN{stm=(ys, rator, xs), succ, ...} =>
if List.all changed ys
then (
(* deleting redundant assignment *)
List.app decUse xs;
IL.CFG.deleteNode nd)
else if (List.exists changed xs)
(* rewrite node to rename variables *)
then IL.CFG.replaceNode(nd, IL.Node.mkMASSIGN(ys, rator, List.map rename xs))
else ()
| IL.NEW{strand, args, ...} =>
if List.exists changed args
then IL.CFG.replaceNode(nd, IL.Node.mkNEW{
strand=strand, args=List.map rename args
})
else ()
| IL.SAVE{lhs, rhs, ...} =>
if changed rhs
then IL.CFG.replaceNode(nd, IL.Node.mkSAVE(lhs, rename rhs))
else ()
| IL.EXIT{kind, live, ...} =>
if List.exists changed live
then let
val newNd = IL.Node.mkEXIT(kind, List.map rename live)
in
if IL.Node.same(nd, !exitNd)
then exitNd := newNd
else ();
IL.CFG.replaceNode (nd, newNd)
end
else ()
| _ => ()
(* end case *))
val _ = List.app doNode (IL.CFG.sort cfg)
val cfg = IL.CFG{entry = IL.CFG.entry cfg, exit = !exitNd}
in
IL.CFG.apply clearNode cfg;
cfg
end

fun transformCFG (liveIn, renameIn, cfg) =(* cfg HERE *)let
val tbl = E.new()
val mkSTATE = E.mkSTATE tbl
val mkVAR = E.mkVAR tbl
val mkLIT = E.mkLIT tbl
val mkOP = E.mkOP tbl
val mkMULTIOP = E.mkMULTIOP tbl
val mkAPPLY = E.mkAPPLY tbl
val mkCONS = E.mkCONS tbl
val mkPHI = E.mkPHI tbl
val mkEinOP = E.mkEinOP tbl

(* convert a list of variables to a list of expressions *)
fun varsToExp (env, xs) = (List.map varToExp xs)
(* convert an SSA RHS into a hash-consed expression *)
fun mkExp (env, rhs) = (case rhs
of IL.STATE x => mkSTATE x
| IL.VAR x => varToExp x
| IL.LIT l => mkLIT l
| IL.OP(rator, args) =>( mkOP(rator, varsToExp(env, args)))
| IL.APPLY(f, args) =>(mkAPPLY(f, varsToExp(env, args)))
| IL.CONS(ty, args) => ( mkCONS(ty, varsToExp(env, args)))
| IL.EINAPP(exp,args)=>  ((*print "\n\n\n EINAPP \n";print(PE.printerE(exp));*)mkEinOP(exp, varsToExp(env,args)))

(* end case *))

(* walk the dominator tree computing value numbers *)

fun vn (env, nd) = let
val env = (case IL.Node.kind nd
of IL.JOIN{succ, phis, ...} => let
fun doPhi ((y, xs), (env, phis)) = let
val vn::vns = List.map getVN xs
in
if List.all (fn vn' => IL.Var.same(vn, vn')) vns
then ((* a meaningless phi node; map y to vn *)
(* DEBUG Log.msg(concat["** meaningless phi node: ", IL.phiToString (y, xs), "\n"]);*)
ST.tick cntMeaninglessPhi;
List.map decUse xs;
setVN(y, vn);
(env, phis))
else let
val exp = mkPHI(varsToExp(env, xs))
in
case expToVN(env, exp)
of SOME vn' => ((* a redundant phi node *)
(* DEBUG Log.msg(concat["** redundant phi node: ", IL.phiToString (y, xs), "\n"]);*)
ST.tick cntRedundantPhi;
List.map decUse xs;
setVN(y, vn');
(env, phis))
| NONE => let
val xs = List.map rename xs
in
(bindVarToExp(env, y, exp), (y, xs)::phis)
end
(* end case *)
end
end
val (env, remainingPhis) = List.foldl doPhi (env, []) (!phis)
in
phis := List.rev remainingPhis;
env
end

| IL.ASSIGN{stm=(y, rhs), succ, ...} => let
(*val tester=print(String.concat["\n\n START \n ",IL.Var.toString y])*)
val exp = mkExp(env, rhs)
(* val tester=print(String.concat["\n END \n\n "])*)
in
case expToVN(env, exp)
of SOME vn => ((* y is redundant, so map it to vn *)
(* DEBUG ** Log.msg(concat["** redundant assignment: ", IL.assignToString (y, rhs),*)
(* DEBUG **"; VN[", IL.Var.toString y, "] = ", IL.Var.toString vn, "\n"]);*)
ST.tick cntRedundantAssign;
setVN(y, vn);
env)
| NONE => bindVarToExp(env, y, exp)
(* end case *)
end
| IL.MASSIGN{stm=(ys, rator, xs), succ, ...} => let
val xs = varsToExp(env, xs)
fun mkExps (env, _, []) = env
| mkExps (env, i, y::ys) = let
val exp = mkMULTIOP(i, rator, xs)
in
case expToVN(env, exp)
of SOME vn => ((* y is redundant, so map it to vn *)
ST.tick cntRedundantAssign;
setVN(y, vn);
mkExps (env, i+1, ys))
| NONE => mkExps (bindVarToExp(env, y, exp), i+1, ys)
(* end case *)
end
in
mkExps (env, 0, ys)
end
| _ => env
(* end case *))
in
List.app (fn nd => vn (env, nd)) (D.children nd)
end

(* define the initial environment by mapping the liveIn variables to themselves *)
val env = List.foldl (fn (x, env) => bindVarToExp(env, x, mkVAR x)) emptyEnv liveIn
(* set the VN of the incoming renamed variables accordingly *)
val _ = List.app setVN renameIn
in
D.computeTree cfg;
(* compute value numbers over the dominance tree *)
vn (env, IL.CFG.entry cfg);
D.clear cfg;
(* delete and rewrite nodes as necessary *)
rewriteCFG cfg before
(List.app clearVar liveIn; List.app (clearVar o #1) renameIn)
end

(*here *)
fun transformCFG' (liveIn, renameIn, cfg) =  let
val origLiveOut = IL.CFG.liveAtExit cfg
val cfg = transformCFG (liveIn, renameIn, cfg)
val liveOut = IL.CFG.liveAtExit cfg
(* compute a mapping from the original liveOut variables to their new names *)
val rename = let
fun findDups (x, x', rename) =
if IL.Var.same(x, x')
then rename
else IL.Var.Map.insert(rename, x, x')
in
ListPair.foldl findDups IL.Var.Map.empty (origLiveOut, liveOut)
end
(* filter out duplicate names from the liveOut list *)
val foundDup = ref false
val liveOut' = let
fun f (x, ys) = if List.exists (fn y => IL.Var.same(x, y)) ys
then (foundDup := true; ys)
else x::ys
in
List.foldr f [] liveOut
end
(* if there were any duplicates, then rewrite the exit node *)
val cfg = if !foundDup
then IL.CFG.updateExit(cfg, fn _ => liveOut')
else cfg
in
{cfg = cfg, rename = IL.Var.Map.foldli (fn (x, y, l) => (x, y)::l) renameIn rename}
end

fun transform prog = let
val IL.Program{props, globalInit, initially, strands} = prog
val {cfg=globalInit, rename} = transformCFG' ([], [], globalInit)
val globals = IL.CFG.liveAtExit globalInit
(* transform the strand initialization code *)
val initially = if List.null rename
then initially
else let
val IL.Initially{isArray, rangeInit, iters, create} = initially
(* first process the range initialization code *)
val {cfg=rangeInit, rename} = transformCFG' (globals, rename, rangeInit)
val live = IL.CFG.liveAtExit rangeInit @ globals
(* create a function for renaming variables *)
fun mkRenameFn rename = let
val vMap = List.foldl IL.Var.Map.insert' IL.Var.Map.empty rename
fun renameVar x = (case IL.Var.Map.find (vMap, x)
of NONE => x
| SOME x' => x'
(* end case *))
in
renameVar
end
(* rename the bounds of the iterators *)
val iters = let
val renameVar = mkRenameFn rename
in
List.map (fn (x, lo, hi) => (x, renameVar lo, renameVar hi)) iters
end
(* add the iteration variables to the live list *)
val live = List.foldl (fn ((x, _, _), lv) => x::lv) live iters
(* process the body *)
val (cfg, strand, args) = create
val {cfg, rename} = transformCFG' (live, rename, cfg)
val create = (cfg, strand, List.map (mkRenameFn rename) args)
in
IL.Initially{
isArray = isArray, rangeInit = rangeInit,
iters = iters, create= create
}
end
(* transform a strand *)
fun transformStrand (IL.Strand{name, params, state, stateInit, methods}) = let
val liveIn = params @ globals
val stateInit = transformCFG (liveIn, rename, stateInit)
(* FIXME: what if a state variable becomes redundant? *)
fun transformMeth (IL.Method{name, body}) = let
val body = transformCFG (liveIn, rename, body)
in
IL.Method{name=name, body=body}
end
in
IL.Strand{
name = name,
params = params,
state = state,
stateInit = stateInit,
methods = List.map transformMeth methods
}
end
val strands = List.map transformStrand strands
in
IL.Program{
props = props,
globalInit = globalInit,
initially = initially,
strands = strands
}
end

end
```