-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathcolor.sml
456 lines (412 loc) · 15.1 KB
/
color.sml
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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
(* The book recommends associating each node with
a membership flag. WE defined it here, but leave it for future improvement *)
structure Color : COLOR =
struct
structure LI = Liveness.I
structure Frame = MipsFrame
(* move set *)
structure NS = BinarySetFn(
type ord_key = LI.node
fun compare(LI.NODE{temp=t1,...},LI.NODE{temp=t2,...})
= String.compare(Temp.makestring t1,Temp.makestring t2))
structure MS = BinarySetFn(
type ord_key = LI.node*LI.node
fun compare((LI.NODE{temp=t1,...},
LI.NODE{temp=t2,...}),
(LI.NODE{temp=t1',...},
LI.NODE{temp=t2',...})) =
case String.compare(Temp.makestring t1,Temp.makestring t1') of
EQUAL => String.compare(Temp.makestring t2,Temp.makestring t2')
| od => od)
(* register set *)
structure RS = ListSetFn(
type ord_key = Frame.register
fun compare (r1,r2) = String.compare(r1,r2))
structure WL = NS
structure TT = Temp.Table
structure T = Temp
type allocation = Frame.register TT.table
(* coloring function *)
fun color{interference = Liveness.IGRAPH{graph,moves},
initial=initAlloc, spillCost, registers} =
let
val simplifyWL : LI.node list ref = ref nil
val freezeWL : LI.node list ref = ref nil
val spillWL : LI.node list ref = ref nil
val coalescedMS = ref MS.empty
val constrainedMS = ref MS.empty
val frozenMS = ref MS.empty
val worklistMS = ref MS.empty
val activeMS = ref MS.empty
val spillNS = ref NS.empty
val coalescedNS = ref NS.empty
val coloredNS = ref NS.empty
val selectStack : LI.node list ref = ref nil
val colored : allocation ref = ref TT.empty
val moveList : MS.set TT.table ref = ref TT.empty
val precolored = ref NS.empty
val initial : LI.node list ref = ref nil
val alias : LI.node TT.table ref = ref TT.empty
fun println s = print (s ^ "\n")
fun remove l n = List.filter (fn (x) => x <> n) l
fun member l n = List.exists (fn x => x = n) l
fun nodename(LI.NODE{temp,...}) = Frame.temp_name temp
(* # of colors available *)
val K = List.length registers
(* get degree of a node *)
fun degree(LI.NODE{status,...}) =
case (!status) of
LI.INGRAPH(d) => d
| _ => ErrorMsg.impossible("calling degree on removed or colored")
(* precolorTable is a mapping from temp to register,
* while initial is a list of uncolored nodes *)
fun build () =
let
fun addMove(LI.NODE{temp,adj,status}, mv) =
let
val s =
case TT.look(!moveList,temp) of
NONE => MS.empty
| SOME ms => ms
in moveList := TT.enter(!moveList,temp,MS.add(s,mv))
end
in
(* initialize colored and precolored *)
app
(fn (n as LI.NODE{temp,adj,status}) =>
case TT.look (initAlloc,temp) of
SOME r =>
let in
colored := TT.enter(!colored,temp,r);
precolored := NS.add(!precolored,n)
end
| NONE =>
initial := n::(!initial)
)
(graph);
(* associate each node with a empty move set *)
app
(fn LI.NODE{temp,...} =>
moveList := TT.enter(!moveList,temp,MS.empty))
(graph);
(* iniitalize worklistMS and moveList *)
app
(fn (m as (src,dst)) =>
let in
if (not (NS.member(!precolored,src)))
then addMove(src, m) else ();
if (not (NS.member(!precolored,dst)))
then addMove(dst, m) else ();
worklistMS := MS.add(!worklistMS, m)
end)
moves
end
fun nodeMoves(LI.NODE{temp,adj,status}) =
case TT.look(!moveList,temp) of
SOME ms =>
MS.intersection(ms,MS.union(!activeMS,!worklistMS))
fun moveRelated n = not (MS.isEmpty (nodeMoves n))
(* Create initial worklist *)
fun makeWorklist () =
app
(fn (n as LI.NODE{temp,adj,status}) =>
case (!status) of
LI.INGRAPH(d) =>
if d >= K then
spillWL := n::(!spillWL)
else if moveRelated n then
freezeWL := n::(!freezeWL)
else
simplifyWL := n::(!simplifyWL)
| _ => ErrorMsg.impossible("error in makeWorklist"))
(!initial);
fun enableMoves(nodes: NS.set) =
let
fun enable1 n =
MS.app
(fn (m as (x,y)) =>
if MS.member(!activeMS,m) then
let in
activeMS := MS.delete(!activeMS,m);
worklistMS := MS.add(!worklistMS,m)
end
else ())
(nodeMoves n)
in
NS.app enable1 nodes
end
fun addWorklist (u as LI.NODE{temp,status,adj}) =
case (!status) of
LI.INGRAPH(d) =>
(if not (NS.member(!precolored,u)) andalso
(not (moveRelated u)) andalso (d < K)
then
let in
freezeWL := remove (!freezeWL) u;
simplifyWL := u::(!simplifyWL)
end
else ())
| _ => ErrorMsg.impossible("error in addWorklist")
fun getAlias (n as LI.NODE{temp,...}) =
if NS.member(!coalescedNS,n)
then getAlias(valOf(TT.look(!alias,temp)))
else n
(* adjacenent nodes *)
fun adjacent (n as LI.NODE{temp,adj,...}) =
NS.difference(NS.addList(NS.empty,(!adj)),
NS.union(NS.addList(NS.empty,!selectStack),
!coalescedNS))
(* decrement degree for graph node n, return
* modified degreeMap and a (possibly augmented) simplify worklist *)
fun decrementDegree(n as LI.NODE{temp,adj,status}) : unit =
(* only decrement those non-precolored nodes - for *)
(* precolored nodes, we treat as if they have infinite *)
(* degree, since we shouldn't reassign them to different registers *)
case (!status) of
LI.INGRAPH(d) =>
(let in
case TT.look(initAlloc,temp) of
SOME _ => ()
| NONE =>
let in
status := LI.INGRAPH(d-1);
if (d = K) then
let in
enableMoves(NS.union(NS.singleton(n),adjacent n));
spillWL := remove (!spillWL) n;
if moveRelated n then
freezeWL := n::(!freezeWL)
else
simplifyWL := n::(!simplifyWL)
end
else ()
end
end)
| _ => ErrorMsg.impossible("error in decrementDegree")
(* whether v is in adj of u.
* TODO: replace with more efficient adjSet *)
fun inAdj(LI.NODE{adj,...}, v) = member (!adj) v
fun OK(t,r) =
degree t < K orelse
NS.member(!precolored,t) orelse
inAdj(t,r)
fun conservative nodes =
let
val k = ref 0
in
NS.app
(fn (n) =>
if degree n >= K
then k := !k + 1
else ()
) nodes;
(!k < K)
end
(* add new edge to graph *)
fun addEdge(u as LI.NODE{temp=tu,adj=adju,status=stu},
v as LI.NODE{temp=tv,adj=adjv,status=stv}) =
case (!stu,!stv) of
(LI.INGRAPH(du),LI.INGRAPH(dv)) =>
if not (inAdj(u,v)) andalso u <> v then
let in
if (not (NS.member(!precolored,u))) then
(adju := v::(!adju); stu := LI.INGRAPH(du+1))
else ();
if (not (NS.member(!precolored,v))) then
(adjv := u::(!adjv); stv := LI.INGRAPH(dv+1))
else ()
end
else ()
| (_,_) => ErrorMsg.impossible("calling addEdge on removed or colored")
fun combine(u as LI.NODE{temp=tu,...},
v as LI.NODE{temp=tv,...}) =
let in
if member (!freezeWL) v then
freezeWL := remove (!freezeWL) v
else
spillWL := remove (!spillWL) v;
coalescedNS := NS.add(!coalescedNS,v);
alias := TT.enter(!alias,tv,u);
let
val mv_u = valOf(TT.look(!moveList,tu))
val mv_v = valOf(TT.look(!moveList,tv))
in
moveList := TT.enter(!moveList,tu,MS.union(mv_u,mv_v));
enableMoves(NS.singleton(v))
end;
NS.app (fn t => (addEdge(t,u); decrementDegree(t))) (adjacent v);
if degree u >= K andalso member (!freezeWL) u
then
let in
freezeWL := remove (!freezeWL) u;
spillWL := u::(!spillWL)
end
else ()
end
fun coalesce () =
let
val m as (x',y') = hd(MS.listItems(!worklistMS))
val x = getAlias(x')
val y = getAlias(y')
val (u,v) = if NS.member(!precolored,y) then (y,x) else (x,y)
val () = worklistMS := MS.delete(!worklistMS,m)
fun allOK (u,nodes) = not (NS.exists (fn t => not (OK(t,u))) nodes)
in
if u = v then
let in
coalescedMS := MS.add(!coalescedMS, m);
addWorklist(u)
end
else
if NS.member(!precolored,v) orelse inAdj(u,v)
then
let in
constrainedMS := MS.add(!constrainedMS, m);
addWorklist(u);
addWorklist(v)
end
else
if (NS.member(!precolored,u) andalso allOK(u,adjacent v))
orelse
((not (NS.member(!precolored,u))) andalso
conservative(NS.union(adjacent(u), adjacent(v))))
then
let in
coalescedMS := MS.add(!coalescedMS, m);
combine(u,v);
addWorklist(u)
end
else
activeMS := MS.add(!activeMS, m)
end
fun freezeMoves (u) =
let
fun freeze1 (m as (x as LI.NODE{temp=tx,...},y as LI.NODE{temp=ty,...})) =
let
val v = if getAlias(y) = getAlias(u)
then getAlias(x) else getAlias(y)
in
activeMS := MS.delete(!activeMS, m);
frozenMS := MS.add(!frozenMS, m);
if MS.isEmpty(nodeMoves(v)) andalso (degree v) < K
andalso not (NS.member(!precolored,v))
then
let in
freezeWL := remove (!freezeWL) v;
simplifyWL := v::(!simplifyWL)
end
else ()
end
in
MS.app freeze1 (nodeMoves u)
end
fun freeze () =
case (!freezeWL) of
u::us =>
let in
freezeWL := us;
simplifyWL := u::(!simplifyWL);
freezeMoves(u)
end
(* simplify the graph by keep removing the first node from simplify
* worklist and add to select stack. At same time, decrement degree
* for adjacent nodes of the removed node.
* precondition: simplifyWL not nil. *)
fun simplify () =
case (!simplifyWL) of
n::ns =>
let in
simplifyWL := ns;
selectStack := n::(!selectStack);
NS.app (fn r => decrementDegree r) (adjacent n)
end
fun selectSpill () =
let
fun f (min as LI.NODE{temp=t',...}) tlist =
case tlist of
nil => min
| (r as LI.NODE{temp=t,...})::rs =>
let val c1 = spillCost t'
val c2 = spillCost t in
if Real.>=(c1,c2)
then f r rs else f min rs
end
in
case (!spillWL) of
r::rs =>
let val (min as LI.NODE{temp,...}) = f r rs in
spillWL := remove (!spillWL) min;
simplifyWL := min::(!simplifyWL);
freezeMoves(min)
end
end
fun pickColor (regs: RS.set) : Frame.register
= List.hd(RS.listItems(regs))
(* assign color to all nodes on select stack. The parameter
* colored is all nodes that are already assigned a color. *)
fun assignColors () : allocation =
case (!selectStack) of
nil =>
let in
NS.app
(fn (n as LI.NODE{temp=tn,...}) =>
let
val LI.NODE{temp=t,...} = getAlias(n)
val c = valOf(TT.look(!colored,t))
in
colored := TT.enter(!colored,tn,c)
end)
(!coalescedNS);
!colored
end
| (n as LI.NODE{temp=tn,adj=adjn,...})::ns =>
let
val availableColors =
List.foldl
(fn (w as LI.NODE{temp=tw,...},cset) =>
let
val (w' as LI.NODE{temp=tw',...}) = getAlias(w)
in
if NS.member(NS.union(!coloredNS,!precolored),w')
then
case TT.look(!colored,tw') of
SOME c =>
let in
if RS.member(cset,c) then
RS.delete(cset,c)
else cset
end
else cset
end)
(RS.addList(RS.empty,registers)) (!adjn)
in
selectStack := ns;
if RS.isEmpty(availableColors) then
spillNS := NS.add(!spillNS, n)
else
let val r = pickColor(availableColors) in
coloredNS := NS.add(!coloredNS,n);
colored := TT.enter(!colored,tn,r)
end;
assignColors()
end
(* the main *loop* *)
fun iter () =
let in
if (not (List.null (!simplifyWL))) then (simplify(); iter())
else if (not (MS.isEmpty (!worklistMS))) then (coalesce(); iter())
else if (not (List.null (!freezeWL))) then (freeze(); iter())
else if (not (List.null (!spillWL))) then (selectSpill(); iter())
else ()
end
in
let
in
build();
makeWorklist();
iter();
(assignColors(),
map (fn (LI.NODE{temp,...}) => temp) (NS.listItems (!spillNS)))
end
end
end