[MLton] deepFlatten exception

Matthew Fluet fluet@cs.cornell.edu
Mon, 19 Jun 2006 23:50:20 -0400 (EDT)


> While compiling a program using the command
>
> mlton -verbose 3 -runtime 'ram-slop 0.4' t.mlb
>
> quite a bit of output is produced (see attached log file) with this at the 
> end:
>
>           deepFlatten starting
>           deepFlatten raised in 0.11 + 0.00 (0% GC)
>        ssa2Simplify raised in 0.35 + 0.00 (0% GC)
>     pre codegen raised in 28.94 + 5.17 (15% GC)
>  Compile SML raised in 28.94 + 5.17 (15% GC)
> MLton raised in 28.94 + 5.17 (15% GC)
> DeepFlatten.replaceVar x_0

The 'problem' seems pretty clear.  Going into the deepFlatten pass, Joe's 
program has:

     x_14472: (option_6 * option_1 * (word8) vector * Dog.sex_0 * option_6) = #4 x_14465
     x_14467: ((option_6 * option_1 * (word8) vector * Dog.sex_0 * option_6)
 	      * RandomSet.set_0
 	      * word32
 	      * RandomSet.set_0
 	      * word32) = (x_14472, x_14471, x_14470, x_14469, x_14468)
     x_14466: bool = MLton_eq (x_14467, x_14459)
     case x_14466 of
       true => L_7685 | false => L_7684

When analyzing the MLton_eq primitive, the deepFlatten pass uses:

       fun primApp {args, prim, resultVar = _, resultType} =
          let
             fun arg i = Vector.sub (args, i)
             fun result () = typeValue resultType
             datatype z = datatype Prim.Name.t
             fun dontFlatten () =
                (Vector.foreach (args, Value.dontFlatten)
                 ; result ())
             fun equal () =
                (Value.unify (arg 0, arg 1)
                 ; result ())
          in
             case Prim.name prim of
              (* ... *)
              | MLton_eq => equal ()
              | MLton_equal => equal ()
              (* ... *)
          end

So, this requires the arguments to MLton_eq to have the same flattening 
behavior: either they are both flattened or they are both not-flattened.

The diagnostics of the deepFlatten pass show that the arguments are 
determined to be flattenable:

x_14459 Object {args = (Object {args = (option_6
 					* option_1
 					* (word8) vector
 					* Dog.sex_0
 					* option_6),
 				con = Tuple,
 				flat = NotFlat}
 			* RandomSet.set_0
 			* word32
 			* RandomSet.set_0
 			* word32),
 		con = Tuple,
 		flat = Flat}
x_14467 Object {args = (Object {args = (option_6
 					* option_1
 					* (word8) vector
 					* Dog.sex_0
 					* option_6),
 				con = Tuple,
 				flat = NotFlat}
 			* RandomSet.set_0
 			* word32
 			* RandomSet.set_0
 			* word32),
 		con = Tuple,
 		flat = Flat}

But, the transformation pass can't handle Flat arguments to primitives.

First off, I note that if we change the analysis of primitives to:

       fun primApp {args, prim, resultVar = _, resultType} =
          let
             fun arg i = Vector.sub (args, i)
             fun result () = typeValue resultType
             datatype z = datatype Prim.Name.t
             fun dontFlatten () =
                (Vector.foreach (args, Value.dontFlatten)
                 ; result ())
             fun equal () =
                (Value.unify (arg 0, arg 1)
                 ; result ())
          in
             case Prim.name prim of
              (* ... *)
              | MLton_eq => dontFlatten ()
              | MLton_equal => dontFlatten ()
              (* ... *)
          end

then the program compiles without error; this effectively forces the 
arguments of MLton_eq to be NotFlat, which transforms without problem.

If we wanted to allow flattening of MLton_eq arguments, then we need to 
correctly handle the transformation.

Although MLton_equal shouldn't be around anymore, its semantics are 
clearer: polymorphic equality on tuples becomes the logical and of 
polymorphic equality on the tuple elements.

It's less clear to me what the semantics of MLton_eq ought to be in this 
case.  If the tuple were to remain unflattened, then the MLton_eq would 
ultimately be translated to pointer equality.

(Interestingly, and possibly a missed opportunity for optimization, in the 
test program, the pointer equality would necessarily evaluate to false, 
since one of the tuples is freshly allocated in the block.)

It may be that this implies that we can't flatten arguments to MLton_eq, 
since I don't see how to encode the right semantics.  Two tuples can have 
pairwise equal components, but not be pointer equal, so it doesn't appear 
that we can translate to the logical and of equality on the tuple 
elements.