File:  [Research Unix] / researchv10no / cmd / sml / src / cps / cpsopt.sml
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

(* Copyright 1989 by AT&T Bell Laboratories *)
(* All record paths must be "OFFp 0" in cpsopt.sml *)

functor CPSopt(val maxfree : int) :
	sig val reduce : (CPS.const Intmap.intmap) -> CPS.cexp -> CPS.cexp
        end =
struct

 open Access CPS SortedList

 fun map1 f (a,b) = (f a, b)

 fun member(i : int, a::b) = i=a orelse member(i,b)
   | member(i,[]) = false

 fun choose(a::b,true::d) = a::choose(b,d)
   | choose(a::b,false::d) = choose(b,d)
   | choose _ = []

 fun sum f = let fun h [] = 0 
		   | h (a::r) = f a + h r
	     in h
	     end

 val debug = false
 fun debugprint s = if debug then print(s:string) else ()
 fun debugflush() = if debug then flush_out std_out else ()

fun reduce ctab cexp =
let
 val clicked = ref 0
 fun click (s:string) = (debugprint s; inc clicked)

 fun eta cexp =
  let exception M2
      val m : lvar Intmap.intmap = Intmap.new(32, M2)
      val name = Intmap.map m
      fun rename v = rename(name v) handle M2 => v
      fun newname x = (Access.sameName x; Intmap.add m x)
      val rec eta = 
	fn RECORD(vl,w,e) => RECORD(map (map1 rename) vl, w, eta e)
	 | SELECT(i,v,w,e) => SELECT(i, v, w, eta e)
	 | APP(f,vl) => APP(rename f, map rename vl)
	 | SWITCH(v,el) => SWITCH(v, map eta el)
	 | PRIMOP(i,vl,wl,el) => PRIMOP(i, map rename vl, wl, map eta el)
	 | FIX(l,e) =>
	     let fun h((f,vl,body as APP(g,wl))::r) =
		     if wl=vl andalso not (member(g, f::vl))
		     then (newname(f,rename g); h r)
		     else let val vl' = map dupLvar vl 
			      and f' = dupLvar f
		          in (f,vl',APP(f',vl'))::(f',vl,body) :: h r
			  end
		   | h((f,vl,body)::r) =
 		     let val vl' = map dupLvar vl 
			 and f' = dupLvar f
		     in (f,vl',APP(f',vl'))::(f',vl,body) :: h r
		     end
		   | h [] = []
	      in case h l of
		  [] => eta e
		| l' => FIX(map (fn(f,vl,e)=>(f,vl,eta e)) l', eta e)
	     end
  in eta cexp
  end

 val hoist = Hoist.hoist click
fun contract last cexp =
 let val mkconst = Intmap.add ctab
     datatype cv = CO of const | VA of lvar
     fun ctable v = CO(Intmap.map ctab v) handle Ctable => VA v
     fun isconst v = case ctable v of CO _ => true | VA _ => false
     datatype arity = BOT | COUNT of int | TOP | NOTUSED
     val botlist = map (fn _ => BOT)
     datatype info = FNinfo of {arity: arity list ref,
			        args: lvar list,
			        body : cexp,
				reduce_ok : bool ref}
		   | RECinfo of (lvar * accesspath) list * (lvar * int) list ref
		   | MISCinfo

     exception Escapemap
     val m : {info: info, used : int ref, escape : int ref} Intmap.intmap =
		     Intmap.new(128, Escapemap)
     val get = Intmap.map m
     val enter = Intmap.add m
     fun use v = inc(#used(get v)) handle Escapemap => ()
     fun used v = !(#used(get v)) > 0 handle Escapemap => true
     fun escape v = let val {escape,used,...} = get v
		    in inc escape; inc used
		    end handle Escapemap => ()
     fun escapes r = !(#escape(get r)) handle Escapemap => 0
     fun flatfun(f,n) =
	 (case get f of
	    {info=FNinfo{arity=ref al,reduce_ok=ref false,...},escape=ref 0,...} =>
	    (case nth(al,n) of
               COUNT i => 1
	     | _ => 0)
	  | _ => 0) handle Escapemap => 0
     fun selectonly r = 0 = !(#escape(get r)) handle Escapemap => false
     fun enterREC(w,vl) = enter(w,{info=RECinfo(vl,ref[]),escape=ref 0,used=ref 0})
     fun enterMISC w = enter(w,{info=MISCinfo, escape=ref 0, used = ref 0})
     fun enterFN (f,vl,cexp) =
		(enter(f,{escape=ref 0,used=ref 0,
		 	 info=FNinfo{arity=ref(botlist vl), args=vl, body=cexp,
			 reduce_ok=ref true}});
		 app enterMISC vl)

     fun checkreduce(f,vl,body) =
	 case get f of
	   {escape=ref 0,used=ref i,
	    info=FNinfo{reduce_ok,arity as ref al,...},...} =>
		if i>1
		then
		  let fun loop(v::vl,a::al) =
			  if used v
			  then if selectonly v
			       then a::loop(vl,al)
			       else TOP::loop(vl,al)
			  else NOTUSED::loop(vl,al)
		        | loop _ = []
		  in reduce_ok := false;
		     arity := loop(vl,al)
		  end
		else ()
	      | {info=FNinfo{reduce_ok,...},...} =>
		    (reduce_ok := false;
		     if last
		     then ()
		     else (case body of
		             APP(g,_) =>
			     (case get g of
				{info=FNinfo{reduce_ok,...},...} => 
				reduce_ok := false
			      | _ => ())
			   | _ => ()))

     exception ConstFold

     val rec pass1 = 
      fn RECORD(vl,w,e) => (enterREC(w,vl); app (escape o #1) vl; pass1 e)
       | SELECT (i,v,w,e) => (enterMISC w; use v; pass1 e)
       | APP(f,vl) =>
	 ((case get f of
	     {info=FNinfo{arity as ref al,...},...} =>
	     let fun loop(TOP::r,v::vl,n) = TOP::loop(r,vl,n+1)
		   | loop(BOT::r,v::vl,n) =
		     ((case get v of
		         {info=RECinfo(wl,flr as ref fl), ...} =>
			 (flr := (f,n)::fl; COUNT(length wl)::loop(r,vl,n+1))
		       | _ => raise Escapemap)
		      handle Escapemap => TOP::loop(r,vl,n+1))
		   | loop((cnt as COUNT a)::r,v::vl,n) = 
		     ((case get v of
		         {info=RECinfo(wl,flr as ref fl), ...} =>
			 if a = length wl
			 then (flr := (f,n)::fl; cnt::loop(r,vl,n+1))
			 else TOP::loop(r,vl,n+1)
		       | _ => raise Escapemap)
		      handle Escapemap => TOP::loop(r,vl,n+1))
		   | loop _ = []
	     in arity := loop(al,vl,0)
	     end
	   | _ => ())
	  handle Escapemap => ();
	  use f; app escape vl)
       | FIX(l, e) => (app enterFN l;
		       app (fn(* (f,vl,APP(g,wl)) => (use g; app escape wl)
			     |*) (f,vl,body) => pass1 body) l;
		       pass1 e;
		       app checkreduce l)
       | SWITCH(v,el) => (use v; app pass1 el)
       | PRIMOP(i,vl,wl,el) =>
	 (case i of
	    P.:= => app escape vl
	  | P.makeref => app escape vl
	  | P.sethdlr => app escape vl
	  | P.store => app escape vl
	  | P.unboxedassign => app escape vl
	  | P.unboxedupdate => app escape vl
	  | P.update => app escape vl
	  | _ => app use vl;
	  app enterMISC wl;
	  app pass1 el)
       | OFFSET _ => ErrorMsg.impossible "OFFSET in cpsopt"

     exception Beta
     val m2 : lvar Intmap.intmap = Intmap.new(32, Beta)
     fun ren v = ren(Intmap.map m2 v) handle Beta => v
     fun newname x = (Access.sameName x; Intmap.add m2 x)
     fun newnames(v::vl, w::wl) = (newname(v,w); newnames(vl,wl))
       | newnames _ = ()
     val one = let val x = mkLvar() in mkconst(x, INTconst 1); x end
     
     val rec reduce = fn cexp => g NONE cexp
     and g = fn hdlr =>
     let val rec g' =
       fn RECORD (vl,w,e) =>
	  let val {info=RECinfo(_,ref fl),escape=ref esc,...} = get w
	  in if esc = sum flatfun fl
	     then (click "rec "; g' e)
	     else RECORD(map (map1 ren) vl, w, g' e)
	  end
        | SELECT(i,v,w,e) =>
	  if not(used w)
          then (click "Sel "; g' e)
	  else let val v' = ren v
	       in (case get v' of
		     {info=RECinfo(vl,_),...} =>
		     let val (x,OFFp 0) = nth(vl,i)
		     in click "sel ";
			newname(w,ren x);
			g' e
		     end
	           | _ => raise Escapemap)
	          handle Escapemap => SELECT(i,v',w,g' e)
	       end
	| OFFSET _ => ErrorMsg.impossible "OFFSET in cpsopt"
	| APP(f,vl) =>
	  ((case get(ren f) of
	       {info=FNinfo{args,body,reduce_ok=ref true,...},...} =>
		(newnames(args, map ren vl); g' body)
             | {info=FNinfo{arity=ref al,...},escape=ref 0,...} =>
	       let fun loop(COUNT _ :: r,v::vl) =
		       let val {info=RECinfo(wl,_),...} = get(ren v)
		           val wl' = map (fn (x,OFFp 0) => ren x) wl
		       in wl' @ loop(r,vl)
		       end
		     | loop(NOTUSED::r,v::vl) = loop(r,vl)
		     | loop(_::r,v::vl) = (ren v)::loop(r,vl)
		     | loop _ = []
	       in APP(ren f,loop(al,vl))
	       end
	     | _ => raise Escapemap)
	   handle Escapemap => APP(ren f, map ren vl))
	| FIX(l,e) =>
	  let fun h((f,vl,body)::r) = 
		 (case get f
		  of {info=FNinfo{reduce_ok=ref true,...},...} =>
		     (click "fn  "; h r)
		   | {info=FNinfo{arity=ref al,...},escape=ref 0,...} =>
	       	          let fun vars 0 = []
				| vars i = mkLvar()::vars(i-1)
			      fun newargs(COUNT j :: r,v::vl) =
				  let val new = vars j
				  in enterREC(v, map (fn x =>(x,OFFp 0)) new);
				     click "flt ";
				     new @ newargs(r,vl)
				  end
				| newargs(NOTUSED::r,v::vl) =
				     (click "drp "; newargs(r,vl))
				| newargs(TOP::r,v::vl) = v::newargs(r,vl)
				| newargs _ = []
			  in (f, newargs(al,vl), reduce body) :: h r
			  end
		   | _ => (f, vl, reduce body) :: h r)
		| h [] = []
	   in case h l of [] => g' e | l' => FIX(l', g' e)
	  end
        | SWITCH(v,el) => 
		(case ctable (ren v)
		  of CO(INTconst i) => (click "swt "; g' (nth(el,i)))
		   | VA v' => SWITCH(v', map g' el)
		   | _ => ErrorMsg.impossible "3121 in cpsopt")
	| PRIMOP(P.gethdlr,vl,wl as [w],[e]) =>
	  (case hdlr of
	     NONE => if used w then PRIMOP(P.gethdlr,vl,wl,[g (SOME w) e])
		     else (click "gth "; g' e)
	   | SOME w' => (click "gth "; newname(w,w'); g' e))
	| PRIMOP(P.sethdlr,[v],wl,[e]) =>
	  let val v' = ren v
	      val e' = g (SOME v') e
	  in case hdlr of
	       NONE => PRIMOP(P.sethdlr,[v'],wl,[e'])
	     | SOME v'' => if v'=v'' then (click "sth "; e')
			   else PRIMOP(P.sethdlr,[v'],wl,[e'])
	  end
	| PRIMOP(i, vl, wl, el as [e1,e2]) => 
	      if e1 = e2
	      then (click "tst "; g' e1)
	      else let val vl' = map ren vl
	           in g' (primops(i,map ctable vl', wl, el))
	              handle ConstFold => PRIMOP(i, vl', wl, map g' el)
	           end
        | PRIMOP(i, vl, wl as [w], el as [e]) =>
	  if not(used w) andalso Prim.pure i
	    then (click "prm "; g' e)
	    else let val vl' = map ren vl
	          in g' (primops(i,map ctable vl', wl, el))
	             handle ConstFold => PRIMOP(i, vl', wl, map g' el)
	         end
        | PRIMOP(i,vl,wl,el) =>
		 let val vl' = map ren vl
	          in g' (primops(i,map ctable vl', wl, el))
	             handle ConstFold => PRIMOP(i, vl', wl, map g' el)
	         end
      in g'
     end

     and primops =
	fn (P.boxed, CO(INTconst _)::_,_,_::b::_) => (click "A"; b)
	 | (P.boxed, CO(STRINGconst s)::_,_,a::b::_) =>
			    (click "A"; if size s = 1 then b else a)
	 | (P.boxed, VA v :: _,_,a::_) => 
            ((case get v of
		  {info=RECinfo _, ...} => (click "A"; a)
	      | _ => raise ConstFold)
	     handle Escapemap => raise ConstFold)
         | (P.<, [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
	              (click "B"; if Integer.<(i,j) then a else b)
         | (P.<=, [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
		   (click "C"; if Integer.<=(i,j) then a else b)
	 | (P.> , [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
	           (click "D"; if Integer.>(i,j) then a else b)
         | (P.>=, [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
	           (click "E"; if Integer.>=(i,j) then a else b)
         | (P.ieql, [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
		     (click "F"; if i=j then a else b)
         | (P.ineq, [CO(INTconst i),CO(INTconst j)],_,[a,b]) =>
		     (click "G"; if i=j then b else a)
         | (P.*, [CO(INTconst 1), VA(v)],[w],[c]) =>
		      (click "H"; newname(w,v); c)
	 | (P.*, [VA(v), CO(INTconst 1)],[w],[c]) =>
		      (click "H"; newname(w,v); c)
	 | (P.*, [CO(INTconst 0), _],[w],[c]) =>
		   (click "H"; mkconst(w,INTconst 0); c)
	 | (P.*, [_, CO(INTconst 0)],[w],[c]) =>
		      (click "H"; mkconst(w,INTconst 0); c)
	 | (P.*, [CO(INTconst i),CO(INTconst j)], [w], [c]) =>
		   (let val x = i*j
		    in x+x; mkconst(w,INTconst x); click "H"; c
		    end handle Overflow => raise ConstFold)
	 | (P.div, [VA(v), CO(INTconst 1)],[w],[c]) =>
		      (click "I"; newname(w,v); c)
	 | (P.div, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
		   (let val x = i div j
		    in click "I"; mkconst(w,INTconst x); c
		    end handle Div => raise ConstFold)
         | (P.+, [CO(INTconst 0), VA(v)],[w],[c]) =>
		   (click "J"; newname(w,v); c)
	 | (P.+, [VA(v), CO(INTconst 0)],[w],[c]) =>
		   (click "J"; newname(w,v); c)
	 | (P.+, [CO(INTconst i),CO(INTconst j)], [w], [c]) =>
		   (let val x = i+j
		    in x+x; mkconst(w,INTconst x); click "J"; c
		    end handle Overflow => raise ConstFold)
         | (P.-, [VA(v), CO(INTconst 0)],[w],[c]) =>
		      (click "K";newname(w,v); c)
	 | (P.-, [CO(INTconst i),CO(INTconst j)], [w], [c]) =>
		  (let val x = i-j
		   in x+x; mkconst(w,INTconst x); click "K"; c
		   end handle Overflow => raise ConstFold)
	 | (P.rshift, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
			   (click "L"; mkconst(w,INTconst(Bits.rshift(i,j))); c)
	 | (P.rshift, [CO(INTconst 0), VA v],[w],[c]) =>
			   (click "L"; mkconst(w,INTconst 0); c)
	 | (P.rshift, [VA v, CO(INTconst 0)],[w],[c]) =>
			   (click "L"; newname(w,v); c)
         | (P.slength, [CO(INTconst _)],[w],[c]) =>
			 (click "M"; mkconst(w, INTconst 1); c)
	 | (P.slength, [CO(STRINGconst s)], [w],[c]) =>
			 (click "M"; mkconst(w, INTconst(size s)); c)
         | (P.ordof, [CO(STRINGconst s), CO(INTconst i)],[w],[c]) =>
			 (click "N"; mkconst(w, INTconst (ordof(s,i))); c)
         | (P.~, [CO(INTconst i)], [w], [c]) =>
		     (let val x = ~i
		      in x+x; mkconst(w,INTconst x); click "O"; c
		      end handle Overflow => raise ConstFold)
	 | (P.lshift, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
			   (let val x = Bits.lshift(i,j)
			    in x+x; mkconst(w,INTconst x); click "P"; c
			    end handle Overflow => raise ConstFold)
	 | (P.lshift, [CO(INTconst 0), VA v],[w],[c]) =>
			   (click "P"; mkconst(w,INTconst 0); c)
	 | (P.lshift, [VA v, CO(INTconst 0)],[w],[c]) =>
			   (click "P"; newname(w,v); c)
	 | (P.orb, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
			(click "Q"; mkconst(w,INTconst(Bits.orb(i,j))); c)
	 | (P.orb, [CO(INTconst 0),VA v],[w],[c]) =>
			(click "Q"; newname(w,v); c)
	 | (P.orb, [VA v, CO(INTconst 0)],[w],[c]) =>
			(click "Q"; newname(w,v); c)
	 | (P.xorb, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
			 (click "R"; mkconst(w,INTconst(Bits.xorb(i,j))); c)
	 | (P.xorb, [CO(INTconst 0),VA v],[w],[c]) =>
			(click "R"; newname(w,v); c)
	 | (P.xorb, [VA v, CO(INTconst 0)],[w],[c]) =>
			(click "R"; newname(w,v); c)
	 | (P.notb, [CO(INTconst i)], [w], [c]) =>
			 (mkconst(w,INTconst(Bits.notb i)); click "S"; c)
	 | (P.andb, [CO(INTconst i),CO(INTconst j)],[w],[c]) =>
			 (click "T"; mkconst(w,INTconst(Bits.andb(i,j))); c)
	 | (P.andb, [CO(INTconst 0),VA v],[w],[c]) =>
			(click "T"; mkconst(w,INTconst 0); c)
	 | (P.andb, [VA v, CO(INTconst 0)],[w],[c]) =>
			(click "T"; mkconst(w,INTconst 0); c)
         | _ => raise ConstFold

    val _ = (debugprint "\nContract: "; debugflush())
  in (pass1 cexp; reduce cexp)
  end

fun expand(cexp,bodysize) =
   let
     datatype info = Fun of {escape: int ref, call: int ref, size: int ref,
		         args: lvar list, body: cexp}
	           | Arg of {escape: int ref, savings: int ref,
		             record: (int * lvar) list ref}
	           | Sel of {savings: int ref}
		   | Rec of {escape: int ref, size: int,
			     vars: (lvar * accesspath) list}

     exception Expand
     val m : info Intmap.intmap = Intmap.new(128,Expand)
     val get = Intmap.map m
     fun call(v,args) = (case get v
	            of Fun{call,...} => inc call
		     | Arg{savings,...} => savings := !savings+1
		     | Sel{savings} => savings := !savings+1
		     | Rec _ => ()  (* impossible *)
	 	  ) handle Expand => ()
     fun escape v = (case get v
	            of Fun{escape,...} => inc escape
		     | Arg{escape,...} => inc escape
		     | Sel _ => ()
		     | Rec{escape,...} => inc escape
		  ) handle Expand => ()
     fun escapeargs v = (case get v
	                 of Fun{escape,...} => inc escape
		       | Arg{escape,savings, ...} =>
			     (inc escape; savings := !savings + 1)
		       | Sel{savings} => savings := !savings + 1
		       | Rec{escape,...} => inc escape)
			 handle Expand => ()
     fun unescapeargs v = (case get v
	                 of Fun{escape,...} => dec escape
		       | Arg{escape,savings, ...} =>
			     (dec escape; savings := !savings - 1)
		       | Sel{savings} => savings := !savings - 1
		       | Rec{escape,...} => dec escape)
			 handle Expand => ()
     fun setsize(f,n) = case get f of Fun{size,...} => (size := n; n)
     fun enter (f,vl,e) = (Intmap.add m(f,Fun{escape=ref 0, call=ref 0, size=ref 0,
					      args=vl, body=e});
			   app (fn v => Intmap.add m (v,
					Arg{escape=ref 0,savings=ref 0,
					    record=ref []})) vl)
     fun noterec(w, vl, size) = Intmap.add m (w,Rec{size=size,escape=ref 0,vars=vl})
     fun notesel(i,v,w) = (Intmap.add m (w, Sel{savings=ref 0});
		     (case get v of
                        Arg{savings,record,...} => (inc savings;
						    record := (i,w)::(!record))
                      | _ => ()) handle Expand => ())
     fun save(v,k) = (case get v
		       of Arg{savings,...} => savings := !savings + k
		        | Sel{savings} => savings := !savings + k
		        | _ => ()
		     ) handle Expand => ()
     fun nsave(v,k) = (case get v
		       of Arg{savings,...} => savings := k
		        | Sel{savings} => savings := k
		        | _ => ()
		     ) handle Expand => ()
     fun savesofar v = (case get v 
		       of Arg{savings,...} => !savings
		        | Sel{savings} => !savings
		        | _ => 0
		     ) handle Expand => 0
     val rec prim = fn (_,vl,wl,el) =>
	 let fun vbl v = (Intmap.map ctab v; 0)
			  handle Ctable =>
			    ((case get v of
                                Rec _ => 0
			      | _ => 1) handle Expand => 1)
	     val nonconst = sum vbl vl
	     val len = length el
	     val sl = map savesofar vl
	     val branches = sum pass1 el
	     val zl = map savesofar vl
	     val overhead = length vl + length wl
	     val potential = overhead + (branches*(len-1)) div len
	     val savings = case nonconst of
		             1 => potential
			   | 2 => potential div 4
			   | _ => 0
	     fun app3 f = let fun loop (a::b,c::d,e::r) = (f(a,c,e); loop(b,d,r))
				| loop _ = ()
			  in loop
			  end
	 in app3(fn (v,s,z)=> nsave(v,s + savings + (z-s) div len)) (vl,sl,zl);
	    overhead+branches
	 end

     and pass1 = 
      fn RECORD(vl,w,e) =>
	  (app (escape o #1) vl;
	   noterec(w,vl,length vl);
	   2 + length vl + pass1 e)
       | SELECT (i,v,w,e) => (notesel(i,v,w); 1 + pass1 e)
       | APP(f,vl) => (call(f,length vl); app escapeargs vl; 1 + length vl)
       | FIX(l, e) => 
	    (app enter l; 
             sum (fn (f,_,e) => setsize(f, pass1 e)) l + length l + pass1 e)
       | SWITCH(v,el) => let val len = length el
			     val jumps = 4 + len
		             val branches = sum pass1 el
			  in save(v, (branches*(len-1)) div len + jumps);
			     jumps+branches
			 end
       | PRIMOP(args as (P.boxed,_,_,_)) => prim args
       | PRIMOP(args as (P.<,_,_,_)) => prim args
       | PRIMOP(args as (P.<=,_,_,_)) => prim args
       | PRIMOP(args as (P.>,_,_,_)) => prim args
       | PRIMOP(args as (P.>=,_,_,_)) => prim args
       | PRIMOP(args as (P.ieql,_,_,_)) => prim args
       | PRIMOP(args as (P.ineq,_,_,_)) => prim args
       | PRIMOP(args as (P.*,_,_,_)) => prim args
       | PRIMOP(args as (P.div,_,_,_)) => prim args
       | PRIMOP(args as (P.+,_,_,_)) => prim args
       | PRIMOP(args as (P.-,_,_,_)) => prim args
       | PRIMOP(args as (P.rshift,_,_,_)) => prim args
       | PRIMOP(args as (P.slength,_,_,_)) => prim args
       | PRIMOP(args as (P.ordof,_,_,_)) => prim args
       | PRIMOP(args as (P.~,_,_,_)) => prim args
       | PRIMOP(args as (P.lshift,_,_,_)) => prim args
       | PRIMOP(args as (P.orb,_,_,_)) => prim args
       | PRIMOP(args as (P.xorb,_,_,_)) => prim args
       | PRIMOP(args as (P.notb,_,_,_)) => prim args
       | PRIMOP(args as (P.andb,_,_,_)) => prim args
       | PRIMOP(_,vl,wl,el) =>
	 (app escape vl; length vl + length wl + sum pass1 el)

     fun substitute(args,wl,e) =
      let exception Alpha
          val vm : lvar Intmap.intmap = Intmap.new(16, Alpha)
          fun use v = Intmap.map vm v handle Alpha => v
          fun def v = let val w = dupLvar v 
		      in Intmap.add vm (v,w); w
		      end
	  fun bind(a::args,w::wl) = (Intmap.add vm (w,a); bind(args,wl))
	    | bind _ = ()
          val rec g =
         fn RECORD(vl,w,ce) => RECORD(map (map1 use) vl, def w, g ce)
          | SELECT(i,v,w,ce) => SELECT(i, use v, def w, g ce)
          | APP(v,vl) => APP(use v, map use vl)
          | FIX(l,ce) => 
	    let fun h1(f,vl,e) = (f,def f, vl, e)
		fun h2(f,f',vl,e) =
		    let val vl' = map def vl
			val e'= g e
		    in (f', vl', e')
		    end
	     in FIX(map h2(map h1 l), g ce)
	    end
          | SWITCH(v,l) => SWITCH(use v, map g l)
          | PRIMOP(i,vl,wl,ce) => PRIMOP(i, map use vl, map def wl, map g ce)
      val cexp = (bind(args,wl); g e)
      in debugprint(makestring(pass1 cexp)); debugprint " "; cexp
      end
		
     fun beta(n, d, e) = case e
      of RECORD(vl,w,ce) => RECORD(vl, w, beta(n,d+2+length vl, ce))
       | SELECT(i,v,w,ce) => SELECT(i, v, w, beta(n,d+1, ce))
       | APP(v,vl) => 
	   ((case get v
	     of Fun{escape,call as ref calls,size,args,body} =>
		let val size = !size
		    fun whatsave(acc, v::vl, a::al) =
			if acc>=size
			then acc
			else
			(case get a of
			   Arg{escape=ref esc,savings=ref save,record=ref rl} =>
                           let val (this,nvl,nal) =
			       if (Intmap.map ctab v; true) handle Ctable => false
			       then (save,vl,al)
			       else (case get v of
			               Fun{escape=ref 1,...} =>
                                         (if esc>0 then save else 6+save,vl,al)
				     | Fun _ => (save,vl,al)
				     | Rec{escape=ref ex,vars,size} =>
				       let fun loop([],nvl,nal) = 
					       (if ex>1 orelse esc>0
					        then save
						else save+size+2,nvl,nal)
					     | loop((i,w)::rl,nvl,nal) =
					       let val (v,OFFp 0) = nth(vars,i)
					       in loop(rl,v::nvl,w::nal)
					       end
				       in loop(rl,vl,al)
				       end
                                     | _ => (0,vl,al)) handle Expand => (0,vl,al)
			   in whatsave(acc + this - (acc*this) div size, nvl,nal)
			   end
			 | Sel{savings=ref save} =>
                           let val this =
			       if (Intmap.map ctab v; true) handle Ctable => false
			       then save
			       else (case get v of
				       Fun _ => save
				     | Rec _ => save
                                     | _ => 0) handle Expand => 0
			   in whatsave(acc + this - (acc*this) div size, vl,al)
			   end)
		      | whatsave(acc,_,_) = acc
		  val predicted = calls*((size-whatsave(0,vl,args))-(1+length vl))
                  val depth = 2
		  val max = 5
		  val increase = (bodysize*(depth - n)) div depth
	     in if (predicted <= increase
		    orelse (!escape=0 andalso
			    (calls = 1
		    orelse (case vl of
			      [_] => calls = 2 andalso
				     predicted - (size+1) <= increase
			    | _ => false))))
		    andalso (n <= max orelse (debugprint "n>";
			   		      debugprint(makestring max);
					      debugprint "\n"; false))
		then let val new = beta(n+1, d+1, substitute(vl,args,body))
		     in click "";
		        call := calls-1;
		        app unescapeargs vl;
		        new
		     end
		else e
	    end
	    | _ => e) handle Expand => e)
       | FIX(l,ce) => let fun h(f,vl,e) = 
			     case get f
			      of Fun{escape=ref 0,...} => (f,vl, beta(n,0,e))
			       | _ => (f,vl,e)
		       in FIX(if n<1 then map h l else l, 
			      beta(n,d+length l, ce))
		      end
       | SWITCH(v,l) => SWITCH(v, map (fn e => beta(n,d+2,e)) l)
       | PRIMOP(i,vl,wl,ce) => PRIMOP(i, vl, wl, map (fn e => beta(n,d+2,e)) ce)

    in debugprint("\nExpand ("); debugprint(makestring(pass1 cexp));
       debugprint("): "); debugflush();
       beta(0,0,cexp)
   end

  val bodysize = !System.Control.CG.bodysize
  val rounds = !System.Control.CG.rounds
  val reducemore = !System.Control.CG.reducemore

  fun contracter last cexp =
	 let val cexp = (clicked := 0; contract false cexp)
	  in if !clicked <= reducemore
	     then if last
		  then contract last cexp
		  else cexp
	     else contracter last cexp
	 end

  fun cycle(0,cexp) = contract true cexp
    | cycle(1,cexp) = 
	let val _ = debugprint "\nHoist: "
	    val cexp = hoist cexp
	    val _ = clicked := 0
	    val cexp = expand(cexp,bodysize div rounds)
	    val cl = !clicked before clicked := 0
        in if cl <= reducemore
	   then contract true cexp
	   else contracter true cexp
	end
    | cycle(k,cexp) = 
	let val _ = debugprint "\nHoist: "
	    val cexp = hoist cexp
	    val _ = clicked := 0
	    val cexp = expand(cexp,(bodysize * k) div rounds)
	    val cl = !clicked before clicked := 0
        in if cl <= reducemore
	   then contract true cexp
	   else cycle(k-1, contract false cexp)
	end
in cycle(rounds,contracter false (eta cexp))
   before (debugprint "\n"; debugflush())
end
end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.