Commit Graph

2 Commits

Author SHA1 Message Date
Zoltan Somogyi
9277d315d2 Test model_semi as well as model_det mutual tail recursion. 2017-08-31 22:16:58 +10:00
Zoltan Somogyi
d6c140af1f Allow inlining of linear mutual tail recursions.
Lets say an SCC contains n procedures, P1 through Pn. The SCC is *linearly
tail recursive* if the set of tail recursive calls in the SCC is {P1 -> P2,
P2 -> P3, ... Pn-1 -> Pn, Pn -> P1}, i.e. each procedure calls the next one
and the last one calls the first. For each Pi that is called from above
the SCC, the new optimization inlines the callee at every tail recursive
call site except the one that calls Pi itself. For example, if Pi is P1,
it would inline the tail call to P2, the tail call to P3 inside P2,
the tail call to P4 inside P3, and so on. Since the only tail recursive
call left in Pi is to Pi, this scheme transforms mutual tail recursion,
which the MLDS backend cannot (yet) implement, into self tail recursion,
which it *can* implement.

We only perform the transformation if each procedure in the SCC
contains *exactly one* tail recursive call. This is because each extra
tail recursive call may *double* the size of the resulting code.

Any recursive calls that are not *tail* recursive are left alone.

compiler/options.m:
doc/user_guide.texi:
    Add a new option, --inline-linear-tail-rec-sccs, that calls for the
    new transformation.

NEWS:
    Announce the new option.

compiler/mercury_compile_middle_passes.m:
    Call inlining if the new option is set.

compiler/inlining.m:
    If the new option is given, implement the transformation described
    at the top.

    Fix several variable and predicate names that misleadingly implied
    that a predicate *has* been inlined when it has only been decided
    that it is *worth* inlining, with the actual inlining taking place later.

    Pass the needed_map inside the inline_params.

    Rename the top predicate to fit the naming scheme used in the rest
    of the module.

compiler/hlds_goal.m:
    Add a goal feature that designates the call that it decorates as being
    either a self or a mutual tail recursive call.

    Rename the existing goal features that apply only to self tail recursive
    calls to make clear that fact.

compiler/mark_tail_calls.m:
    Generalize the code to look either for

    - just self tail recursive calls, as at the moment, as needed by both
      the LLDS and the MLDS code generator (for different purposes), or for
    - both self and mutual tail recursive calls, as needed by the new
      kind of inlining.

    Give the top level predicates names that indicate their overall purpose.

    Change the representation of the at_tail type to separate out the
    flag that says whether we have or haven't seen a recursive call
    in the backward traversal so far. This yields cleaner code
    in several places.

    Store the list of generated error_specs, and the flag that says whether
    the traversal has found any recursive call, in the mark_tail_calls_info
    structure, instead of returning them as separate output arguments.
    This is better, since *most* places don't add error_specs or set the flag.

compiler/dependency_graph.m:
    Explicitly gather the list of edges in the graph we are building,
    and record that list. Inlining now needs this, because it needs to know
    not just that e.g. two procedures p and q in an SCC call each other,
    also *from how many call sites". The dependency graph does not contain
    that information, but the list of edges from which it is built does.

compiler/hlds_dependency_graph.m:
    For most purposes, we want to add an edge from p to q if

    - p calls q in a tail call,
    - p calls q in a non-tail call, or
    - p *refers* to q without calling it, e.g. by constructing a closure
      whose procedure is q.

    However, when constructing the *tail* SCC within a conventional SCC,
    we want to add an edge from p to q only in the first situation.
    Add an option that controls whether we add an edge just in the first
    situation or all three.

compiler/ml_tailcall.m:
    ZZZ

compiler/call_gen.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/mercury_compile_llds_back_end.m:
compiler/saved_vars.m:
compiler/term_constr_main.m:
    Conform to the changes above.

tests/hard_coded/tail_rec_scc.{m,exp}:
    A new test case for the new option.

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
    Enable the new test case.
2017-03-21 19:32:00 +11:00