On 22 Nov 2002 at 2:17, Frank Heckenbach wrote:
As just explained, variant checking is not part of general range checking....
Perhaps I should have said, "part of a general implementation of _constraint_ checking...." It would indeed be useful to have several independently specifiable checking options for special circumstances, but I should think that, from a user perspective, whether:
rcd.twobyte := something^ + 1;
...fails from the result being out of range, or the variant selector value being wrong, or "something" being nil, or the addition overflowing is of secondary importance to catching the error at all.
I do take your point that, from an implementation view, each of these types of constraint checks are implemented differently.
a.b := 2; a.b := 1; WriteLn (a.c) { WRONG }
But _is_ that wrong?
ISO 10206, section 6.5.3.3, says:
"When a variant becomes non-active, all of its components shall become totally-undefined."
But "totally-undefined" is not a value-bearing state, from 6.2.4, so the value of "a.c" is not changed by the change in the variant selector. Once "a.b" is set to 1, the first variant becomes active again, so references to "a.c" are again legal. On what basis, therefore, is the third statement above wrong?
Of course, there are cases where some checks can be omitted by compile-time knowledge. [...] As far as I'm concerned, when I do it, I'll only do the simplest optimizations....
That is quite reasonable. Having the compiler emit redundant checks is far better than omitting a needed one.
For the occasional tight loop where speed really matters, the programmer might want to choose types etc. in order to help the compiler avoid unnecessary checks, rather than hoping for some complicated optimizations.
Or perhaps allow checking to be turned off and on via compiler directives.
Not exactly. In a `case' statement, the compiler produces code for all variants at once (possibly using jump tables etc.), for a variant access we need to check only one case.
I fear that again I have failed to make myself clear. A variant field access would, of course, check only the particular case-constant-list associated with that variant. What I meant was that the logic used to generate a _single_ case alternative comparison is the same (or similar) logic as is needed to generate a variant selector check. Consider:
program p;
var a, b : integer;
begin case a of -9999, 1..5: b := 2 end end.
Not a jump table in sight in the GPC-generated assembly code. ;-) My point was that handling variant selector checking isn't overwhelmingly difficult, as the problem is similar to handling case-constant-lists in regular CASE statements.
I doubt whether that's too useful. The cases where the function call overhead might be worth it (very complex lists of selectors/ranges) are probably very rare in practice, so it doesn't seem worth optimizing for them.
Whether the check is inlined or a function call is simply an implementation issue. I would imagine this is done simply to limit the code size (consider inlining the identical check hundreds or thousands of times). I have not investigated specifically, but I would not be surprised if specifying "-finline-functions" would change this behavior in GNAT.
[Assembler stuff skipped. This goes to you, too -- if you think something can be improved in the assembler code, then please contact the respective backend maintainers.
Oh dear, I really must improve my use of English! ;-) I shall endeavor to be clearer in future communications.
I was not making any comment at all on the GPC-generated code. I was simply trying to counter the argument that variant checking would inevitably add an intolerable overhead to a program by offering an illustration.
Here, let's please stay at the high level.]
I agree in principle. However, it is my observation that programmers today generally have little knowledge of the code generated by compilers for specific constructs. I see this commonly expressed in erroneous assertions regarding the performance of specific compilers or language constructs, e.g., "Ada (or Pascal :-) generates inefficient code when compared to C," when an examination of the code generated for equivalent programs reveals otherwise.
My illustration at the assembly level was merely to demonstrate that variant checking need not involve large amounts of code -- something that may not be immediately evident to those not accustomed to looking at the code generated for, e.g., an "if-then-else" statement.
-- Dave