[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.