[MLton] Converting recursive functions to SSA
Matthew Fluet
fluet@cs.cornell.edu
Sun, 23 Jul 2006 11:14:11 -0400 (EDT)
> So, we're almost done (hopefully) with converting the CPS code back into SSA.
"back into SSA"? It's been my impression from your earlier e-mails that
you were converting from SXML into CPS; I'd think your job would be
easiest if you converted from CPS into SXML, although that assumes that
all of the environment analyses/optimizations that are being effectively
translated back into SXML.
If you are converting CPS into SSA, then you'll want to follow the
behavior of mlton/closure-convert/closure-convert.{sig,fun}.
It might help as well if you could point us at your code and/or a diff
patch.
> We just hit what we think is our last major stumbling block. How do you handle
> recursive functions when you produce the SSA code?
The semantics of the SSA IL is that all of the functions in an SSA IL
program are mutually recursive (i.e., an SSA IL program is a giant LetRec
with a set of global variables and a distinguished (nullary) main
function). IIRC, almost every SXML lambda becomes its own SSA function in
the initial conversion to SSA; subsequent inlining and contification
optimization passes rapidly get rid of the very small functions and
functions with determined control flow.
> The problem is, it seems like if we choose the wrong mechanism it
> could break a lot of the intelligence that is built into later stages of the
> compiler, bu producing code that is not in the style that the optimizations have
> been tuned for.
That is a valid concern, which is why it seems that converting from CPS
back into SXML would be the easiest way to avoid this problem. Otherwise,
I suggest you study closure-convert.{sig,fun} and supporting analyses to
see how we convert an SXML program to SSA.
> That's why we decided to ask and see how you handle compilation
> of recursive functions. For example, if I had the ML code:
>
> let fun fib (n, a, b) = if n = 0 then a else fib (n - 1, b, a + b)
> in fib (5, 0, 1)
> end
>
> How do I convert this to SSA?
Converting the "let" to a "local" and "fib (5, 0, 1)" to
"val n = fib (5, 0, 1)" and compiling with -keepPass closureConvert, I see
the following:
Datatypes:
...
lambdas_3 = Env_66 of (unit)
...
Globals:
...
tuple_25 = ()
fib_0 = Env_66 (tuple_25)
...
Main: main_0
Functions:
...
fun main_0 () = L_0 ()
...
L_341 (x_1024)
x_1026 = Env_100 (tuple_26)
Ref_assign (x_841, x_1026)
x_1025 = Env_98 (exit_0)
Ref_assign (x_844, x_1025)
case fib_0 of
Env_66 => L_342
L_342 (env_103)
fib_1 (env_103, x_837) NonTail {cont = L_343, handler = Handle L_6}
...
fun fib_1 (env_109, x_1037) = L_351 ()
L_351 ()
b_0 = #2 x_1037
a_0 = #1 x_1037
n_1 = #0 x_1037
x_1038 = (n_1, x_832)
case x_11 of
Env_2 => L_352
L_352 (env_110)
x_1039 (env_110, x_1038) NonTail {cont = L_353, handler = Caller}
L_353 (x_1040)
case x_1040 of
true => L_355 | false => L_354
L_354 ()
x_1041 = (n_1, x_833)
case x_72 of
Env_10 => L_356
L_356 (env_111)
x_1042 (env_111, x_1041) NonTail {cont = L_357, handler = Caller}
L_357 (x_1043)
x_1044 = (a_0, b_0)
case x_68 of
Env_9 => L_358
L_358 (env_112)
x_873 (env_112, x_1044) NonTail {cont = L_359, handler = Caller}
L_359 (x_1045)
x_1046 = (x_1043, b_0, x_1045)
case fib_0 of
Env_66 => L_360
L_360 (env_113)
fib_1 (env_113, x_1046) Tail
L_355 ()
return a_0
...
So, you can see that fib_1 may freely call itself.
> It's made even more difficult if the function
> being converted has free variables, and is mutually recursive with other
> functions who also have free variables.
I believe that in this case, the environment for each function in the
mutually recursive set is the union of the free variables in all functions
in the mutually recursive set. See
mlton/closure-convert/lambda-free.{sig,fun}.