225 |
|
|
226 |
val loop = cexp cfg ifs |
val loop = cexp cfg ifs |
227 |
|
|
228 |
fun used lv = C.usenb lv > 0 |
fun used lv = (C.usenb(C.get lv) > 0) |
229 |
|
handle x => |
230 |
|
(say("while in FContract.used "^(C.LVarString lv)^"\n"); |
231 |
|
raise x) |
232 |
|
|
233 |
fun impurePO po = true (* if a PrimOP is pure or not *) |
fun impurePO po = true (* if a PrimOP is pure or not *) |
234 |
|
|
253 |
| Val v => v |
| Val v => v |
254 |
|
|
255 |
fun val2sval m (F.VAR ov) = |
fun val2sval m (F.VAR ov) = |
256 |
((lookup m ov) handle x => (PP.printSval(F.VAR ov); raise x)) |
((lookup m ov) handle x => ((* PP.printSval(F.VAR ov); *) raise x)) |
257 |
| val2sval m v = Val v |
| val2sval m v = Val v |
258 |
|
|
259 |
fun bugsv (msg,sv) = bugval(msg, sval2val sv) |
fun bugsv (msg,sv) = bugval(msg, sval2val sv) |
265 |
of F.VAR lv => lv |
of F.VAR lv => lv |
266 |
| v => bugval ("unexpected val", v) |
| v => bugval ("unexpected val", v) |
267 |
|
|
268 |
fun unuseval f (F.VAR lv) = ((C.unuse f false lv) handle x => raise x) |
fun unuseval f (F.VAR lv) = ignore((C.unuse f false lv) handle x => raise x) |
269 |
| unuseval f _ = () |
| unuseval f _ = () |
270 |
|
|
271 |
(* called when a variable becomes dead. |
(* called when a variable becomes dead. |
273 |
fun undertake m lv = |
fun undertake m lv = |
274 |
let val undertake = undertake m |
let val undertake = undertake m |
275 |
in case lookup m lv |
in case lookup m lv |
276 |
of Var {1=nlv,...} => ASSERT(nlv = lv, "nlv = lv") |
of Var {1=nlv,...} => () |
277 |
| Val v => () |
| Val v => () |
278 |
| Fun (lv,le,args,_,_) => |
| Fun (lv,le,args,_,_) => |
279 |
(#2 (C.unuselexp undertake)) (lv, map #1 args, le) |
(#2 (C.unuselexp undertake)) (lv, map #1 args, le) |
284 |
| Decon _ => () |
| Decon _ => () |
285 |
end |
end |
286 |
handle M.IntmapF => |
handle M.IntmapF => |
287 |
(say "\nUnable to undertake "; PP.printSval(F.VAR lv)) |
(say("Unable to undertake "^(C.LVarString lv)^"\n")) |
288 |
| x => |
| x => |
289 |
(say "\nwhile undertaking "; PP.printSval(F.VAR lv); raise x) |
(say("while undertaking "^(C.LVarString lv)^"\n"); raise x) |
290 |
|
|
291 |
fun addbind (m,lv,sv) = M.add(m, lv, sv) |
fun addbind (m,lv,sv) = M.add(m, lv, sv) |
292 |
|
|
295 |
(case sval2val sv of F.VAR lv2 => C.transfer(lv1,lv2) | v2 => (); |
(case sval2val sv of F.VAR lv2 => C.transfer(lv1,lv2) | v2 => (); |
296 |
unuseval (undertake m) v; |
unuseval (undertake m) v; |
297 |
addbind(m, lv1, sv)) handle x => |
addbind(m, lv1, sv)) handle x => |
298 |
(say ("\nwhile substituting "^ |
(say ("while substituting "^ |
299 |
(C.LVarString lv1)^ |
(C.LVarString lv1)^ |
300 |
" -> "); |
" -> "); |
301 |
PP.printSval (sval2val sv); |
PP.printSval (sval2val sv); |
328 |
of Fun(g,body,args,{inline,...},od) => |
of Fun(g,body,args,{inline,...},od) => |
329 |
(ASSERT(used g, "used "^(C.LVarString g)); |
(ASSERT(used g, "used "^(C.LVarString g)); |
330 |
if d <> od then (NONE, ifs) |
if d <> od then (NONE, ifs) |
331 |
else if C.usenb g = 1 andalso not(S.member ifs g) then |
else if ((C.usenb(C.get g))handle x => raise x) = 1 andalso not(S.member ifs g) then |
332 |
|
|
333 |
(* simple inlining: we should copy the body and then |
(* simple inlining: we should copy the body and then |
334 |
* kill the function, but instead we just move the body |
* kill the function, but instead we just move the body |
399 |
| known (F.RET[_]) = true |
| known (F.RET[_]) = true |
400 |
| known _ = false |
| known _ = false |
401 |
fun cassoc (lv,v,body,wrap) = |
fun cassoc (lv,v,body,wrap) = |
402 |
if lv = v andalso C.usenb lv = 1 andalso |
if lv = v andalso ((C.usenb(C.get lv)) handle x=> raise x) = 1 andalso |
403 |
known le1 andalso known le2 then |
known le1 andalso known le2 then |
404 |
(* here I should also check that le1 != le2 *) |
(* here I should also check that le1 != le2 *) |
405 |
let val nle1 = F.LET([lv], le1, body) |
let val nle1 = F.LET([lv], le1, body) |
446 |
* changed (read: bigger), so we have to reset the |
* changed (read: bigger), so we have to reset the |
447 |
* `inline' bit *) |
* `inline' bit *) |
448 |
val nfk = {isrec=isrec, cconv=cconv, |
val nfk = {isrec=isrec, cconv=cconv, |
449 |
known=known orelse not(C.escaping f), |
known=known orelse not(C.escaping(C.get f))handle x => raise x, |
450 |
inline=if !inlineWitness |
inline=if !inlineWitness |
451 |
then F.IH_SAFE |
then F.IH_SAFE |
452 |
else (inline before |
else (inline before |
464 |
else cfun(m, fs, acc) |
else cfun(m, fs, acc) |
465 |
|
|
466 |
(* check for eta redex *) |
(* check for eta redex *) |
467 |
fun ceta ((fk,f,args,F.APP(g,vs)):F.fundec,(m,hs)) = |
fun ceta (fdec as (fk,f,args,F.APP(g,vs)):F.fundec,(m,fs,hs)) = |
468 |
if vs = (map (F.VAR o #1) args) andalso |
if vs = (map (F.VAR o #1) args) andalso |
469 |
(* don't forget to check that g is not one of the args |
(* don't forget to check that g is not one of the args |
470 |
* and not f itself either *) |
* and not f itself either *) |
478 |
* escaping one. It's dangerous for optimisations based |
* escaping one. It's dangerous for optimisations based |
479 |
* on known functions (elimination of dead args, f.ex) |
* on known functions (elimination of dead args, f.ex) |
480 |
* and could generate cases where call>use in collect *) |
* and could generate cases where call>use in collect *) |
481 |
in if not (C.escaping f andalso not (C.escaping g)) |
in if not (((C.escaping(C.get f))handle x => raise x) andalso not (C.escaping(C.get g))handle x => raise x) |
482 |
then let |
then let |
483 |
(* if an earlier function h has been eta-reduced |
(* if an earlier function h has been eta-reduced |
484 |
* to f, we have to be careful to update its |
* to f, we have to be careful to update its |
493 |
* unuse in substitute assumes the val is escaping *) |
* unuse in substitute assumes the val is escaping *) |
494 |
C.transfer(f, g); |
C.transfer(f, g); |
495 |
C.unuse (undertake m) true g; |
C.unuse (undertake m) true g; |
496 |
(addbind(m, f, svg), f::hs) |
(addbind(m, f, svg), fs, f::hs) |
497 |
end |
end |
498 |
(* the default case could ensure the inline *) |
(* the default case could ensure the inline *) |
499 |
else (m, hs) |
else (m, fdec::fs, hs) |
500 |
end |
end |
501 |
else (m, hs) |
else (m, fdec::fs, hs) |
502 |
| ceta (_,(m,hs)) = (m, hs) |
| ceta (fdec,(m,fs,hs)) = (m,fdec::fs,hs) |
503 |
|
|
504 |
(* drop constant arguments if possible *) |
(* drop constant arguments if possible *) |
505 |
fun cstargs (f as ({inline=F.IH_ALWAYS,...},_,_,_):F.fundec) = f |
fun cstargs (f as ({inline=F.IH_ALWAYS,...},_,_,_):F.fundec) = f |
506 |
| cstargs (f as (fk,g,args,body):F.fundec) = |
| cstargs (f as (fk,g,args,body):F.fundec) = |
507 |
let val cst = |
let val actuals = (C.actuals (C.get g)) handle x => raise x |
508 |
|
val cst = |
509 |
ListPair.map |
ListPair.map |
510 |
(fn (NONE,_) => false |
(fn (NONE,_) => false |
511 |
| (SOME(F.VAR lv),(v,_)) => |
| (SOME v,(a,_)) => |
512 |
((lookup m lv; |
((case substval v |
513 |
if used v andalso used lv then |
of F.VAR lv => |
514 |
(C.use NONE lv; true) |
if used a andalso used lv then |
515 |
else false) |
(C.use NONE (C.get lv); true) |
516 |
handle M.IntmapF => false) |
else false |
517 |
| _ => true) |
| _ => false) |
518 |
(C.actuals g, args) |
handle M.IntmapF => false)) |
519 |
|
(actuals, args) |
520 |
(* if all args are used, there's nothing we can do *) |
(* if all args are used, there's nothing we can do *) |
521 |
in if List.all not cst then f else |
in if List.all not cst then f else |
522 |
let fun newarg lv = |
let fun newarg lv = |
530 |
(* construct the new body *) |
(* construct the new body *) |
531 |
val nbody = |
val nbody = |
532 |
F.LET(map #1 (filter args), |
F.LET(map #1 (filter args), |
533 |
F.RET(map O.valOf (filter (C.actuals g))), |
F.RET(map O.valOf (filter actuals)), |
534 |
body) |
body) |
535 |
in (fk, g, nargs, nbody) |
in (fk, g, nargs, nbody) |
536 |
end |
end |
548 |
val appargs = (map F.VAR nargs') |
val appargs = (map F.VAR nargs') |
549 |
val nf = (nfk, g, nargs, F.APP(F.VAR ng, appargs)) |
val nf = (nfk, g, nargs, F.APP(F.VAR ng, appargs)) |
550 |
val nf' = (nfk', ng, args', body) |
val nf' = (nfk', ng, args', body) |
551 |
|
|
552 |
|
val ngi = C.new (SOME(map #1 args')) ng |
553 |
|
val nargsi = map ((C.new NONE) o #1) nargs |
554 |
in |
in |
555 |
C.new (SOME(map #1 args')) ng; |
C.use (SOME appargs) ngi; |
556 |
C.use (SOME appargs) ng; |
app (C.use NONE) nargsi; |
|
app ((C.new NONE) o #1) nargs; |
|
|
app (C.use NONE) nargs'; |
|
557 |
nf'::nf::fs |
nf'::nf::fs |
558 |
end |
end |
559 |
val used = map (used o #1) args |
val used = map (used o #1) args |
563 |
dropargs (fn xs => OU.filter(used, xs)) |
dropargs (fn xs => OU.filter(used, xs)) |
564 |
|
|
565 |
(* eta-split: add a wrapper for escaping uses *) |
(* eta-split: add a wrapper for escaping uses *) |
566 |
else if C.escaping g andalso C.called g then |
else |
567 |
|
let val gi = C.get g |
568 |
|
in if ((C.escaping gi)handle x => raise x) andalso ((C.called gi)handle x => raise x) then |
569 |
(* like dropargs but keeping all args *) |
(* like dropargs but keeping all args *) |
570 |
dropargs OU.id |
dropargs OU.id |
571 |
|
|
572 |
else f::fs |
else f::fs |
573 |
end |
end |
574 |
|
end |
575 |
|
|
576 |
|
(* junk unused funs *) |
577 |
|
val fs = List.filter (used o #2) fs |
578 |
|
|
579 |
(* redirect cst args to their source value *) |
(* redirect cst args to their source value *) |
580 |
val fs = map cstargs fs |
val fs = map cstargs fs |
587 |
addbind(m, f, Fun(f, body, args, fk, od))) |
addbind(m, f, Fun(f, body, args, fk, od))) |
588 |
m fs |
m fs |
589 |
(* check for eta redexes *) |
(* check for eta redexes *) |
590 |
val (nm,_) = foldl ceta (nm,[]) fs |
val (nm,fs,_) = foldl ceta (nm,[],[]) fs |
591 |
|
|
592 |
(* move the inlinable functions to the end of the list *) |
(* move the inlinable functions to the end of the list *) |
593 |
val (f1s,f2s) = |
val (f1s,f2s) = |
605 |
case fs |
case fs |
606 |
of [] => nle |
of [] => nle |
607 |
| [f1 as ({isrec=NONE,...},_,_,_),f2] => |
| [f1 as ({isrec=NONE,...},_,_,_),f2] => |
608 |
(* gross hack: dropargs might have added a second |
(* gross hack: `wrap' might have added a second |
609 |
* non-recursive function. we need to split them into |
* non-recursive function. we need to split them into |
610 |
* 2 FIXes. This is _very_ ad-hoc *) |
* 2 FIXes. This is _very_ ad-hoc *) |
611 |
F.FIX([f2], F.FIX([f1], nle)) |
F.FIX([f2], F.FIX([f1], nle)) |
620 |
end |
end |
621 |
|
|
622 |
| F.TFN ((f,args,body),le) => |
| F.TFN ((f,args,body),le) => |
623 |
|
if used f then |
624 |
let val nbody = cexp (DI.next d, DI.next od) ifs m body #2 |
let val nbody = cexp (DI.next d, DI.next od) ifs m body #2 |
625 |
val nm = addbind(m, f, TFun(f, nbody, args, od)) |
val nm = addbind(m, f, TFun(f, nbody, args, od)) |
626 |
val nle = loop nm le cont |
val nle = loop nm le cont |
627 |
in |
in |
628 |
if used f then F.TFN((f, args, nbody), nle) else nle |
if used f then F.TFN((f, args, nbody), nle) else nle |
629 |
end |
end |
630 |
|
else loop m le cont |
631 |
|
|
632 |
| F.TAPP(f,tycs) => |
| F.TAPP(f,tycs) => |
633 |
cont(m, F.TAPP((substval f) handle x => raise x, tycs)) |
cont(m, F.TAPP((substval f) handle x => raise x, tycs)) |
721 |
bugval("unexpected switch arg", sval2val sv)) |
bugval("unexpected switch arg", sval2val sv)) |
722 |
|
|
723 |
| F.CON (dc1,tycs1,v,lv,le) => |
| F.CON (dc1,tycs1,v,lv,le) => |
724 |
|
if used lv then |
725 |
let val ndc = cdcon dc1 |
let val ndc = cdcon dc1 |
726 |
fun ccon sv = |
fun ccon sv = |
727 |
let val nv = sval2val sv |
let val nv = sval2val sv |
738 |
else ccon sv |
else ccon sv |
739 |
| sv => ccon sv |
| sv => ccon sv |
740 |
end |
end |
741 |
|
else loop m le cont |
742 |
|
|
743 |
| F.RECORD (rk,vs,lv,le) => |
| F.RECORD (rk,vs,lv,le) => |
744 |
(* g: check whether the record already exists *) |
(* g: check whether the record already exists *) |
745 |
|
if used lv then |
746 |
let fun g (n,Select(_,v1,i)::ss) = |
let fun g (n,Select(_,v1,i)::ss) = |
747 |
if n = i then |
if n = i then |
748 |
(case ss |
(case ss |
776 |
in if used lv then F.RECORD(rk, nvs, lv, nle) else nle |
in if used lv then F.RECORD(rk, nvs, lv, nle) else nle |
777 |
end |
end |
778 |
end |
end |
779 |
|
else loop m le cont |
780 |
|
|
781 |
| F.SELECT (v,i,lv,le) => |
| F.SELECT (v,i,lv,le) => |
782 |
|
if used lv then |
783 |
(case ((val2sval m v) handle x => raise x) |
(case ((val2sval m v) handle x => raise x) |
784 |
of Record (lvr,vs) => |
of Record (lvr,vs) => |
785 |
let val sv = (val2sval m (List.nth(vs, i))) handle x => raise x |
let val sv = (val2sval m (List.nth(vs, i))) handle x => raise x |
791 |
val nle = loop nm le cont |
val nle = loop nm le cont |
792 |
in if used lv then F.SELECT(nv, i, lv, nle) else nle |
in if used lv then F.SELECT(nv, i, lv, nle) else nle |
793 |
end) |
end) |
794 |
|
else loop m le cont |
795 |
|
|
796 |
| F.RAISE (v,ltys) => |
| F.RAISE (v,ltys) => |
797 |
cont(m, F.RAISE((substval v) handle x => raise x, ltys)) |
cont(m, F.RAISE((substval v) handle x => raise x, ltys)) |
809 |
|
|
810 |
| F.PRIMOP (po,vs,lv,le) => |
| F.PRIMOP (po,vs,lv,le) => |
811 |
let val impure = impurePO po |
let val impure = impurePO po |
812 |
val nvs = ((map substval vs) handle x => raise x) |
in if impure orelse used lv then |
813 |
|
let val nvs = ((map substval vs) handle x => raise x) |
814 |
val npo = cpo po |
val npo = cpo po |
815 |
val nm = addbind(m, lv, Var(lv,NONE)) |
val nm = addbind(m, lv, Var(lv,NONE)) |
816 |
val nle = loop nm le cont |
val nle = loop nm le cont |
819 |
then F.PRIMOP(npo, nvs, lv, nle) |
then F.PRIMOP(npo, nvs, lv, nle) |
820 |
else nle |
else nle |
821 |
end |
end |
822 |
|
else loop m le cont |
823 |
|
end |
824 |
end |
end |
825 |
|
|
826 |
in |
in |