[comp.lang.c] A different view of volatile

hankd@pur-ee.UUCP (Hank Dietz) (04/26/88)

In article <2003@rtech.UUCP>, jas@llama.rtech.UUCP (Jim Shankland) writes:
> In article <13074@brl-adm.ARPA> dsill@NSWC-OAS.arpa (Dave Sill) writes:
> >Terry Lambert writes:
> >>Basically, if it works without -O, it should work with -O, regardless of what
> >>the compiler writer's optimization does to achieve its goal.  If this makes
> >>writing compilers harder, so what?
> >
> >This bears repeating.  There should be no circumstances under which
> >the semantics of the language are changed by a flag to the compiler.

I agree.  The programmer should explicitly request "magic" which might
change the results of running a program; further, this request should
be within the language, not an ad-hoc command-line option.

> The alternatives that have been mentioned include:
> 
> 	(1) "Just don't do all that silly optimization".  Then, as Dennis

Actually, you can still do a lot of that optimization... it just takes more
compile time to do the better flow/dependence analysis to support it.

> 	(2) "If you need `volatile', don't use C."  I agree, it's

The un-solution.

> 	(3) "Let implementers of optimizing compilers come up with their
> 	own pragmas that can turn off certain optimizations where they
> 	will be destructive."  In other words, let each implementer

Another un-solution... this is the "programmer's job security enhancement"
choice.  Further, there is no guarantee that two compilers will not use the
exact same #pragma to mean two subtly different things.

Instead, why not use "register" to solve the problem....

Ever since K&R, code which takes the address of a register variable has been
non-portable in the best sense of the phrase:  where the code wouldn't work,
it would be flagged as a compile-time error.  Now, X3J11 says that it is
ALWAYS a compile-time error to take the address of a register variable.
In other words, if code is broken by register assignment, the compiler
can easily flag this condition at compile time.

Now, look at volatile.  Volatile says that an object either can change value
while we are not looking at it or that somebody else may notice when we
change the object's value.  This can only happen if two or more "processes"
(perhaps across multiple processors or DMA channels) simultaneously have
access to the same object.  It is easy for one process to know where an
object is (by simply declaring it), but I know of NO EXISTING C MECHANISM
for letting another process access that object OTHER THAN to pass the
explicitly-taken address of the object.  The same is true of DMA locations:
they are specific places in memory, and the only general way to overlay a
specific place is to set a pointer to that address.  In other words, AN
OBJECT WHICH HAS NO ADDRESS CANNOT BE VOLATILE:  A REGISTER OBJECT CANNOT BE
VOLATILE!

Why not make use of this SAFE, prior-art, compiler hint?  Currently, a C
compiler is correct iff it treats ALL non-register variables as volatile
(unless flow analysis can prove that the object address is never taken:
i.e., unless flow analysis can prove that it would have been safe to place
the variable in a register :-).  I propose that we simply extend register so
that, instead of merely being a flavor of auto storage class, it is an
attribute which can be applied to static and global data as well as to
expressions... the meaning is simply "this could be in a register" or,
phrasing it slightly differently, "this is NOT volatile."  This usage not
only breaks no (reasonable :-) existing code, but it also results in
compile-time errors where code would be broken, rather than resulting in the
mysterious execution caused by lack of a now-required-by-X3J11 volatile
declaration.

Oddly enough, the extended notion of register IS "noalias" with a somewhat
more flexible structure; an object has no aliases if one can only have one
name for it, and the inability to take the address of a register object
provides exactly this guarantee.

The semantics proposed are:

1. Use of "register" as the storage class specifier in a declaration
indicates that the object being allocated is of the default storage class,
but cannot have its address taken.  In other words, the declared items are
non-volatile and have the noalias property.

2. Use of "register" as an attribute of a storage class ("register" appearing
immediately after the storage class specifier in a declaration) forces the
exact same constraint: all thus declared objects carry the "register"
property.

3. Use of "register" as an attribute within a declaration after the type
specifier indicates that the appropriate typed entity has the register
property.  (This rule actually is how register declarations *should* have
been done, but it does not conflict with supporting the old-style register
declaration syntax for a while :-).

4. Use of "register" as an attribute cast on an expression, or as an
attribute cast within a declaration, forces the interpretation that the
expression value object has the "register" property.

5. When used as a cast or in a function argument list, the "register"
attribute does not propagate, whereas it does propagate when used as part of
a declaration.

Some simple examples:

/* a register global defined elsewhere */
register extern int a;

/* an array of 100 doubles, all conceptually accessible ONLY by use of the
   name d, with or without subscripts, but of static storage class.
*/
register static double d[100];

/* a pointer to a char object for which no other name exists...
   a pointer to a non-volatile, noalias, object.
*/
char register *p;

/* how the function strcpy should be declared (but need not be)... */
char *
strcpy(char register *p, register *q;)
{ ... }

/* how strcpy might be used... including a cast on malloc()... */
char register *p = (char register *) malloc(6);
p = strcpy(p, "hello");

Now, I'm not saying that the above syntax is perfect, and as DMR pointed-out
to me, having all those "register"s is certainly noisy, but by the rule of
"if it ain't broken, don't fix it" it seems to me that the above extension of
register -- especially rules 1. and 2. -- is much more reasonable.  Further,
although I have nothing against volatile, per se, isn't it better to go with
the more aggressive compiler optimization only when a person has specifically
hinted that it's ok, as opposed to the "volatile" scheme of aggressively
optimizing unless you're told no?  Besides, by now we all know how to spell
"register."

The views expressed above are overly written and under thought-out, but there
they are, so what is the consensus?  Is register as useful as I think it is?

						-Prof. Hank Dietz
						 School of EE
						 Purdue University
						 West Lafayette, IN  47907

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/26/88)

In article <7996@pur-ee.UUCP> hankd@pur-ee.UUCP (Hank Dietz) writes:
>Why not make use of this SAFE, prior-art, compiler hint?

Any attempt to make "register" a type qualifier rather than a storage
class is likely to conflict with existing practice.  Otherwise I more
or less agree with the notion.

In any case, it's too late to change this in the forthcoming Standard.

christiansen@chewi.che.wisc.EDU (REED CHRISTIANSEN) (04/27/88)

>
>From: Hank Dietz <hankd@pur-ee.uucp>
>Subject: A different view of volatile
>Message-ID: <7996@pur-ee.UUCP>
>Date: 26 Apr 88 00:29:37 GMT
>
> [Text Deleted.  Professor Dietz proposes the use of REGISTER to denote
>  data objects that cannot possibly be VOLATILE, since a REGISTER item
>  does not have an address.]
>
>although I have nothing against volatile, per se, isn't it better to go with
>the more aggressive compiler optimization only when a person has specifically
>hinted that it's ok, as opposed to the "volatile" scheme of aggressively
>optimizing unless you're told no?  Besides, by now we all know how to spell
>"register."

My observation is that the number of data items in a program that are
VOLATILE (that is, whose value(s) can change asynchronously due to
action by another process or by hardware action) is very small.  Even in
implementing real-time process control systems, the D/A and A/D handlers
are a small portion of the entire package.  It seems much easier to
declare these few variables as special cases than to declare all
non-special variables to be REGISTER.

I have no problem with aggressive optimization--I would prefer that the
compiler do as much optimization as it can, as long as I can point out
the VERY FEW data items that are non-deterministic.  In fact, our
never-ending problem is to squeeze more complicated mathematical models
into our real-time packages in order to do state-estimation, etc.  The
faster these computational loops run, the more realistic our models can
become.

If you hate VOLATILE and need to do real-time work, you have these
options:

(1) Optimize and use REGISTER, which is a burdensome but workable
alternative, requiring one to modify 90+% of declarations in one's code
from conventional C technique [TEDIOUS BUT SUITABLE CHOICE],

(2) Don't optimize, which will limit your ability to do computations in
real-time loops [VERY BAD CHOICE],

(3) Optimize computational modules; don't optimize the control loops;
make sure there is no module with both, document what you're doing, and
hope that the next fool to work on your project understands what is going
on [POTENTIALLY DANGEROUS CHOICE].

I prefer VOLATILE.
------

karl@haddock.ISC.COM (Karl Heuer) (04/27/88)

In article <7996@pur-ee.UUCP> hankd@pur-ee.UUCP (Hank Dietz) writes:
>Instead, why not use "register" to solve the [volatile] problem....

Currently, "break" has two (or maybe one and a half) meanings, "static" has
two meanings, and "void" has three.  I'd rather not see "register" achieve a
similar overloading, which is what I see in your proposal.

>[a register object cannot be volatile]

But the converse is false.  I use non-volatile non-register objects all the
time.

Also, your proposal breaks the rule of defaulting to the most common case.
Most programs don't need *any* volatile declarations, and of those that do,
most objects are *not* so qualified.  This is why X3J11 invented "volatile"
rather than "novolatile".

>register static double d[100];

How does the register-nonaddressibility rule interact with the automatic decay
of the array expression "d" into the pointer "&d[0]"?  You'd need to define
the rules very carefully to make this declaration useful.

>char *strcpy(char register *p, register *q;) { ... }

Minor nit: types don't propagate in a function prototype; you need "char" in
both declarations.  And no semicolon.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

nevin1@ihlpf.ATT.COM (00704a-Liber) (04/27/88)

In article <7996@pur-ee.UUCP> hankd@pur-ee.UUCP (Hank Dietz) writes:

>Why not make use of this SAFE, prior-art, compiler hint?  Currently, a C
>compiler is correct iff it treats ALL non-register variables as volatile
>(unless flow analysis can prove that the object address is never taken:
>i.e., unless flow analysis can prove that it would have been safe to place
>the variable in a register :-).

I don't like this for a number of reasons.

If a compiler assumes that all variables are volatile unless otherwise
stated (such as by a register declaration), then I do not think that it is
possible to do *ANY* type of optimization involving those variables.
Even simple peephole optimizations such as 'a=b;a=b' cannot be
legally optimized out, and 'x=2*y' and 'x=y+y' can yield two different
results.  What kind of optimization (or non-optimization code generation,
for that matter) is legal and what is illegal??

Most of the semantics of C become ill-defined at best, if it has to use
volatile variables.  This is my main problem with using 'volatile' as it
is defined now.  Suppose a variable 'i' is declared 'volatile' because
every time the memory location is referenced its' value is automatically
incremented.  What does '++i' or 'i <<= 1' mean?  In these examples, is the
memory location for i referenced once or twice?  Since this is
*implementation-dependent* (it is not addressed in the Standard as far as I
could see), using these operations for any kind of portable application are
meaningless.  But try programming without them!!

Try programming making the same assumptions that you want the compiler to
make (ie, that all variables, unless otherwise stated, are volatile).  Good
luck!  Unless you are *very* careful, you shouldn't use statements like

tmp = a * b;
c = tmp + a;

since 'a' could have changed between the two assignments.  (If you use this
construct with the assumption that a,b,c,tmp are volatile and you really
meant this as the outcome, this is still very hard to read/maintain.)  Since
you make assumptions about your environment when you program (it is
probably impossible to program otherwise), why not let the compiler
in on the secret?

[I was also going to talk about how 'register' would now have too many
meanings, but what I stated above is what I very strongly object to.  This
posting is long enough as it is.]

Any variable which is 'volatile' automatically becomes non-portable and
implementation-dependent.  Therefore, assuming that all variables, unless
otherwise stated, are volatile leads to machine-dependent unoptimizable
code (given the current definition of volatile).  This is not desirable and
it defeats the purpose of a Standard.
-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

hankd@pur-ee.UUCP (Hank Dietz) (04/28/88)

In article <4548@ihlpf.ATT.COM>, nevin1@ihlpf.ATT.COM (00704a-Liber) writes:
> In article <7996@pur-ee.UUCP> hankd@pur-ee.UUCP (Hank Dietz) writes:
> >Why not make use of this SAFE, prior-art, compiler hint?  Currently, a C
> >compiler is correct iff it treats ALL non-register variables as volatile
> >(unless flow analysis can prove that the object address is never taken:
> >i.e., unless flow analysis can prove that it would have been safe to place
> >the variable in a register :-).
...
> If a compiler assumes that all variables are volatile unless otherwise
> stated (such as by a register declaration), then I do not think that it is
> possible to do *ANY* type of optimization involving those variables.
> Even simple peephole optimizations such as 'a=b;a=b' cannot be
> legally optimized out, and 'x=2*y' and 'x=y+y' can yield two different
> results.  What kind of optimization (or non-optimization code generation,
> for that matter) is legal and what is illegal??

Not correct:  converting "a=b;a=b" into "a=b" often can be KNOWN SAFE.  You
only have to use register when the compiler wouldn't otherwise have noticed.

Suppose that a is declared "int a;" and that ALL references to a can be
seen.  If the address of "a" is never taken, then all references to "a" can
be safely removed; likewise, if "&a" is taken, only references to "a" where
"&a" reaches cannot be removed.  I'm oversimplifying a bit, but the basic
point is that the analysis to determine this for most LOCAL NON-POINTER
variables is quite easy, hence "register" helps only a little for local
variables.  It would be a big help for externs, statics, and for function
interfaces because it is very expensive (at least) for the compiler to see
all references when some references might be in other compilation units
(other files).

Even if we want to keep volatile, which I agree is probably a good idea given
that X3J11 has assumed it's there, we should at least permit register and
volatile to be used in very similar fashion, because they are conceptually
very closely related.

						-hankd

bts@sas.UUCP (Brian T. Schellenberger) (05/03/88)

In article <8013@pur-ee.UUCP> hankd@pur-ee.UUCP (Hank Dietz) writes:
|
|converting "a=b;a=b" into "a=b" often can be KNOWN SAFE.  You
|only have to use register when the compiler wouldn't otherwise have noticed.
|
|Suppose that a is declared "int a;" and that ALL references to a can be
|seen.  If the address of "a" is never taken, then all references to "a" can
|be safely removed; likewise, if "&a" is taken, only references to "a" where
|"&a" reaches cannot be removed.  I'm oversimplifying a bit, but the basic
|point is that the analysis to determine this for most LOCAL NON-POINTER
|variables is quite easy, hence "register" helps only a little for local
|variables.  It would be a big help for externs, statics, and for function
|interfaces because it is very expensive (at least) for the compiler to see
|all references when some references might be in other compilation units
|(other files).
|

No, no.  If you assume that it is "volatile" in the absense of of "register",
you can't do this at all.  "a=b;a=b" can't be optimized in this case because
the value of "b" may change between the two statement due to an asynchronus
process.  THAT is what "volatile" means.

What you are talking about--and what "register" implies--is NOALIAS, that
much-maligned and now defunct keyword.  It might be good to suggest for the
C-92 standard that the next ANSI committee add semantic meaning to "register"
allowing it to apply to other situations than it currently does in order to
provide the same functionality as NOALIAS in a keyword everybody feels more
comfortable with.

Of course, as Mr. Dietz points out, "register" is redundant for this purpose
for simple local variables anyway, since the compiler can usually figure it 
out.  Which is probably just as well, since "register" already means something
else for simple local variables.

The proposal to reuse "register" in this way seems very much in the "spirit of
C", but I consider this to be the worst single aspect of the language; I'd 
rather see NOALIAS brought back than overload "register" in this way meself.
Understood that this is probably a minority position; please skip the non-
informative flames (flames with actual information are ok).
-- 
                                                         --Brian.
(Brian T. Schellenberger)				 ...!mcnc!rti!sas!bts

. . . now at 2400 baud, so maybe I'll stop bothering to flame long includes.

mikew@wyse.wyse.com (05/04/88)

It seems that volatile is ill-defined when combined with operators
that operate in-place.  A way of alleviating this problem would
be to state that conforming programs can't have a volatile variable
that is on boths sides of an equal sign,  volatile variables can't
be used on the left hand side of the following 
operators: +=, -=, *=, /=, |=, &=, and volatiles can't be used at all
with the following operators: ++, --.

Example:
...
volatile int a,b;
int c;

a=a;		/* illegal */
a=b;		/* legal */
a=c;		/* legal */
c=a;		/* legal */
a=a+c;		/* illegal */
a+=c;		/* illegal */
++a;		/* illegal */
...

chris@mimsy.UUCP (Chris Torek) (05/05/88)

In article <178@wyse.wyse.com> mikew@wyse.wyse.com writes:
>It seems that volatile is ill-defined when combined with operators
>that operate in-place.

More than that, volatile is ill-defined *always*: on a machine
with only halfword load and stores, a fullword `a = 0' is not atomic.

Remember, though, that `ill-defined' does not mean `useless'.  The
following is ill-defined:

	struct rkdevice *rkaddr = (struct rkdevice *)0777440;
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

nevin1@ihlpf.ATT.COM (00704a-Liber) (05/06/88)

In article <178@wyse.wyse.com> mikew@wyse.wyse.com () writes:
>It seems that volatile is ill-defined when combined with operators
>that operate in-place.  A way of alleviating this problem would
>be to state that conforming programs can't have a volatile variable
>that is on boths sides of an equal sign,  volatile variables can't
>be used on the left hand side of the following 
>operators: +=, -=, *=, /=, |=, &=, and volatiles can't be used at all
>with the following operators: ++, --.

I was going to propose this myself!!  I have a problem with one of your
examples, though.

>volatile int a,b;
>a=b;		/* legal */

This type of assignment should be illegal, since

>a=a;		/* illegal */

is illegal.  Suppose the declaration was:

int	foo(bar1, bar2)
volatile int	*bar1, *bar2;
*bar1 = *bar2;

There may be no way, with static checking, to determine if bar1 and bar2
are the same or different.  At most one variable of type volatile is
allowed to appear in any statement (except for function arguments).

Also, volatile variables should probably be limited to types which only
require one machine instruction to load them, such as char, int, and *void (ie,
structs should not be allowed to be declared volatile), and arrays made up
of these types.
-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

be@dde.uucp (Bjorn Engsig) (05/06/88)

In article <13120@brl-adm.ARPA>, christiansen@chewi.che.wisc.EDU (REED CHRISTIANSEN) writes:
...
> VOLATILE (that is, whose value(s) can change asynchronously due to
> action by another process or by hardware action) ...
            ---------------       ---------------

That's not the only cases, consider:

----------------- get_value.c ------------------
static int *pointer;

set_address(ptr); int *ptr;
  { pointer = ptr };

get_value()
  { /* stuff */ 
    if (value_found)
      { *pointer = value; return 1;  }
    else
      return 0;
  }

------------------ main.c -------------------
main()
  {
  /* volatile */ int result;
  set_address(&result);
  while (get_value())  process_it();
  }

Such kind of code is for example found in database host language
interfaces, where you first define where to store the data from
the database, and later you fetch the data until no more data are
found.  In real life, the set_address() is called a various number
of times (probably many times) and then get_value() knows the addresses
and doesn't need a large and varying number of parameters.

This is not to oject against volatile, I know where I should put it.

-- 
Bjorn Engsig @ Dansk Data Elektronik A/S, Herlev, Denmark

Email: be@dde.dk			Phone:	+ 45 2 84 50 11
Email: ..!uunet!mcvax!dkuug!dde!be	Fax:	+ 45 2 84 52 20

henry@utzoo.uucp (Henry Spencer) (05/07/88)

> More than that, volatile is ill-defined *always*: on a machine
> with only halfword load and stores, a fullword `a = 0' is not atomic.
> 
> Remember, though, that `ill-defined' does not mean `useless'...

Remember also that "volatile" does not mean "atomic"!
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

tanner@ki4pv.uucp (Dr. T. Andrews) (05/07/88)

In article <4651@ihlpf.ATT.COM>, nevin1@ihlpf.ATT.COM (he of the longish and often-seen .signature filled with bad cursive) writes:
) ... (ie, structs should not be allowed to be declared volatile), ...

Gee, thanks.  That de-values my new whiz-bang disk controller (the
one with the nice structure filled with device registers and ending
with a memory-mapped i/o buffer).
-- 
{allegra clyde!codas decvax!ucf-cs ihnp4!codas killer}!ki4pv!tanner

chris@mimsy.UUCP (Chris Torek) (05/08/88)

In article <432@Aragorn.dde.uucp> be@dde.uucp (Bjorn Engsig) provides
an example of ordinary aliasing:
>static int *pointer;
>
>set_address(ptr) int *ptr;
>  { pointer = ptr };
	...
>main()
>  {
>  /* volatile */ int result;
>  set_address(&result);

This sort of aliasing is considered `normal' in C, and not cause
for declaring variables as volatile.  After that call to set_address,
even though `result' is a local variable, a straightforward compiler
(by which I mean one that does not analyse other functions during
compilation of main()) would have to consider any function call
(not just one to which &result is passed) as a change to `result':

	main() {
		int result;
		addr(&result); result = 1; f(); if (result==1) ...

the compiler may not optimise away the test in the `if'.  If you remove
the call to addr, or allow the compiler to see the code for addr()
and/or f() (some can do this at `link' time), and either addr() does
not save its parameter in a global or static variable and/or f() does
not use the same value (which would then be &result), the compiler may
optimise away the `if' test.

In (standard) Pascal, pointers may not point at local variables,
and any purely local optimisation is therefore safe.  The same is
true in (standard) FORTRAN.  This sort of problem is why `noalias'
came into being (and, fortunately, went out again: compilers that
do cross-module optimisation will soon be the norm, rather than the
exception; here the problem becomes tractable).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ray@micomvax.UUCP (Ray Dunn) (05/12/88)

 In article <11369@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
 >In article <178@wyse.wyse.com> mikew@wyse.wyse.com writes:
 >>It seems that volatile is ill-defined when combined with operators
 >>that operate in-place.
 >
 >More than that, volatile is ill-defined *always*: on a machine
 >with only halfword load and stores, a fullword `a = 0' is not atomic.
 >

No....volatile is not ill defined, it is machine dependant, which is what
you would expect it to be.

There is no connection between "volatile" and "atomic", "volatile" does not
imply "semaphore".
-- 
Ray Dunn.                      |   UUCP: ..!{philabs, mnetor}!micomvax!ray
Philips Electronics Ltd.       |   TEL : (514) 744-8200   Ext: 2347
600 Dr Frederik Philips Blvd   |   FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9   |   TLX : 05-824090

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/14/88)

In article <1054@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:
>No....volatile is not ill defined, it is machine dependant, which is what
>you would expect it to be.

The semantics of "volatile" are LESS machine dependent than its omission!

>There is no connection between "volatile" and "atomic", "volatile" does not
>imply "semaphore".

This much is true.

mouse@mcgill-vision.UUCP (der Mouse) (05/16/88)

In article <178@wyse.wyse.com>, mikew@wyse.wyse.com writes:
> It seems that volatile is ill-defined when combined with operators
> that operate in-place.  [suggestion:] [S]tate that conforming
> programs can't have a volatile variable that is on boths sides of an
> equal sign, volatile variables can't be used on the left hand side of
> [the (op)= operators] and volatiles can't be used at all with [++ and
> --].

> Example:  [edited]

> volatile int a;  int c;
> a=a;		/* illegal */
> a=a+c;		/* illegal */
> a+=c;		/* illegal */

I would argue that none of the above are at all hazy.  In each case, I
would claim that the result is exactly equivalent to the result
obtained by using a temporary.  For example, we can consider a+=c to be
identical to a=a+c (a is a simple variable, remember).  So the second
and third are really the same.  Then, I would say that

a = <expression>;

is identical to

{ /* not volatile */ int temp; temp = <expression>; a = temp; }

On some machines, this may mean that a+=c must compile to different
code depending on whether a is volatile.  (For example, the VAX addl2
instruction might not be usable, depending on exactly how it works.)

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

daveb@geac.UUCP (David Collier-Brown) (05/16/88)

> >In article <178@wyse.wyse.com> mikew@wyse.wyse.com appears to write:
> >More than that, volatile is ill-defined *always*: on a machine
> >with only halfword load and stores, a fullword `a = 0' is not atomic.

In article <1054@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:
>No....volatile is not ill defined, it is machine dependant, which is what
>you would expect it to be.
>There is no connection between "volatile" and "atomic", "volatile" does not
>imply "semaphore".

In the case of a fullword device register on a halfword-fetch
machine, the **machine** is ill-defined.  Volatile hardly helps.  It
does help on a halfword device register by ensuring that two reads
are done for
	status = device_register_foo;
It remains up to the device designer to make it possible to read the
register meaningfully in halves.

--dave (please let me NOT work on one of those) c-b