Discussion:
[m-dev.] mutual tail recursion warnings
Zoltan Somogyi
2017-09-12 14:17:45 UTC
Permalink
I have a question about what people think the compiler should do
when it is asked to generate warnings for mutually recursive calls
that are not TAIL recursive, but this fact is NOT a fault of the caller.

The require_tail_rec_N.m programs in tests/invalid each have
two mutually recursive predicates, odd and even. Even calls odd
in a non-tail position, while odd calls even in a tail position.
The expected output says the compiler should generate
a warning about the call to odd in even, but not the call to even
in odd. And that is what we generate in LLDS grades. In those
grades, the call to even in odd is optimized: the generated code
deallocates odd's stack frame and does a goto to even.

In MLDS grades, this doesn't work. The MLDS code generator
works on TSCCs: sets of procedures in which each procedure
is reachable from every other via TAIL calls. In this case,
since even does NOT call odd via a tail call (a fact that gets
a warning), the MLDS code generator generates code for them
separately, which means that the call from odd to even *must*
be an ordinary call, not a tail call. The MLDS code generator
therefore generates a warning about this non-tail recursive call.
But if the programmer looks at this call, he/she will see no reason
why this call is not a tail call. The actual reason is not *anywhere*
in odd; it is in even. The way I see it, this violates the law
of least astonishment.

Note that in this case, while the MLDS code won't be able to reuse
any of even's or odd's stack frames, the LLDS code won't be able
to reuse even's stack frames either, so BOTH backends use
stack space that is linear in the depth of recursion. The MLDS backend
will use twice as many stack frames, but there is no necessary
relationship between the *sizes* of the stack frames on the two backends,
so if the C compiler is much smarter than the Mercury compiler
about stack slot optimization, the MLDS version may in theory
be able to use *less* stack space than the LLDS version.
That is not very likely, but it is possible. It is much more likely
that the user cares about the constant vs linear stack space distinction
much more than about the linear constant factor. In both cases,
the extra warning in MLDS grades is not helpful, and (at least with
the current wording) is likely to be misleading.

Do people think that adding an explanation along the lines of
"the fault for the non-tail nature of this recursive call may lie
in another predicate" would be sufficient to reassure programmers
when they can't find the fault in the predicate (in this case, odd)
mentioned in the error message, or should we try to avoid generating
the misleading error message at all? The latter would require
changing the error message about the actual source of the problem
(the non-tail call in even) to explain that it may affect its whole SCC,
not just the predicate in which it appears.

Zoltan.
Peter Wang
2017-09-13 05:06:30 UTC
Permalink
Hi Zoltan,
Post by Zoltan Somogyi
Do people think that adding an explanation along the lines of
"the fault for the non-tail nature of this recursive call may lie
in another predicate" would be sufficient to reassure programmers
when they can't find the fault in the predicate (in this case, odd)
mentioned in the error message, or should we try to avoid generating
the misleading error message at all?
Can we name the predicate(s) in the SCC which is the source of the problem?
Post by Zoltan Somogyi
The latter would require
changing the error message about the actual source of the problem
(the non-tail call in even) to explain that it may affect its whole SCC,
not just the predicate in which it appears.
I wouldn't necessarily think to look at the error message for another
predicate, at least, not initially.

Peter
Zoltan Somogyi
2017-09-13 05:21:20 UTC
Permalink
Post by Peter Wang
Hi Zoltan,
Post by Zoltan Somogyi
Do people think that adding an explanation along the lines of
"the fault for the non-tail nature of this recursive call may lie
in another predicate" would be sufficient to reassure programmers
when they can't find the fault in the predicate (in this case, odd)
mentioned in the error message, or should we try to avoid generating
the misleading error message at all?
Can we name the predicate(s) in the SCC which is the source of the problem?
We can name the procedures in the SCC for which we have already generated
such warnings. Since we process the TSCCs within the SCC bottom up,
this will be the procedures from which the procedure in question is not
reachable via *tail* calls. If there is only one such procedure, this will be
the source of the problem; if there is more than one, then the source
of the problem may be just one of them, and we can't tell which one.
Post by Peter Wang
Post by Zoltan Somogyi
The latter would require
changing the error message about the actual source of the problem
(the non-tail call in even) to explain that it may affect its whole SCC,
not just the predicate in which it appears.
I wouldn't necessarily think to look at the error message for another
predicate, at least, not initially.
That is the problem I am trying to fix, yes. But did you intend that comment
to argue for or against either course of action listed above?

Zoltan.
Peter Wang
2017-09-13 05:50:28 UTC
Permalink
Post by Zoltan Somogyi
Post by Peter Wang
Hi Zoltan,
Post by Zoltan Somogyi
Do people think that adding an explanation along the lines of
"the fault for the non-tail nature of this recursive call may lie
in another predicate" would be sufficient to reassure programmers
when they can't find the fault in the predicate (in this case, odd)
mentioned in the error message, or should we try to avoid generating
the misleading error message at all?
Can we name the predicate(s) in the SCC which is the source of the problem?
We can name the procedures in the SCC for which we have already generated
such warnings. Since we process the TSCCs within the SCC bottom up,
this will be the procedures from which the procedure in question is not
reachable via *tail* calls. If there is only one such procedure, this will be
the source of the problem; if there is more than one, then the source
of the problem may be just one of them, and we can't tell which one.
That sounds good.
Post by Zoltan Somogyi
Post by Peter Wang
Post by Zoltan Somogyi
The latter would require
changing the error message about the actual source of the problem
(the non-tail call in even) to explain that it may affect its whole SCC,
not just the predicate in which it appears.
I wouldn't necessarily think to look at the error message for another
predicate, at least, not initially.
That is the problem I am trying to fix, yes. But did you intend that comment
to argue for or against either course of action listed above?
For the first suggestion, with the addition above if possible.

Peter

Loading...