[comp.std.c] NEVERMIND!

rfg@lupine.ncd.com (Ron Guilmette) (11/04/90)

In article <1990Nov3.231856.20556@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>
>>This seems entirely counter-intutive to me, and yet one supposedly ANSI
>>C compiler provides such a treatment.
>
>Your use of the word "supposedly" is appropriate.  The way you asked this
>implies that this doesn't happen if the thing pointed at is not `volatile'.
>My diagnosis would be as mentioned above:  somebody kludged `volatile' into
>a compiler that originally didn't support it, and broke the prefix `++'
>operator in the process.

OK.  Let me apologize to everyone for having wasted net bandwidth on
this question.

Here is what was *actually* happening.

	char *extern_charptr_func ();
	int extern_int_func ();

	void example ()
	{
		int i = extern_int_func ();
		volatile char *cp = extern_charptr_func ();

		do {
			i--;
			(++cp)[0];
		} while (i);
	}

Now in this particular compiler (which happens to be GCC, as I believe
Henry guessed) I asked the author (Richard Stallman) some time back to
add a nice little feature for me, which he was nice enough to do.

The feature that I asked for was to have the values of volatile
expressions evaluated, even if the result was not used, so that:

	volatile char *cp;

		...
		*cp;
		...

would in fact cause a (byte) fetch from the address pointed to by `cp'.

Now apparently, the ANSI standard doesn't explicitly require such treatment,
but it certainly doesn't rule it out either.  I found this feature quite
useful in certain circumstances (e.g. driving I/O chips) in order to be
able to code (entirely in C) a simple load operation (on say a device
register which recognizes the load itself as a signal to do something).

Unfortunately, due to a minor oversight while implementing this enviable
feature, Richard caused such expressions to have code for their side
effects generated *twice*.

Thus, for my complete example above, the pointer `cp' was being incremented
*twice* (once before the indirection and once after) for each trip thru
the loop.  The latter increment was (later) getting stuffed into a
delay slot.

Serves me right for asking for a bizzare feature.

Anyway, I just tracked down the bug and wrote a three line fix.  Now,
only one increment is generated (prior to the indirection) and correct
ordering of operations is maintained nicely.  (Try that on your binary-
only compilers!)

So anyway, NEVERMIND!

gwyn@smoke.brl.mil (Doug Gwyn) (11/05/90)

In article <2419@lupine.NCD.COM> rfg@lupine.ncd.com (Ron Guilmette) writes:
>	volatile char *cp;
>		*cp;
>would in fact cause a (byte) fetch from the address pointed to by `cp'.
>Now apparently, the ANSI standard doesn't explicitly require such treatment,

Actually, it does require an access (preferably but not necessarily a byte-
wide one).  See 3.5.3 Constraints.  The implementation must define what
constitutes an access; it is intended that the access be constrained to the
program-specified width whenever possible.

>I found this feature quite useful in certain circumstances (e.g. driving
>I/O chips) in order to be able to code (entirely in C) a simple load
>operation (on say a device register which recognizes the load itself as
>a signal to do something).

Indeed, that was one of the main motivations for the introduction of the
"volatile" type qualifier.  To take a specific example, UNIX device drivers
are almost always coded entirely in C, and on the PDP-11 and similar memory-
mapped I/O architectures, some device registers perform different actions
upon a "read-byte", "read-word", "write-byte", "write-word", "read-modify-
write", or other variations of the memory-bus access cycles involved.
Trying to get the right type of machine code generated while coding the
driver in C was quite tricky, and many hard-to-track-down bugs resulted.
With compilers other than Ritchie's, enabling optimization often would
change this behavior, too.  At least one version of the UNIX Portable C
Compiler (PCC) had a special hack to recognize constructs like
	((struct xxx *)0177450)->zzz
as being potential references to I/O space (device registers) and would
avoid excessive optimization involving such expressions (where the constant
lay within the Unibus I/O address range).  X3J11 decided that this problem
had to be faced squarely, and introduced "volatile" to obviate the need for
such hacks.  However, although it was proposed that conforming
implementations be required to implement the minimum possible access
"width" for volatile-qualified data, and that is the intent of requiring an
implementation definition for it, it was not practical to insist on it in
every implementation; thus, some latitude was allowed implementors in that
regard.