1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
|
(*
* This module builds the data dependence graph for acyclic scheduling.
*
* Notes:
* 1. Special source and sink nodes are added to each basic block.
* These nodes anchor live-in and live-out values.
* 2. If a block has a branch, then it is control dependent on the live-in
* node.
*
* -- Allen
*)
functor SchedulerDDGBuilder
(structure DDG : SCHEDULER_DDG
structure CFG : CONTROL_FLOW_GRAPH
structure RTLProps : RTL_PROPERTIES
structure InsnProps : INSN_PROPERTIES
sharing InsnProps.I = RTLProps.I = DDG.I = CFG.I
) : SCHEDULER_DDG_BUILDER =
struct
structure DDG = DDG
structure CFG = CFG
structure RTL = RTLProps.RTL
structure G = Graph
structure I = CFG.I
structure C = I.C
structure SchedProps = DDG.SchedProps
structure HA = HashArray
structure A = Array
structure W8A = Word8Array
structure SL = SortedList
exception BuildDDG
fun error msg = MLRiscErrorMsg.error("BuildDDG",msg)
val i2s = Int.toString
(* Zero register magic! *)
val zeroTbl = W8A.array(C.firstPseudo, 0w0)
val _ = List.app (fn k =>
case C.zeroReg k of
SOME r => W8A.update(zeroTbl, r, 0w1)
| NONE => ()
) C.cellkinds
fun isZero r = W8A.sub(zeroTbl, r) <> 0w0 handle _ => false
exception Nothing
fun buildDDG{cpu_info, cfg, numberOfInstructions, blockIdTbl} =
let val CFG as G.GRAPH cfg = cfg
(* The number of nodes <= instructions + livein + liveout per block *)
val M = numberOfInstructions + #order cfg () * 2
val DDG as G.GRAPH ddg = DDG.newDDG M
val globalInfo = DDG.globalInfo DDG
(* Extract instruction properties *)
val SchedProps.CPU_INFO{defUse, ...} = cpu_info
(* Regmap magic! *)
val regmap = C.lookup(CFG.regmap CFG)
val regmapDefs = map (fn (r,l) => (regmap r,l))
val regmapUses = map regmap
fun simplifyCopy(instr, dst, src) =
let fun loop([], [], dst', src') = (dst', src')
| loop((d,l)::dst, s::src, dst', src') =
let val d = regmap d and s = regmap s
in if d = s then loop(dst, src, dst', src')
else loop(dst, src, (d,l)::dst', s::src')
end
| loop _ = error "simplifyCopy"
val (dst, src) = loop(dst, src, [], [])
(* add the copy temporary! *)
val dst = case dst of
[] => dst
| _ => case InsnProps.moveTmpR instr of
SOME r => (regmap r,~1)::dst
| _ => dst
in (dst, src)
end
(* Edge constructors *)
(* memory *)
fun m_flow(m,l) = DDG.EDGE{l=l, r=m, d=DDG.MEM_FLOW}
val m_anti = DDG.EDGE{l= ~1, r= ~1, d=DDG.MEM_ANTI}
val m_output = DDG.EDGE{l=0, r= ~1, d=DDG.MEM_OUTPUT}
(* register *)
fun flow(r,l) = DDG.EDGE{l=l, r=r, d=DDG.FLOW}
val output = DDG.EDGE{l=0, r= ~1, d=DDG.OUTPUT}
val anti = DDG.EDGE{l= ~1, r= ~1, d=DDG.ANTI}
(* control dependence *)
fun c_flow(r,l) = DDG.EDGE{l=l, r=r, d=DDG.CTRL}
val c_dep = DDG.EDGE{l= ~1, r= ~1, d=DDG.CTRL}
val c_output = DDG.EDGE{l=0, r= ~1, d=DDG.CTRL}
val c_anti = DDG.EDGE{l= ~1, r= ~1, d=DDG.CTRL_ANTI}
(* How to make a new edge *)
val newEdge = #add_edge ddg
(* val newEdge = fn (i,j,e) => (print(i2s i^"->"^i2s j^" "^DDG.edgeToString e^"\n"); newEdge(i,j,e)) handle e => raise e *)
(* A table of definitions and uses indexed by block *)
val defUseTbl = HA.array'(13, fn _ => raise BuildDDG)
(* Create nodes for block b *)
fun createNodes(id, b, [], ops) = (id, ops)
| createNodes(id, b, instr::instrs, ops) =
let val (d, u) = defUse instr
fun newNode(defs, uses) =
let val node = DDG.NODE{b=b,instr=instr,defs=defs,uses=uses}
in #add_node ddg (id, node);
createNodes(id+1, b, instrs, (id, node)::ops)
end
in case InsnProps.instrKind instr of
InsnProps.IK_COPY =>
(case simplifyCopy(instr, d, u) of
([], []) => createNodes(id, b, instrs, ops)
| (d, u) => newNode(d, u)
)
| _ => newNode(regmapDefs d, regmapUses u)
end
(* Scan one block; ops are in forward order *)
fun scanBlock{ops,liveIn=(liveIn,_),defTbl,useTbl} =
let fun addOutputAndAnti j (r,_) =
(app (fn i => newEdge(i,j,anti)) (HA.sub(useTbl,r));
app (fn (i,e) => newEdge(i,j,output)) (HA.sub(defTbl,r))
)
fun addFlow j r =
app (fn (i,e) => newEdge(i,j,e)) (HA.sub(defTbl,r))
(* Update def/use *)
fun addDef i (r,l) =
if isZero r then ()
else
(HA.update(defTbl,r,[(i,flow(r,l))]); HA.update(useTbl,r,[]))
fun addUse i r =
if isZero r then ()
else HA.update(useTbl,r,i::HA.sub(useTbl,r))
fun scan [] = ()
| scan((i,DDG.NODE{instr, defs, uses,...})::rest) =
let val rtl = RTLProps.rtl instr
in if RTL.can'tMoveUp rtl then
newEdge(liveIn, i, c_dep)
else ();
app (addOutputAndAnti i) defs;
app (addFlow i) uses;
(* update defs/uses *)
app (addUse i) uses;
app (addDef i) defs;
scan rest
end
in scan ops
end
val blockId = ref 0
val nodeId = ref 0
val blockMap = A.array(#order cfg (), 0)
val liveInMap = IntHashTable.mkTable(13, Nothing)
val liveOutMap = IntHashTable.mkTable(13, Nothing)
val specialMap = IntHashTable.mkTable(32, Nothing)
val addSpecial = IntHashTable.insert specialMap
val isSpecial = IntHashTable.find specialMap
val isSpecial = fn b => case isSpecial b of SOME _ => true
| NONE => false
(* Process a basic block in topological order of the region:
* 1. create all the nodes in the DDG
* 2. add the edges
*)
fun processBlock(b,b' as CFG.BLOCK{insns,...}) =
let val bid = !blockId (* block id *)
val _ = A.update(blockMap, bid, b)
val _ = A.update(blockIdTbl, b, bid)
val _ = blockId := bid + 1
fun createNode(instr, defs, uses) =
let val node = (!nodeId,
DDG.NODE{instr=instr,b=bid,defs=defs,uses=uses})
in nodeId := !nodeId + 1;
#add_node ddg node;
node
end
(* Create the nodes *)
val (newNodeId, ops) = createNodes(!nodeId, bid, !insns, [])
val _ = nodeId := newNodeId
val revAppend = List.revAppend
val defs = HA.array(13, [])
val uses = HA.array(13, [])
(* edge Y->X is an internal region edge
* merge definition and uses from Y => X
*)
fun mergeDefUse(Y,X,_) =
let val {defTbl, useTbl} = HA.sub(defUseTbl, Y)
in HA.appi (fn (r,es) =>
HA.update(defs, r, revAppend(es, HA.sub(defs, r))))
(defTbl, 0, NONE);
HA.appi (fn (r,is) =>
HA.update(uses, r, revAppend(is, HA.sub(uses, r))))
(useTbl, 0, NONE)
end
fun addCtrlDepEdge(i, j) = newEdge(i,j,c_dep)
(* Add a live-in node for a block that summarizes the
* values that are coming live-in from side-exits
*)
fun addLiveIn X =
let val entry_edges = #entry_edges cfg X
val liveIn =
SL.uniq(foldr (fn ((Y,_,_),S) =>
let val CFG.BLOCK{annotations,...} = #node_info cfg Y
in case #get DDG.LIVENESS (!annotations) of
SOME{liveOut, ...} => revAppend(liveOut,S)
| NONE => S
end) [] entry_edges)
val liveInNode as (i,_) =
createNode(SchedProps.source,
map (fn r => (r,~1)) liveIn, [])
val _ = IntHashTable.insert liveInMap (bid, liveInNode)
val _ = addSpecial(i, true)
fun addOutputAndAnti j r =
(app (fn i => if isSpecial j then ()
else newEdge(i,j,anti)) (HA.sub(uses,r));
app (fn (i,e) =>
if isSpecial i then ()
else newEdge(i,j,output)) (HA.sub(defs,r))
)
in app (addOutputAndAnti i) liveIn;
app (fn r => HA.update(defs, r,
(i,DDG.EDGE{l= ~1,r=r,d=DDG.LIVEIN})::HA.sub(defs, r)))
liveIn;
liveInNode
end
val _ = app mergeDefUse (#in_edges cfg b)
val liveInNode = addLiveIn b
(* Add a live-out node for a block that summarizes the
* values that are going live-out from side-exits
*)
fun addLiveOut X =
(case #exit_edges cfg X of
exit_edges =>
let fun createLiveOutNode(liveOut) =
let val node as (i, _) =
createNode(SchedProps.sink, [], liveOut)
in IntHashTable.insert liveOutMap (bid, node);
addSpecial(i, true);
node
end
val liveOut =
if List.exists
(fn (_,_,CFG.EDGE{k,...}) => k = CFG.EXIT)
exit_edges
then
let val CFG.BLOCK{annotations,...} = #node_info cfg X
in case #get DDG.LIVENESS (!annotations) of
SOME{liveOut, ...} => liveOut
| NONE => error "missing live out"
end
else
SL.uniq(foldr (fn ((_,Y,_),S) =>
let val CFG.BLOCK{annotations,...} = #node_info cfg Y
in case #get DDG.LIVENESS (!annotations) of
SOME{liveIn, ...} => revAppend(liveIn,S)
| NONE => S
end) [] exit_edges)
val liveOutNode as (i,_) =
case !insns of
[] => createLiveOutNode(liveOut)
| jmp::_ =>
case InsnProps.instrKind jmp of
InsnProps.IK_JUMP =>
(* add a control dependence edge to the liveIn *)
let val jmpNode as (j,_) = List.last ops
in addCtrlDepEdge(#1 liveInNode, j);
jmpNode
end
| _ => createLiveOutNode(liveOut)
fun addUse i r =
if isZero r then ()
else HA.update(uses,r,i::HA.sub(uses,r))
fun addLiveOut j r =
app (fn (i,DDG.EDGE{l,r,...}) =>
newEdge(i,j,DDG.EDGE{l=l,r=r,d=DDG.LIVEOUT}))
(HA.sub(defs,r))
in app (addLiveOut i) liveOut;
addLiveOutCtrlDep i;
app (addUse i) liveOut
end
)
(* Add control dependences edges from all the instructions
* to the live-out node
*)
and addLiveOutCtrlDep(j) =
app (fn node as (i,_) =>
if i = j then () else addCtrlDepEdge(i,j)
) ops
val _ = scanBlock{ops=ops, liveIn=liveInNode,
defTbl=defs, useTbl=uses};
in addLiveOut b;
HA.update(defUseTbl, b, {defTbl=defs, useTbl=uses})
end
(* Build the entire dag *)
fun buildDag() =
let val allNodes = #nodes cfg () (* must be in topological order! *)
in app processBlock allNodes
end
in buildDag();
globalInfo :=
SOME{blockMap=blockMap, liveInMap=liveInMap, liveOutMap=liveOutMap};
DDG
end
end
|