[comp.lang.c] volatile, noalias and optimization

tneff@atpal.UUCP (Tom Neff) (04/22/88)

It's been pointed out at some length that the new /volatile/ and /noalias/
keywords are really all about controlling the optimizer in various C
implementations, more than about the language itself.  Thus /volatile/
says "treat this variable no different syntactically, in type, usage etc.,
but DON'T optimize access to its memory location when you generate code;
go 'to the metal' every blessed time."  This is a wonderful feature to
have, a real "plus" for systems work... but shouldn't we use

        #pragma volatile(var1, var2, var3)

instead of imposing a new keyword on the language grammar?  And ditto for
/noalias/, although I had a cow when I saw that keyword suddenly sprinkled
through string.h et al.  It shouldn't be necessary in the standard library
prototypes, for heavens sake.  In the cases where it's helpful to let the
optimizer know there are no alias paths to a variable,

        #pragma noalias(var4, var5)

ought to be all you need.  If XJ311 is worried about the syntax varying
from one implementation to the next, they can publish a "guideline" which
I'm sure most complying vendors would be happy to follow unless there was
a compelling reason to express it differently on some particular machine.


-- 
Tom Neff			UUCP: ...uunet!pwcmrd!skipnyc!atpal!tneff
	"None of your toys	CIS: 76556,2536		MCI: TNEFF
	 will function..."	GEnie: TOMNEFF		BIX: are you kidding?

ljz@fxgrp.fx.com (Lloyd Zusman) (04/23/88)

In article <132@atpal.UUCP> uunet!pwcmrd!skipnyc!atpal!tneff (Tom Neff) writes:
>It's been pointed out at some length that the new /volatile/ and /noalias/
>keywords are really all about controlling the optimizer in various C
>implementations, more than about the language itself.
> ...
> ... but shouldn't we use
>
>        #pragma volatile(var1, var2, var3)
>
> ... And ditto for /noalias/ ...
>
>        #pragma noalias(var4, var5)
>
> ...

Hear hear!  This way, those of us who really want one or the other of
these constructs could use them all we want, and those others who
don't want the namespace cluttered can be happy, too.

Of course, we'll probably see a few postings from some C
Fundamentalists that try to tell us how we should never write code
that needs either of these.  I think the term "Fundamentalists" is
apt, as these folks aren't satisfied with their own programming
holiness, but they feel they have to force the rest of us to program
in accordance with their (often misguided) beliefs.  Oh well ...
that's life on the net.

I also presume that the ANSI committee won't follow this excellent
suggestion, either (sigh).


--
    Lloyd Zusman
    Master Byte Software

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

In article <132@atpal.UUCP> uunet!pwcmrd!skipnyc!atpal!tneff (Tom Neff) writes:
>This is a wonderful feature ... but shouldn't we use
>        #pragma volatile(var1, var2, var3)
>instead of imposing a new keyword on the language grammar?

Unless you expand on this a bit, it's not as powerful.  I've actually used the
declaration "char volatile * volatile p;" (a volatile pointer to volatile
memory) -- would your proposal handle this?

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(In case anyone cares, p was volatile because it was being used by both
branches after a fork(), and *p because it was a shared memory segment.)

chasm@killer.UUCP (Charles Marslett) (04/27/88)

In article <132@atpal.UUCP>, tneff@atpal.UUCP (Tom Neff) writes:
> It's been pointed out at some length that the new /volatile/ and /noalias/
> keywords are really all about controlling the optimizer in various C
> implementations, more than about the language itself.  Thus /volatile/
> says "treat this variable no different syntactically, in type, usage etc.,
> but DON'T optimize access to its memory location when you generate code;
> go 'to the metal' every blessed time."  This is a wonderful feature to
> have, a real "plus" for systems work... but shouldn't we use
> 
>         #pragma volatile(var1, var2, var3)
> 
> instead of imposing a new keyword on the language grammar?  And ditto for

I'll go along with this if we will (for consistency sake) also banish
"register", "short" and "void" with it.  They all have similar impure
usage.  "Register" is even an optimizer directive, if I ever saw one.  And
"void" is documentation/lintification feature that probably doesn't serve
its purpose near as well as "volatile" does its own.  Sure the language
becomes a bit more verbose, somewhat more difficult to read (somewhat
more like Pascal (?)), but the inferences are useful when you need them,
and I don't like "#pragma" as a compiler directive any more than I did
"#line"  --  kludges, only if you gotta use 'em!

Did I step on any toes this time?

> Tom Neff			UUCP: ...uunet!pwcmrd!skipnyc!atpal!tneff

Charles Marslett
chasm@killer.UUCP

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (04/27/88)

 >> It's been pointed out at some length that the new /volatile/ and /noalias/
 >> keywords are really all about controlling the optimizer in various C
 >> implementations, more than about the language itself.
 >> 
 >>         #pragma volatile(var1, var2, var3)
 >> 
 >> instead of imposing a new keyword on the language grammar?  And ditto for
 > 
 > I'll go along with this if we will (for consistency sake) also banish
 > "register", "short" and "void" with it.  They all have similar impure
 > usage.  "Register" is even an optimizer directive, if I ever saw one.  And

   The criticism of volatile comes mainly from the fact that it's use is more
for the optimzer than an aid to the programmer.  Register is the only construct
you have named above that could directly affect the optimizer.  So it is the
only construct of relevance that analogies could be drawn from.  People
have also criticized register for it's role as a optimization hint.

 >	[ranting deleted ]
 > 
 > Did I step on any toes this time?
 > 
   Not really, you only show your lack of understanding for the opposing
position on volatile.

 > Charles Marslett
 > chasm@killer.UUCP

   I believe that if the non-volatile concept is to be adopted as the default
for variables then the volatile declaration should be provided via keyword.
The current utilization of the language would dictate the need for such
a sematic construct. So it should also be adopted in the syntax.

  However, if you were to ask me whether I believed non-volatile should
be the default, well that's another question.  I'm kind of swaying between the
the fundalmentist view and realizes what the pragmaitcs are for both sides.

-- 

Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

tneff@atpal.UUCP (Tom Neff) (04/27/88)

In article <3637@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) asks:
>In article <132@atpal.UUCP> uunet!pwcmrd!skipnyc!atpal!tneff (Tom Neff) writes:
>>This is a wonderful feature ... but shouldn't we use
>>        #pragma volatile(var1, var2, var3)
>>instead of imposing a new keyword on the language grammar?
>
>Unless you expand on this a bit, it's not as powerful.  I've actually used the
>declaration "char volatile * volatile p;" (a volatile pointer to volatile
>memory) -- would your proposal handle this?

You're right, Karl, the #pragma approach wouldn't work for nested volatile
references like your example, and I can't think of a graceful way to extend
my proposal to deal with it either.  I guess, then, that the compelling 
argument for extending the name space to include volatile is that it needs
syntactic access to the declarations themselves.  Thanks for pointing this
out!  (It's amazing how sweet tempered one feels on reading of noalias's 
demise...)
-- 
Tom Neff			UUCP: ...uunet!pwcmrd!skipnyc!atpal!tneff
	"None of your toys	CIS: 76556,2536		MCI: TNEFF
	 will function..."	GEnie: TOMNEFF		BIX: are you kidding?

shankar@hpclscu.HP.COM (Shankar Unni) (04/29/88)

> ..... (It's amazing how sweet tempered one feels on reading of noalias's 
> demise...)

I'm a little behind on this topic, but is the demise for real, or just
wishful thinking?

------
Shankar Unni
  "The reports of my demise are a little premature" -- Mark Twain

pablo@polygen.uucp (Pablo Halpern) (04/29/88)

> It's been pointed out at some length that the new /volatile/ and /noalias/
> keywords are really all about controlling the optimizer in various C
> implementations, more than about the language itself.

No, volatile is not all about controlling the optimizer.  It's just that
code that needs volatile is MORE LIKELY to break when optimized.  It might
break on some compilers without optimization.  In fact, volatile has
less to say about optimization than does register.

I think a lot of the debate about the necessity of volatile comes from
a lack of understanding about how many subtleties there are in defining
the semantics of a language.

To show why volatile is really necessary, let me first show why the
"assume all variables are volatile" argument is a semantic nightmare.
Take the following code:

1 main()
2 {
3	int a, b;
4
5	scanf("%d", &a);
6	b = 2*a;
7	printf("%d\n", b);
8 }

Assume I run this program and type the number 5 at the keyboard.  Would you
have any hesitation about claiming that this program would produce "10"
as its output?  No? So you wouldn't have any problem with the compiler
optimizing this as:

	scanf("%d", &a);
	printf("%d\n", 2*a);

would you?  Of course not!  But if b is assumed volatile, you cannot
assume it has the same value in line 7 as it was assigned in line 6.
Even if you were to restrict the optimizer, do you really want the
program not to mean what it seems to mean?  You see, its not just the
optimizer that needs variables to be non-volatile.  Its needed by both
humans and machines for giving meaning to a program.  Thus, making all
variables effectively volatile not only makes the program harder to
optimize, it acually changes the semantics of the language such that
almost nothing can be expressed in it.

So, variables should not be volatile by default.  "Why not use a #pragma
to show the exceptions, instead of adding a keyword." you ask.  "After
all, the use of shared memory and device registers is non-portable anyway, 
right?"

Wrong.  The use of these things can be as portable as writing to a file.
The fopen() function from the standard library returns a handle that
can be used by portable programs to write to a file.  The implementation
of fopen() is not portable, but the function call itself its.  The
vender of your C compiler isolated the non-portable stuff so that you
could call your program "portable."

Similarly, let's assume a set of functions that have non-portable
implementations but whose interfaces are portable and well-defined.
The function, shared_malloc() returns a pointer to a named piece of
shared memory and the functions begin_mutex() and end_mutex() guarentee
mutually exclusive access to that memory.  The following code
would be impossible without volatile:

	int volatile *shared;	/* pointer to volatile int */

	shared = (int *) shared_malloc("foo", 10 * sizeof(int));
	while (should_fill()) {
		begin_mutex(shared);
		if (shared[0] == 0)
			fill_array(shared);
		end_mutex(shared);
	} /* end while */

This type of code could be scattered throughout a 10,000 line program.
The program is portable except for the three functions mentioned.  If
volatile were not standard, this program could not be written portably
at all.

"But that's multi-tasking and C is not a multi-tasking language."
You'd better get use to the fact that multi-tasking is becoming a
bigger and bigger port of a programer's life.  Even personal computers
are beginning to multi-task and these tasks sometimes need to communicate.
Signal and interupt handlers are examples of multi-tasking in an
otherwise single-task environment.

But unlike the ill-fated noalias, you CAN program in C without understanding
or using volatile while giving those of us that write system software
a way to write portable code.

FLAME ON
	I'm also sick of people implying that any program that is not
	strictly conforming is totally non-portable.  I write a lot of
	programs that are portable to a large number of machines but
	are not portable to ALL machines.  I also write a lot of programs
	that have small, self-contained, sections that handle non-portable
	things like shared memory allocation, interupt handling, semaphores,
	etc..  Volatile would allow me to keep these sections small and
	isolated because the program could "admit" that it might be
	running in a multi-tasking environment.  As it is, I'm already
	playing it a bit dangerous when it comes to signal handlers.

	If volatile were a #pragma, then every compiler could choose its
	own syntax and semantics for it, if it were implemented at all.
	Even among Unix systems, code that used volatile would not be
	portable!  Then maybe IEEE would have to get into the act and
	define a superset of ANSI C (called POSIX C?) which specifies
	a standard syntax for the volatile #pragma.  Yuk!
FLAME OFF

Thankfully, it looks like volatile is here to stay.  Thankfully, it looks
like noalias has bit the dust!

Pablo Halpern		|	mit-eddie \
Polygen Corp.		|	princeton  \ !polygen!pablo  (UUCP)
200 Fifth Ave.		|	bu-cs      /
Waltham, MA 02254	|	stellar   /

marcus@illusion.UUCP (Marcus Hall) (04/30/88)

In article <135@atpal.UUCP> tneff@atpal.UUCP (Tom Neff) writes:
>In article <3637@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) asks:
>>In article <132@atpal.UUCP> uunet!pwcmrd!skipnyc!atpal!tneff (Tom Neff) writes:
>>>This is a wonderful feature ... but shouldn't we use
>>>        #pragma volatile(var1, var2, var3)
>>>instead of imposing a new keyword on the language grammar?
>>
>>Unless you expand on this a bit, it's not as powerful.  I've actually used the
>>declaration "char volatile * volatile p;" (a volatile pointer to volatile
>>memory) -- would your proposal handle this?
>
>You're right, Karl, the #pragma approach wouldn't work for nested volatile
>references like your example, and I can't think of a graceful way to extend
>my proposal to deal with it either.

Well, actually I would think that this could be expressed thusly:

char *p;
#pragma volatile(p, *p)

The problem with this whole approach, however, is that #pragma is explicitly
left undefined in ANSI-C.  Any compiler implementer is free to do whatever
he/she feels like for #pragma.  ANSI-C merely defines #pragma to be a standard
escape to non-standard directives.  Thus, one compiler may implement this in
the method mentioned above, but another may implement it as:

#pragma vol p; *p;

or any number of different ways.  Usage of #pragma is by definition
non-portable.  It is just there for an escape for local additions that may
be important enough to add despite the non-portableness.  A concept of
volatility is important enough (in my opinion, and in quite a few others)
that a standard, portable way of specifying this is desirable.

Most programs can just ignore volatile and everything will work just fine.
Older compilers can just ignore the keyword and assume everything is
volatile just like current compilers.  Smarter compilers can take advantage
of this to avoid re-loading a register with a variable that was already there,
avoid doing extra writes to memory, etc.

Noalias does enable many optimizations, but while most variables are normally
not volatile, most variables ARE noalias.  Variables that should be declared
volatile are easy to identify; globals that are actually memory mapped i/o
registers, variables that are accessed by signal catchers or interrupt
routines, etc.  Maybe it would make more sense to define a keyword "aliased"
which would be tagged onto variables that actually ARE referenced by
multiple means and let the compiler treat variables as noalias unless it
has its address taken or it is declared "aliased".  Of course, globals
would need to be declared "aliased" if its address were taken *anywhere*.

Anyhow, it seems that noalias should be implemented by some compiler somewhere
through a technique similar to what you have proposed before it gets worked
into the standard.  If it really works and there aren't subtle disasters that
arise from its implementation, THEN incorporate it into ANSI-C-rev2.

Marcus Hall
..!{ihnp4,mcdchg}!illusion!marcus

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

In article <145@polygen.UUCP> pablo@polygen.uucp (Pablo Halpern) writes:
>> It's been pointed out at some length that the new /volatile/ and /noalias/
>> keywords are really all about controlling the optimizer in various C
>> implementations, more than about the language itself.
>
>No, volatile is not all about controlling the optimizer.  It's just that
>code that needs volatile is MORE LIKELY to break when optimized.  It might
>break on some compilers without optimization.  In fact, volatile has
>less to say about optimization than does register.
>
>I think a lot of the debate about the necessity of volatile comes from
>a lack of understanding about how many subtleties there are in defining
>the semantics of a language.
>

Unfortunately, the above statements are off the mark.  Volatile is *indeed*
only required to control the optimization, *from the compilers' point of
view*.

"Volatile" and "register" etc are not part of the subtleties of the
semantics of the *language*, but are defining something about the
*environment* in which the compiled code is to be run.

The examples cited only showed the compiler being told to avoid non-volatile
dependant optimizations because of environmental requirements.

Programs run in *real machines*.

I agree fully that the concept of volatility may imply a great deal,
including the examples cited by Pablo, but only if the definition of the
*environment* in which the program is running also makes these
implications valid.

>1 main()
>2 {
>3	int a, b;
>4
>5	scanf("%d", &a);
>6	b = 2*a;
>7	printf("%d\n", b);
>8 }
>

If b in the above is defined as volatile, the *compiler* must assume it can
change between line 6 and 7, and (only) control its optimization, but the
*programmer* needs to read some other spec to determine its true nature!

Indeed, declaring b volatile may not be adequate, because it may change
after it has been loaded into some register deep in the heart of the printf
function.  In that case the *programmer* has to take very special care with
b.  Special care that a compiler might never be expected to provide.

No one has suggested (have they?) that the ANSI 'C' volatile keyword fully
covers the requirements of these special architectural features, only that
the compiler can at least be forced to produce something *predictable* in
the cases where special features are being manipulated.

Remember, the "volatile" we are discussing, is the keyword as defined in the
ANSI 'C' definition, not that defined in the OED.

>FLAME ON
>	I'm also sick of people implying that any program that is not
>	strictly conforming is totally non-portable.  I write a lot of
>	programs that are portable to a large number of machines but
>	are not portable to ALL machines.  I also write a lot of programs
>	that have small, self-contained, sections that handle non-portable
>	things like shared memory allocation, interupt handling, semaphores,
>	etc..

These people are the Fundamentalists.

Only they believe that being non-portable is in itself Not A Good Thing
Under Any 'C'ircumstances.

>	If volatile were a #pragma, then every compiler could choose its
>	own syntax and semantics for it, if it were implemented at all.
>	Even among Unix systems, code that used volatile would not be
>	portable!

Now that we have the current ANSI standard (nearly) put to bed, perhaps we
can feel free to discuss what should be included in the *next* revision
without worrying about being told "it's too late" (:-).

Frankly, I think that instead of "volatile" what is *really* needed is a
*contextural* "dont optimize"/"optimize" set of switch pairs to handle such
things as volatility and, god forbid, alias assumption relaxation.

I wouldn't dare to suggest the syntax at this stage, but I *don't* think a
#pragma is the correct vehicle, as this need to be a basic language feature,
not a compiler specific option.  Remember in these days of microprocessors,
a compiler for a particular CPU can make *no* assumptions about the
architecture that the compiled code is running on, other than the
instruction set.  Writing a compiler for a 68000 is a different exercise
than writing one for a VAX, which is a fully defined environment.

So it's not reasonable to make these controls a compiler specific thing.
They *have* to be part of the language.
-- 
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