The world is not ready for 'volatile'

Chris Torek chris at mimsy.UUCP
Wed Jan 4 07:46:17 AEST 1989


>>>In article <15166 at mimsy.UUCP> I suggested that
>>>>... ["register"] implies not-volatile and not-aliased; and it does so
>>>>in a way that the compiler can reasonably enforce.
(by the way, the word `implies' is key.)

>>In article <9236 at smoke.BRL.MIL> gwyn at smoke.BRL.MIL (Doug Gwyn) writes:
>>>No, I reject this claim.

>In article <15171 at mimsy.UUCP> I answered with:
>>You mean to say that a register could be aliased?  Not in C!  How
>>about a volatile register?  It is a possibility, but it seems entirely
>>unnecessary.

In article <903 at husc6.harvard.edu> geoff at endor.harvard.edu
(Geoff Clemm) replies:
>I would have to second this rejection.  There is nothing in the
>reference manual that lets you count on register variables not being
>volatile.

You misinterpret (everyone always misinterprets! :-) ).

The dpANS allows you to write

	register const k = 4;
and
	register volatile v;

but, I ask, what do these mean?  The answer is that they mean the same
thing as

	const k = 4;
and
	volatile v;

except that you may not take the address of either variable---which
therefore means that the compiler need not even assign an address to
either variable.  This makes the effect (if any) of volatile on a
register declaration dubious at best.

>Now Chris, this is a total waffle.  For folks that are seriously concerned
>about portability, one needs a stronger argument than that "it seems entirely
>unnecessary" for a compiler writer to do something -- especially since many
>compiler writers ignore register declarations, which means register variables
>will be as volatile or non-volatile as any other variable.

For folks concerned with portability, the word `volatile' does not
exist in the language (with one exception), since the actual effect of
the volatile qualifier is compiler-dependent.  The exception is in
functions using setjmp.  Optimising such functions well is hard, and
the dpANS simply grants license to ignore the effect of longjmp on
program flow during optimisation.  This was, in my opinion, the wrong
thing to do; but while we are stuck with it, remember that I was not
saying that `volatile' and `register' are opposites, but merely that
`register' *ought* (in some more perfect world where the dpANS were
different) to imply not-aliased (it does) and not-volatile (it does
not).  Actually, again in my opinion, in a still more perfect world,
both the dpANS and `old C' would not have the `register' keyword
anyway.

Moreover, for those again concerned with portability, it is necessary
never to use `register volatile' even in functions using setjmp, since
in old compilers---where one would `#define volatile /*empty*/'---
registers are the *only* non-volatile variables.  In particular, the
PDP-11 V7 C runtime system, the 3.0, 4.0, and 4.1BSD runtime systems,
and most if not all SunOS runtime systems, effectively restore register
variables to their state at the time of the *setjmp* call:

	f()
	{
		register int r = 1;
		jmp_buf j;

		if (setjmp(j)) {
			(void) printf("r is now %d\n", r);
			return;
		}
		r = 2;
		longjmp(j, 1);
		/* NOTREACHED */
	}

This program prints `1', not `2', in a number of systems.  This is
precisely the effect produced by an optimising compiler given a
non-volatile variable `r' and ignoring the implicit `goto' produced by
the setjmp/longjmp pair.  The variable life analysis goes like this:

	register int r = 1	| r = constant 1
	jmp_buf j		| r = constant 1, j = constant <uninit>

	if (setjmp(j))		| r = constant 1, j = <unknown 1>
		/* (remember, j is passed by address) */
	printf(...)		| r = constant 1, j = <unknown 1>
	return	
	r = 2			| r = constant 2, j = <unknown 1>
	longjmp(j, 1)		| r = constant 2, j = <unknown 2>
		/* note that <unknown 1> != <unknown 2> */
	implicit return		| r = dead, j = dead

At this point, the compiler should replace known constants (the one
instance of r) with their values.  It can then delete both writes (r=1
and r=2) since they are to dead variables.  The optimised function is
thus

	if (setjmp(j)) {
		(void) printf("r is now %d\n", 1);
		return;
	}
	longjmp(j, 1);

We can merrily write `register volatile int r = 1', and a dpANS-
conformant compiler will do the `right thing', but the program is
not portable to some widespread versions of `old C' (including SunOS
3.2, where I just tested it).  The important thing is not that these
implementations are not dpANS conformant (they are not), but rather
that `volatile int r = 1' *will* work.

Then too, I doubt that `register volatile v' will do anything different
from `volatile v' in any worthwhile compiler.  (Note key words `I
doubt': this is an opinion, not a fact.)

Anyway, the point is that `register volatile v' (but not `register
volatile *v') is effectively useless.  It is therefore possible---but
not necessarily wise---to make `register' mean `not volatile', and to
declare the volatile qualifier and the register storage class
incompatible.  I do not claim that this encompasses all uses for
`volatile'.  I claim only what I said: register implies not-aliased,
and does so in a way the compiler can enforce (`&v' not allowed); and
register implies (through effective uselessness) not-volatile, again in
a way that the compiler can enforce (since volatility is purely the
compiler's notion anyway, as far as code generation is concerned).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list