[m-dev.] request for opinions about a change to switch detection
Zoltan Somogyi
zoltan.somogyi at runbox.com
Fri Nov 14 10:29:12 AEDT 2025
I have just got to successful bootcheck of a diff that
makes switch detection able to look arbitrarily deep in goals
to find deconstruction unifications that can denote
the arms of switches.
Until now, switch detection's limitations meant that
sometimes, we had to add redundant blocks of code to
get the compiler to recognize switches. One example is
the big block of unifications starting at line 2140 in
compiler/print_help.m. This diff would avoid the need
for such redundant code. (Which, in this case, turned out
to be *incorrect* redundancy, since four of the function
symbols listed in that block are not actually handled
by the code of the switch arm that this block starts.)
To get a successfull bootcheck, I had to shut up one warning
that the compiler now generates that it did not generate before.
The warning was for code whose essence is a switch like this:
message_type_to_string(MessageType) = Cord :-
(
(
MessageType = msg_a(Num),
TemplateAB = "A %d"
;
MessageType = msg_b(Num),
TemplateAB = "B %d"
),
string.format(TemplateAB, [i(Num)], Str)
;
MessageType = msg_c,
Str = "C"
),
Cord = singleton(Str).
The warning was:
unknown format string in call to predicate `string.format'/3.
The warning results from the fact that the updated version of
switch detection turns each disjunction (the outer and the inner)
into a switch, while the old version directly generated a single switch,
which is the outer switch that has been flattended by effectively
inlining in it the inner switch.
The problem is one of phasing. Switch detection is followed by
- cse (always run)
- determinism analysis (always run)
- unique modes (always run)
- stratification (rarely run)
- order-independent state update (never run)
- try expansion (always run)
- the format_call pass (run only if the proc may contain a format call)
- simplification (always run)
Simplification flattens any nested switches it finds, but by then,
the format_call pass has already generated the warning.
I can fix the problem in several ways, and I am looking for opinions
on which you guys prefer.
The first fix is to modify the code of switch detection to inline
any nested switches it now generates. This is conceptually simple,
but it can, in the worst case, greatly increase the workload of
the passes between switch detection and format call. This is because
inlining the inner switch in the outer switch creates N copies of
all the code that follows the inner switch in its arm of the outer
switch if the inner switch has N cases, and that following code has
no bound on its size.
The second fix is to modify the code of the format_call pass
to inline switches. This avoids the potential slowdown described above,
but requires a new pass as the initial part of format_call. Since most
procedures do not contain any call to any predicate named "format",
this prepass would not slow down the compilation of most procedures;
its impact would mostly by on compiler code complexity.
The third "fix" is to simply declare that the warning is an appropriate
response to code like the above.
My preference is for the second fix, but would also be ok with the first.
What do you guys think?
Also, if we settle on one the first two fixes, would you prefer that
I commit my diff *without* the chosen fix, and then post that fix for review
separately?
Zoltan.
More information about the developers
mailing list