Skip to content

Lifting of statically closed functions in Lambda_to_flambda#511

Closed
Keryan-dev wants to merge 1 commit intoocaml-flambda:flambda2.0-stablefrom
Keryan-dev:lift-closed-fun
Closed

Lifting of statically closed functions in Lambda_to_flambda#511
Keryan-dev wants to merge 1 commit intoocaml-flambda:flambda2.0-stablefrom
Keryan-dev:lift-closed-fun

Conversation

@Keryan-dev
Copy link
Copy Markdown

This converts sets of closures to top-level symbols when possible.

This can be improved further by removing the closure entirely, and referring recursive functions by their symbols directly in the code. It would require a more involved patch as the code of relevant functions would change, and symbols would need to be declared in topological order.

|> Closure_id.Lmap.mapi (fun closure_id _ ->
Symbol.create (Compilation_unit.get_current_exn ())
(Linkage_name.create
(Variable.unique_name (Closure_id.unwrap closure_id))))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably use the same code as Simplify_set_of_closures.simplify_and_lift_set_of_closures, which would be Linkage_name.create (Closure_id.to_string closure_id) (I think you can skip the extra Closure_id.rename here).

@lthls
Copy link
Copy Markdown

lthls commented Jun 30, 2021

We already discussed this, but here is the main issue with this PR:
Assume we start with let rec f x = f x in ....
This will be compiled to let_code f_code = fun x -> f_sym x in let_symbol f_sym = set_of_closures [f: f_code] in .... So f_code refers to f_sym, and f_sym to f_code.
In simplify this would be handled by making all of this into a mutually recursive definition, but this is annoying to do correctly here. What saves us though is that the symbols that we generate are fully static (both the closures and the code IDs), meaning that they don't need initialisation and can be considered as correctly initialised at any point in the program.
However the Flambda 2 terms lack this distinction, so here we end up generating terms that do not match the scoping rules.
I see two (three?) possible fixes:

  1. Compute strongly connected components when emitting the code IDs and symbols in Lambda_to_flambda
  2. Add a special kind of symbols, for those that are fully static. In practice this would probably re-purpose the Symbol_scoping_rule.Syntactic constructor, which (I think ?) is only used for fully-static symbols anyway.
  3. Ignore the issue, and assume that in some cases the symbol scopes will be wrong. In this particular case, putting the code IDs before the symbols mean that the symbol definitions will always refer to names in scope, while the code definitions will not. This was already the case anyway (as the code IDs were not topologically sorted), so this shouldn't break anything.

This PR implements solution 3. Apart from a small comment the code looks correct.

@Keryan-dev
Copy link
Copy Markdown
Author

Assume we start with let rec f x = f x in ....
This will be compiled to let_code f_code = fun x -> f_sym x in let_symbol f_sym = set_of_closures [f: f_code] in .... So f_code refers to f_sym, and f_sym to f_code.

Note that in this patch the code will still fetch recursive functions through its closure, there is no direct reference to set of closures symbols, I think, so what you describe should not happen (at least, no more than before, as it was the case in mlexamples/tests9.ml) and binding all sets of closures under the let_codes would be in order.

But yes, in fine we would remove Select_closures from the code, that's what I meant in my initial comment, albeit not clearly.
For that I was indeed thinking of working on your solution 1.

@lthls
Copy link
Copy Markdown

lthls commented Jun 30, 2021

I thought that adding a substitution to the symbol would automatically transform the recursive calls too. Is the substitution only used for the code outside the function ? I think it would be correct to also use it inside the function.

@Keryan-dev
Copy link
Copy Markdown
Author

The body of functions is processed before the symbols are added to the environment here. I'm not sure that adding them before would clear the Select_closures for free.

@mshinwell
Copy link
Copy Markdown

Being done in the Flambda backend repo.

@mshinwell mshinwell closed this Jan 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants