[MLton] cvs commit: fixed quadratic liveness for list constants

Stephen Weeks sweeks@mlton.org
Tue, 29 Jun 2004 22:27:24 -0700


sweeks      04/06/29 22:27:05

  Modified:    mlton/defunctorize defunctorize.fun
  Log:
  MAIL fixed quadratic liveness for list constants
  
  Fixed a performance problem that caused a quadratic amount of liveness
  information for list constants.  The problem is that list elements are
  evaluated left-to-right, but lists are constructed right-to-left.  So,
  for [e1, e2, ..., en], the code looks like
  
   	x1 = e1
          x2 = e2
          ...
          xn = en
          x1 :: (x2 :: ... :: (xn :: []))
  
  Note that at each ei, all of the previous xi are live.  Hence, if each
  ei is a complex expression that cause the creation of a new basic
  block, there will be a quadratic amount of liveness information.
  
  The fix is to build the list in reverse as we go, and then reverse it
  at the end.
  
  	l0 = []
  	l1 = e1 :: l0
  	l2 = e2 :: l1
  	...
  	ln = en :: l(n-1)
  	rev ln
  
  With this approach, there is a constant number of live variables at
  each block.
  
  For now, I've hardwired in a constant, 20, so that lists larger than
  that use the reverse trick, and smaller lists are evaluated directly.
  
  This fix didn't help with the HOL performance problem, which is due to
  the large number of blocks in main.

Revision  Changes    Path
1.18      +109 -21   mlton/mlton/defunctorize/defunctorize.fun

Index: defunctorize.fun
===================================================================
RCS file: /cvsroot/mlton/mlton/mlton/defunctorize/defunctorize.fun,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- defunctorize.fun	1 May 2004 00:49:41 -0000	1.17
+++ defunctorize.fun	30 Jun 2004 05:27:02 -0000	1.18
@@ -322,6 +322,114 @@
 				    tyvars = tyvars,
 				    var = x}]}
 
+structure Xexp =
+   struct
+      open Xexp
+	 
+      val list: Xexp.t vector * Xtype.t -> Xexp.t =
+	 fn (es, ty) =>
+	 let
+	    val targs = #2 (valOf (Xtype.deConOpt ty))
+	    val eltTy = Vector.sub (targs, 0)
+	    val nill: Xexp.t =
+	       Xexp.conApp {arg = NONE,
+			    con = Con.nill,
+			    targs = targs,
+			    ty = ty}
+	    val consArgTy = Xtype.tuple (Vector.new2 (eltTy, ty))
+	    val cons: Xexp.t * Xexp.t -> Xexp.t =
+	       fn (e1, e2) =>
+	       Xexp.conApp
+	       {arg = SOME (Xexp.tuple {exps = Vector.new2 (e1, e2),
+					ty = consArgTy}),
+		con = Con.cons,
+		targs = targs,
+		ty = ty}
+	 in
+	    if Vector.length es < 20
+	       then Vector.foldr (es, nill, cons)
+	    else
+	       let
+		  val revArgTy = Xtype.tuple (Vector.new2 (ty, ty))
+		  val revTy = Xtype.arrow (revArgTy, ty)
+		  val revVar = Var.newString "rev"
+		  fun rev (e1, e2) =
+		     Xexp.app
+		     {func = Xexp.monoVar (revVar, revTy),
+		      arg = Xexp.tuple {exps = Vector.new2 (e1, e2),
+					ty = revArgTy},
+		      ty = ty}
+		  fun detuple2 (tuple: Xexp.t,
+				f: XvarExp.t * XvarExp.t -> Xexp.t): Xexp.t =
+		     Xexp.detuple {body = fn xs => let
+						      fun x i = #1 (Vector.sub (xs, i))
+						   in
+						      f (x 0, x 1)
+						   end,
+						tuple = tuple}
+		  val revArg = Var.newNoname ()
+		  val revLambda =
+		     Xlambda.make
+		     {arg = revArg,
+		      argType = revArgTy,
+		      body =
+		      Xexp.toExp
+		      (detuple2
+		       (Xexp.monoVar (revArg, revArgTy), fn (l, ac) =>
+			let
+			   val ac = Xexp.varExp (ac, ty)
+			   val consArg = Var.newNoname ()
+			in
+			   Xexp.casee
+			   {cases =
+			    Xcases.Con
+			    (Vector.new2
+			     ((Xpat.T {arg = NONE,
+				       con = Con.nill,
+				       targs = targs},
+			       ac),
+			      (Xpat.T {arg = SOME (consArg, consArgTy),
+				       con = Con.cons,
+				       targs = targs},
+			       detuple2
+			       (Xexp.monoVar (consArg, consArgTy),
+				fn (x, l) =>
+				rev (Xexp.varExp (l, ty),
+				     cons (Xexp.varExp (x, eltTy),
+					   ac)))))),
+			    default = NONE,
+			    test = Xexp.varExp (l, ty),
+			    ty = ty}
+			end))}
+		  val revDec =
+		     Xdec.Fun
+		     {decs = Vector.new1 {lambda = revLambda,
+					  ty = revTy,
+					  var = revVar},
+		      tyvars = Vector.new0 ()}
+		  val l = Var.newNoname ()
+		  val (l, body) =
+		     Vector.foldr
+		     (es, (l, Xexp.lett {decs = [revDec],
+					 body = rev (Xexp.monoVar (l, ty),
+						     nill)}),
+		      fn (e, (l, body)) =>
+		      let
+			 val l' = Var.newNoname ()
+		      in
+			 (l',
+			  Xexp.let1 {body = body,
+				     exp = cons (e, Xexp.monoVar (l', ty)),
+				     var = l})
+		      end)
+	       in
+		  Xexp.let1 {body = body,
+			     exp = nill,
+			     var = l}
+	       end
+	 end
+   end
+
 fun defunctorize (CoreML.Program.T {decs}) =
    let
       val {get = conExtraArgs: Con.t -> Xtype.t vector option,
@@ -782,27 +890,7 @@
 				   ty = ty}
 		| Lambda l => Xexp.lambda (loopLambda l)
 		| Let (ds, e) => loopDecs (ds, loopExp e)
-		| List es =>
-		     let
-			val targs = #2 (valOf (Xtype.deConOpt ty))
-			val eltTy = Vector.sub (targs, 0)
-		     in
-			Vector.foldr
-			(es,
-			 Xexp.conApp {arg = NONE,
-				      con = Con.nill,
-				      targs = targs,
-				      ty = ty},
-			 fn (e, l) =>
-			 Xexp.conApp
-			 {arg = (SOME
-				 (Xexp.tuple
-				  {exps = Vector.new2 (#1 (loopExp e), l),
-				   ty = Xtype.tuple (Vector.new2 (eltTy, ty))})),
-			  con = Con.cons,
-			  targs = targs,
-			  ty = ty})
-		     end
+		| List es => Xexp.list (Vector.map (es, #1 o loopExp), ty)
 		| PrimApp {args, prim, targs} =>
 		     let
 			val args = Vector.map (args, #1 o loopExp)