|
|
1.1 root 1: (* Copyright 1989 by AT&T Bell Laboratories *)
2: signature SPILL =
3: sig val spill : (CPS.function * bool) list * (CPS.lvar -> bool)
4: * (int * int * CPS.cexp -> CPS.cexp) ->
5: (CPS.function * bool) list
6: end
7:
8: functor Spill(val maxfree : int) : SPILL =
9: struct
10: open FreeMap Access SortedList CPS
11: val error = ErrorMsg.impossible
12: fun sublist test =
13: let fun subl(a::r) = if test a then a::(subl r) else subl r
14: | subl [] = []
15: in subl
16: end
17:
18: local val spillname = Symbol.symbol "spillrec"
19: in fun spillLvar() = namedLvar spillname
20: end
21:
22: val ilist = PrintUtil.printClosedSequence ("[",",","]") Integer.print
23:
24: fun cut(0,_) = []
25: | cut(i,a::x) = a::cut(i-1,x)
26: | cut(_,[]) = []
27:
28: fun nextuse x =
29: let fun xin[] = false | xin(y::r) = x=y orelse xin r
30: fun g(level,a) =
31: let val rec f =
32: fn ([],[]) => level
33: | ([],next) => g(level+1,next)
34: | (SWITCH(v,l)::r,next) => if x=v then level else f(r,l@next)
35: | (RECORD(l,w,c)::r,next) =>
36: if xin(map #1 l) then level else f(r,c::next)
37: | (SELECT(i,v,w,c)::r,next) => if x=v then level else f(r,c::next)
38: | (OFFSET(i,v,w,c)::r,next) => if x=v then level else f(r,c::next)
39: | (PRIMOP(i,a,w,cl)::r,next) => if xin a then level else f(r,cl@next)
40: | (APP(v,vl)::r,next) => if xin(v::vl) then level else f(r,next)
41: in f(a,[])
42: end
43: fun h y = g(0,[y])
44: in h
45: end
46:
47: local val sort = Sort.sort (fn ((i:int,_),(j,_)) => i>j)
48: in fun sortdups(cexp,dups) =
49: map #2 (sort (map (fn dup as (v,w) => (nextuse v cexp, dup)) dups))
50: end
51:
52: (* should do the first n and then only go
53: deep enough to prove that it is not needed *)
54:
55: fun next_n_dups(0,cexp,dups) = []
56: | next_n_dups(n,cexp,dups) =
57: if n >= length dups
58: then dups
59: else cut(n,sortdups(cexp,dups))
60:
61: fun show (SWITCH(v,l)) = (print "SWITCH "; print v; print "\n")
62: | show (RECORD(_,w,_)) = (print "RECORD "; print w; print "\n")
63: | show (SELECT(_,_,w,_)) = (print "SELECT "; print w; print "\n")
64: | show (OFFSET(_,_,w,_)) = (print "OFFSET "; print w; print "\n")
65: | show (PRIMOP(_,_,w::_,_)) = (print "PRIMOP "; print w; print "\n")
66: | show (PRIMOP(_,vl,_,_)) = (print "PRIMOP "; ilist vl; print "\n")
67: | show (APP(f,vl)) = (print "APP "; print f; ilist vl; print "\n")
68:
69: nonfix before
70: val \/ = merge and /\ = intersect
71: infix 6 \/ infix 7 /\
72: fun mash (constant,freevars,spillmem) =
73: let fun f(results : lvar list,
74: uniques : lvar list,
75: dups : (lvar*lvar) list,
76: spill : (lvar list * lvar) option,
77: cexp : cexp) =
78: let fun prepare l = sublist (fn x => not(constant x)) (uniq l)
79: val (before,after) = (* variables free in this operation, and after
80: not including the newly-bound variables *)
81: let val rec free =
82: fn SWITCH(v,l) => foldmerge(prepare[v] :: map free l)
83: | RECORD(l,w,c) => prepare (map #1 l) \/ freevars w
84: | SELECT(i,v,w,c) => prepare[v] \/ freevars w
85: | OFFSET(i,v,w,c) => prepare[v] \/ freevars w
86: | PRIMOP(i,a,[],cl) => foldmerge(prepare a :: map free cl)
87: | PRIMOP(i,a,[res],cl) => prepare a \/ freevars res
88: | APP(f,vl) => prepare(f::vl)
89: fun here(vl,wl) = (prepare vl, wl)
90: in case cexp
91: of SWITCH(v,l) => here([v],foldmerge(map free l))
92: | RECORD(l,w,c) => here(map #1 l,freevars w)
93: | SELECT(i,v,w,c) => here([v],freevars w)
94: | OFFSET(i,v,w,c) => here([v],freevars w)
95: | PRIMOP(i,a,[],cl) => here(a,foldmerge(map free cl))
96: | PRIMOP(i,a,[res],cl) => here(a,freevars res)
97: | APP(f,vl) => here(f::vl,[])
98: end
99:
100: val uniques = uniques \/ results
101: val uniques_after = uniques /\ after
102: val uniques_before = (uniques /\ before) \/ uniques_after
103: val spill_after =
104: case spill of
105: NONE => NONE
106: | SOME(contents,_) =>
107: case uniq contents /\ after of
108: [] => NONE
109: | _ => spill
110: val maxfree' = case spill of NONE => maxfree | SOME _ => maxfree-1
111: val maxfreeafter = case spill_after of
112: NONE => maxfree | SOME _ => maxfree-1
113: val avail = maxfree' - length(uniques_before \/ results)
114: val dups = next_n_dups(avail,cexp,dups)
115:
116: fun getpath p v =
117: if constant v orelse member uniques_before v
118: then (v, OFFp 0)
119: else let fun try((w,x)::l) = if v=w then (x,OFFp 0) else try l
120: | try [] = let val SOME (l,sv) = spill
121: fun find(i,w::l) =
122: if v=w
123: then ((* if p
124: then (print "Retching ";
125: print v;
126: print "\n")
127: else (); *)
128: (sv,SELp(i,OFFp 0)))
129: else find(i+1,l)
130: | find(_,[]) = error "not found in spill"
131: in find(0,l)
132: end
133: in try dups
134: end
135:
136: fun makeSpillRec args =
137: let val contents = prepare args \/ after
138: val spillrec = map (getpath true) contents
139: val sv = spillLvar()
140: val dups' = map (fn x => (x,x)) uniques_before @ dups
141: in (* ilist contents; print "\n"; *)
142: RECORD(spillrec,sv,f([],[],dups',SOME(contents,sv),cexp))
143: end
144:
145: fun g(args,res,conts,gen) =
146: if length(prepare args \/ uniques_after) > maxfreeafter orelse
147: length res + length uniques_after > maxfreeafter
148: then makeSpillRec args
149: else let val paths = map (fn x => (x, getpath false x)) (uniq args)
150: fun fetchit (_,(_,OFFp 0)) = false | fetchit _ = true
151: in case sublist fetchit paths of
152: [(v,(w,SELp(i,OFFp 0)))] =>
153: let val x = dupLvar v
154: in (* print "Fetching ";
155: print v;
156: print "\n"; *)
157: SELECT(i,w,x,f([],uniques_before,(v,x)::dups,
158: spill_after,cexp))
159: end
160: | (v,(w,SELp(i,OFFp 0)))::_ =>
161: let val x = dupLvar v
162: in (* print "fetching ";
163: print v;
164: print "\n"; *)
165: SELECT(i,w,x,f([],uniques_before,(v,x)::dups,spill,cexp))
166: end
167: | [] => let fun f' cexp = f(uniq res,uniques_after,
168: dups,spill_after,cexp)
169: in gen(map (#1 o (getpath false)) args,res,map f' conts)
170: end
171: end
172:
173: in case ((*show cexp;*) cexp)
174: of SWITCH(v,l) => g([v],[],l,fn([v],[],l)=>SWITCH(v,l))
175: | RECORD(l,w,c) =>
176: if 1+length uniques_after > maxfreeafter
177: then makeSpillRec (map #1 l)
178: else let val paths = map (fn (v,p) =>
179: let val (v',p') = getpath true v
180: in (v', combinepaths(p',p))
181: end)
182: l
183: in RECORD(paths,w,f([w],uniques_after,dups,spill_after,c))
184: end
185: | SELECT(i,v,w,c) => g([v],[w],[c], fn([v],[w],[c])=>SELECT(i,v,w,c))
186: | OFFSET(i,v,w,c) => g([v],[w],[c], fn([v],[w],[c])=>OFFSET(i,v,w,c))
187: | PRIMOP(i,a,r,cl) => g(a,r,cl, fn(a,r,cl)=>PRIMOP(i,a,r,cl))
188: | APP(f,vl) => g(f::vl,[],[],fn(f::vl,[],[])=>APP(f,vl))
189: end
190: in f
191: end
192:
193: fun spill(carg,constant,prof) =
194: let
195: exception SpillCall
196: val callmap = Intmap.new(64,SpillCall) : (lvar list * lvar list) Intmap.intmap
197: val callinfo = Intmap.map callmap
198: val note = Intmap.add callmap
199: val t = Intset.new()
200: val spillarg = Intset.add t
201: val spillmem = Intset.mem t
202:
203: fun spill_call(arg as ((f,vl,body),k)) =
204: if length vl < maxfree
205: then (arg,uniq vl,[],NONE)
206: else let val dups = map (fn x => (x,x)) vl
207: val dups' = next_n_dups(maxfree-2,body,dups)
208: val sv = spillLvar()
209: val new = map #1 dups'
210: val new_vl = sv :: new
211: val spill = SOME(vl,sv)
212: in note(f,(new,vl));
213: (((f,new_vl,body),k),[],dups',spill)
214: end
215:
216: val rec fixApp =
217: fn e as APP(f,vl) =>
218: (let val (new,old) = callinfo f
219: val sv = spillLvar()
220: val sr = map (fn x => (x,OFFp 0)) vl
221: fun find [] = []
222: | find(x::r) =
223: let fun loop(a::b,c::d) =
224: if x=a then c :: find r else loop(b,d)
225: | loop _ = error "fixApp in spill"
226: in loop(old,vl)
227: end
228: in spillarg sv;
229: RECORD(sr,sv,APP(f,sv :: find new))
230: end handle SpillCall => e)
231: | SWITCH(v,l) => SWITCH(v,map fixApp l)
232: | RECORD(l,w,c) => RECORD(l,w,fixApp c)
233: | SELECT(i,v,w,c) => SELECT(i,v,w,fixApp c)
234: | OFFSET(i,v,w,c) => OFFSET(i,v,w,fixApp c)
235: | PRIMOP(i,a,w,l) => PRIMOP(i,a,w,map fixApp l)
236: val carg' = map spill_call carg
237: val carg'' = map (fn (((f,vl,b),k),uniq,dups,spill) =>
238: (((f,vl,fixApp b),k),uniq,dups,spill)) carg'
239: val freevars =
240: let exception SpillFreemap
241: val m = Intmap.new(32, SpillFreemap) : lvar list Intmap.intmap
242: val _ = app (freemap constant (Intmap.add m) o #3 o #1 o #1) carg''
243: in Intmap.map m
244: end
245: exception TooMany
246: fun checkv w = if length(freevars w) >= maxfree then raise TooMany else ()
247: val rec check =
248: fn FIX _ => error "FIX in cps/spill"
249: | APP(l,args) => ()
250: | SWITCH(v,l) => app check l
251: | RECORD(l,w,c) => (checkv w; check c)
252: | SELECT(i,v,w,c) => (checkv w; check c)
253: | OFFSET(i,v,w,c) => (checkv w; check c)
254: | PRIMOP(i,args,[],l) => app check l
255: | PRIMOP(i,args,w::_, l) => (checkv w; app check l)
256: val masher = mash(constant,freevars,spillmem)
257:
258: in map
259: (fn (((f,vl,body),k),uniq,dups,spill as SOME _) =>
260: ((f,vl,masher([],uniq,dups,spill,body)), k)
261: | (arg as ((f,vl,body),k),uniq,dups,NONE) =>
262: ((check body; arg)
263: handle TooMany => ((f,vl,masher([],uniq,dups,NONE,body)), k)))
264: carg''
265: end
266:
267: end (* structure Spill *)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.