conts, handlers, and liveness
Stephen Weeks
MLton@sourcelight.com
Thu, 19 Jul 2001 12:26:32 -0700
> x_3673 doesn't appear in any live list. What happens is something like
> the following:
>
> fun L_1 () = L_3(global_1)
> fun L_2 () = L_3(x_1)
> fun L_3 (x_2) = let
> val _ = HandlerPop
> in
> ...
> end
> fun L_4 () = let
> val x_3 = Int_add (x_7, x_8)
> val x_4 = Int_eq (x_3, 0)
> in
> Switch(x_3, (0, L_1), (1, L_2))
> end
> (presumably somewhere else is a nontail call with L_3 as the handler)
...
> I think I see what's going on. At CPS, you don't have near handlers and
> far handlers -- just handlers. But, in MachineIL you have far handlers
> (i.e., the code pointer you put on the stack) which adjust the stack top
> on a return, moves the raise global to the near handler actual, and then
> jumps to the near handler, and also near handlers which is where raise to
> jumps jump and do the actual handle code. And it's the raise-to-jumps
> that are getting the short end -- they can't tell that the exception
> argument that they are raising won't get used and can't do the appropriate
> dead code elimination.
A simple CPS optimization could introduce near/far handlers in cases where the
handler argument is unused, and rewrite the above as follows.
fun L_1 () = L_3(global_1)
fun L_2 () = L_3(x_1)
fun L_3' () = let
val _ = HandlerPop
in
...
end
fun L_3 (x_2) = L_3'()
fun L_4 () = let
val x_3 = Int_add (x_7, x_8)
val x_4 = Int_eq (x_3, 0)
in
Switch(x_3, (0, L_1), (1, L_2))
end
I think the shrinker will then do the right thing.
It probably makes sense to do this as part of raise-to-jump. Any interest? The
CVS tree is there for the taking. :-)