[net.lang.c] register variables

stevens (03/28/83)

   Until a few years ago Yourdon, Inc. was in the C compiler business.
I am aware of a compiler they sold for the PDP-11 (Unix and RSX-11 versions)
and they also developed one for IBM for their Series/1 (under the EDX
operating system, I believe - IBM never released it since they changed the
OS under Yourdon's feet during developement and when the compiler was
completed it wouldn't work under the new version of EDX!).
   Anyway, Yourdon's PDP-11 compiler allowed longs to be assigned to two
of the three available registers on the PDP-11 and also allowed floats and
doubles to be assigned to two of the 4 FP registers.  I consider that
quite amazing since the Ritchie compiler, PCC and Whitesmiths don't go
that far with register variables on the 11.  PCC on the VAX doesn't even allow
floats or doubles in registers either.
   Is anyone aware of any other C compilers that allow either floats/doubles
to be assigned to registers or allow multi-register register assignments
(longs on the PDP-11, for example)?
	Richard Stevens
	...decvax!kpno!stevens
	...ucbvax!arizona!kpno!stevens

shekita@crystal.UUCP (06/20/85)

I have some questions about register variables:

1) When is it appropriate to declare a variable as a
   register? I have been told that declaring a variable 
   as a register can actually result in slower code. Is
   there a rule of thumb dictating when and when not to
   declare a variable as a register?

2) How many variables can be declared as registers on a Vax 780?
   In general, is there some way to tell how many register variables
   can be declared?

								 Eugene Shekita
								 Univ of Wisconsin

chris@umcp-cs.UUCP (Chris Torek) (06/21/85)

> From: shekita@crystal.UUCP

> When is it appropriate to declare a variable as a register? I have
> been told that declaring a variable as a register can actually
> result in slower code. Is there a rule of thumb dictating when and
> when not to declare a variable as a register?

Declare things registers when they're heavily used.  You *can* make
code run slower; consider how long it takes to save and restore the
register(s) before using them for something trivial.

> How many variables can be declared as registers on a Vax 780? In
> general, is there some way to tell how many register variables can
> be declared?

Depends on the compiler.  Most Unix compilers have 6 registers on
Vaxen (r11-r6).  VMS uses r12-r2 (!), though I don't know how their
compiler reacts to register declarations.  Sun's C compiler has 4
register pointers (a5-a2) and 6 register integers (d7-d2).  (I think.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

faustus@ucbcad.UUCP (Wayne A. Christopher) (06/22/85)

Speaking of register variables -- does anybody know what various C
compilers do when you don't declare variables as register, but there
are spare registers to use? From what I hear, neither ccom nor c2 are
smart enough to put local variables in registers when they are
available. It seems that it would be simple to just take the first few,
or even the most heavily used local variables that don't ever get &'d
and make them register...

	Wayne

arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (06/22/85)

In article <472@crystal.UUCP> shekita@crystal.UUCP writes:
>1) When is it appropriate to declare a variable as a
>   register? I have been told that declaring a variable 
>   as a register can actually result in slower code. Is
>   there a rule of thumb dictating when and when not to
>   declare a variable as a register?

Generally, the only time declaring a variable to be a register
generates slower code is when you declare a parameter to be a
register.  This is because, on most systems, this requires a move from
the stack into a register.  If the variable is rarely used, this
overhead may cost you more than having it in the register saves.

In some degenerate, unpredictable cases a compiler which isn't properly
written will generate worse code for a register variable than a
non-register variable.  I have seen this happen once on a vax.
However, you have no way of prediciting this kind of behavior, and
since someone might fix the compiler, you run a chance of getting worse
code in the future.

Some particularly smart compilers will use unused registers for
storage of intermediate values to avoid recalculating them.  Then you
can hurt yourself by declaring rarely used variables, since it takes
them out of contention for this, but these compilers are VERY rare.

>2) How many variables can be declared as registers on a Vax 780?
>   In general, is there some way to tell how many register variables
>   can be declared?

You have an infinite number of registers.  No, seriously, this is the
way to think about it.  You should declare EVERYTHING which you don't
have to take the address of to be a register.  You can tell old pdp-11
code in UNIX by the fact that they leave off declaraing register
variables after three.  Then, when the code was brought to a vax, which
has five, this potential optimization was lost.  If you declare all
legal variables to be registers, your code ports and takes advantage of
the new machine's resources without added work.

By EVERYTHING I mean just that.  Some machines have floating point
registers and some don't.  Some don't put chars in registers and others
do.  Some don't put in shorts in.  Some put one-word structures in
registers.  Some will someday put multiword structures in registers, if
somebody doesn't already.

Just be somewhat careful to declare things in the order you care
about.  This cuts both ways -- if you move to a machine with fewer
registers than yours, you can loose the most critical register uses in
favor of less critical.  For example, let's posit a two register
machine and the following code

	register int	i, j;

	for (i = 0; ...)
		for (j = 0; ...)

Now, move it to a one register machine, and "j", which is the most
tested variable, is out of a register and "i", which is used less
often, is still in one.  Not what you want.

All this shows is that register allocation should be done by the
compiler, not the user, except in rare circumstances.  Until someone
does a C compiler this way, though, you're stuck with these
techniques.

		Ken Arnold

chris@umcp-cs.UUCP (Chris Torek) (06/24/85)

Ken Arnold makes a good point here:

> You have an infinite number of registers.  No, seriously, this is the
> way to think about it.  You should declare EVERYTHING which you don't
> have to take the address of to be a register. [...] Just be somewhat
> careful to declare things in the order you care about.

I have to admit to getting into the sloppy habit of stopping after
six register declarations.  But that's not why I'm writing this.
. . what I really want to do is make another point here, and that
is that you should declare register variables before ordinary
variables (in general), since some machines (Pyramids) ignore the
word ``register'' and just put the first N (12) variables in
registers.  (Such a machine must, of course, be able to take the
address of a register.)

Also (last point---I promise!), to C compiler writers: please don't
parse the list of declarations and then perform the declarations in
reverse order!
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

alex@ucla-cs.UUCP (06/24/85)

>Just be somewhat careful to declare things in the order you care
>about.  This cuts both ways -- if you move to a machine with fewer
>registers than yours, you can loose the most critical register uses in
>favor of less critical.  For example, let's posit a two register
>machine and the following code
>
>	register int	i, j;
>
>	for (i = 0; ...)
>		for (j = 0; ...)
>
>Now, move it to a one register machine, and "j", which is the most
>tested variable, is out of a register and "i", which is used less
>often, is still in one.  Not what you want.

You are assuming the compiler assigns register variables in the order
they are declared, which is not always true.  An alternative solution
is to do something like this:

#define REG1 register
#define REG2 register
 ...
#define REG8 register                /* assume 8 registers on our machine */
#define REG9
 ...
#define REG20                        /* but up to 20 variables that might */
				     /* be put into registers */

Then declare the local variables as

  REG1 int j;     /* j is most important */
  REG2 int i;     /* i is next most important */
  ...

The register #defines can go in a header file that uses #ifdefs to
do the #defines appropriately for the machine you are using.  This
method makes it clear which variables are important to be placed in
registers and which aren't.

Alex

stew@harvard.ARPA (Stew Rubenstein) (06/26/85)

> In article <472@crystal.UUCP> shekita@crystal.UUCP writes:
> >1) When is it appropriate to declare a variable as a
> >   register? I have been told that declaring a variable 
> >   as a register can actually result in slower code. Is
> >   there a rule of thumb dictating when and when not to
> >   declare a variable as a register?
> 
> Generally, the only time declaring a variable to be a register
> generates slower code is when you declare a parameter to be a
> register.  This is because, on most systems, this requires a move from
> the stack into a register.  If the variable is rarely used, this
> overhead may cost you more than having it in the register saves.

This is not always true.  On many (most?) systems, the use of a register in a
subroutine requires that the register be saved before use and restored
before return.  So you get:

   Move register onto stack
   If a parameter or initialized auto then move initial value into register
   Do your subroutine
   Move saved value back into register

On the vax, the register is saved and restored by the CALL instruction,
but it still takes time.

jmoore@mips.UUCP (Jim Moore) (06/26/85)

> You have an infinite number of registers.  No, seriously, this is the
> way to think about it.  You should declare EVERYTHING which you don't
> have to take the address of to be a register. [...] Just be somewhat
> careful to declare things in the order you care about.

This is the method I always use in the procedures I write. I am
accustomed to programming a 68k based machine and it does not take
many references to a variable to justify any additional cost in making
it a register on that architecture.

Using this declaration method seems to be saying that the register
hint given the compiler contains no information (other than promising
not to take its address). What I really want is for the compiler to
assign as many variables to registers as it can. I would also like it
to assign to "right" variables to registers, including globals.
In this scenerio, register declarations should act as over-rides to
the compilers register allocation policy. This would result in code
with fewer register declarations, but with more information contained
in each one.

Jim Moore
MIPS Computer Systems
Mountain View, CA
ucbvax!decwrl!mips!jmoore

braun@drivax.UUCP (Karl Braun) (06/26/85)

Ken Arnold presented the following example while talking about the necessity
of proper ordering when declaring register vars.  

> 
> 	register int	i, j;
> 
> 	for (i = 0; ...)
> 		for (j = 0; ...)
> 

It made me wonder if the following version would be any more efficient:

	register int	i ;

	for( i = 0 ; ... )
	{
		register int	j ;

		for( j = 0 ;... )
	}

-- 
			kral
ihnp4!-------- \
mot! ---------- \
ucbvax!unisoft!  >	drivax!braun
ucscc!--------- /
amdahl!------- /

arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (06/27/85)

In article <6115@ucla-cs.ARPA> alex@ucla-cs.UUCP writes:
>>Just be somewhat careful to declare things in the order you care
>>about.  This cuts both ways -- if you move to a machine with fewer
>>registers than yours, you can loose the most critical register uses in
>>favor of less critical.  For example, let's posit a two register
>>machine and the following code
>>
>>	register int	i, j;
>>
>>	for (i = 0; ...)
>>		for (j = 0; ...)
>>
>>Now, move it to a one register machine, and "j", which is the most
>>tested variable, is out of a register and "i", which is used less
>>often, is still in one.  Not what you want.
>
>You are assuming the compiler assigns register variables in the order
>they are declared, which is not always true.

It SHOULD always be true.  If a compiler doesn't put things in
registers in the order declared, it is not following (a) standard
practice, or (b) K&R (the closest thing we currently have to a
standard).  K&R says

	A "register" declaration is best thought of as an "auto"
	declration, together with a hint to the compiler that the
	varibles declared will be heavily used.  Only the first few
	such declarations are effective.

"first few" means "first few".  In the above listing, "i" comes before
"j" and therefore is part of the "first few" before "j" is.  Any compiler
which puts "j" in first is doing it wrong.

		Ken Arnold

mhs@enmasse.UUCP (Mike Schloss) (06/27/85)

> Speaking of register variables -- does anybody know what various C
> compilers do when you don't declare variables as register, but there
> are spare registers to use? From what I hear, neither ccom nor c2 are
> smart enough to put local variables in registers when they are
> available. It seems that it would be simple to just take the first few,
> or even the most heavily used local variables that don't ever get &'d
> and make them register...
> 
> 	Wayne

Easier said than done.  For example, what do you mean by most heavily used?
Do you mean occurs most often in the code or encountered more often during
execution.  Assume two variables, one with 16 references in the first half
of the routine and none in the second half, another variable with only one
reference in the second half, in a loop, where the program spend 98% of its
time.  Get the picture?  Also the is some cost to using registers, the
overhead of storing and restoring them.  A compiler does not know about
execution paths so it can not deal with this properly.  Better left to the
programmer who shoud know better about variable usage and possible input data.

maxwell@speedy.DEC (06/28/85)

It's a  shame  that  we're  all  too  often  hampered  by  the  lack of good
optimizing compilers.

The only  reason that K&R's C *has* register variables in the first place is
because their  original  C  compiler  (and  most  later ones) can't generate
reasonable  code without (and often even with) them. These compilers require
'hints'  about  variable  use.  The trouble is, many compilers take the hint
indiscriminatly,  without  regard  for  the  program itself. (The variety of
assignment operators are there for the same reason).

The 'register'  storage  class  qualifier should generally be *ignored* by a
good  compiler:  the  compiler  should  place values (and not just variables
necessarily, but common subexpressions as well) in registers as it sees fit.
E.g. a  compiler  can  realize  that  a  variable  is used inside a loop and
generate code accordingly, etc.

Not to  blow  DEC's  horn  too  loudly,  but  the VAX C compiler *is* a good
compiler,  at  least  by  this  definition.  Declaring a variable 'register'
increases  the likelyhood of that variable getting a register (increases its
priority); but  generally  the compiler keeps track of variable usage (up to
32  of them) and generates code according to their use. 'register' variables
are otherwise treated *exactly* like regular 'auto' ones.

For those who might be interested, the compiler technology used by the VAX C
compiler is described in "Engineering a Compiler: VAX-11 Code Generation and
Optimization",  Digital  Press.  Perhaps PCC (et al) users should read books
like this and rewrite a few compiler backends.

-+- Sid  "some of my best friends write compilers" Maxwell, DEC @ Spit Brook
Rd, Nashua NH

"I seriously  doubt that the opinion, as expressed in the preceding message,
is necessarily shared by anyone else, including my employer. So there."

pritch@osu-eddie.UUCP (Norman Pritchett) (06/30/85)

Just for the sake of information, VMS ignores register declarations and
automatically decides for itself how frequently you use each variable and
whether or not to make it a "register declaration".  I personally don't
think this is the wisest approach but after looking at a number of machine
code listings it actually appears to work well under most conditions.

> > From: shekita@crystal.UUCP
> >
> > How many variables can be declared as registers on a Vax 780? In
> > general, is there some way to tell how many register variables can
> > be declared?
> 
> Depends on the compiler.  Most Unix compilers have 6 registers on
> Vaxen (r11-r6).  VMS uses r12-r2 (!), though I don't know how their
> compiler reacts to register declarations.  Sun's C compiler has 4
> register pointers (a5-a2) and 6 register integers (d7-d2).  (I think.)
> -- 
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
> UUCP:	seismo!umcp-cs!chris
> CSNet:	chris@umcp-cs		ARPA:	chris@maryland

-- 
-----------------------------------
Norm Pritchett
UUCP:   cbosgd!osu-eddie!pritch
CSNET:  pritch@ohio-state
BITNET: TS0017 at OHSTVMA
MA-NET: (614) 291-8775

ps@celerity.UUCP (Pat Shanahan) (07/01/85)

> Speaking of register variables -- does anybody know what various C
> compilers do when you don't declare variables as register, but there
> are spare registers to use? From what I hear, neither ccom nor c2 are
> smart enough to put local variables in registers when they are
> available. It seems that it would be simple to just take the first few,
> or even the most heavily used local variables that don't ever get &'d
> and make them register...
> 
> 	Wayne

Release 2.1 of the Celerity C1200 C compiler implements simple automatic
register allocation for  optimized compiles. Declared register variables
have priority for allocation of registers. The remaining registers are
allocated for an arbitary selection of the simple automatic variables,
excluding any that have their addresses calculated.

Automatic register allocation is particularly important for the C1200,
because it provides an unusually large number of registers and a wide range
of types of register variables. The C1200 supports all integer types and
both floating point types in registers. Depending on the number of registers
that the function needs for arguments, up to 26 integer registers can be
allocated. The C1200 also has 15 floating point registers, of which the C
compiler will allocate up to 9 for variables. Each floating point register
can contain either a float or a double. This large supply of registers is
very desirable for big FORTRAN subroutines.

The C compiler makes no attempt to do usage based allocation and allocates
registers for the whole scope of the variables, since the number of
registers exceeds the number of suitable variables in most C functions. For
example, all suitable automatic variables in the C compiler first pass fit
into registers.

Excessive register allocation is not a concern on the C1200, because the
architecture supports rapid saving and restoring of blocks of registers. 

The C1200 C compiler first pass user time improved by 5% due to automatic
register allocation. This is probably typical of UNIX code that already has
many register declarations, and that does not use floating point much. The
largest improvement I have seen so far was in a small artificial benchmark.
The user time reduced from 13.4 seconds to 8.6 seconds. Obviously, there
would be no improvement in a program that already had all possible variables
declared register.

-- 
	ps
	(Pat Shanahan)
	uucp : {decvax!ucbvax || ihnp4 || philabs}!sdcsvax!celerity!ps
	arpa : sdcsvax!celerity!ps@nosc

brooks@lll-crg.ARPA (Eugene D. Brooks III) (07/02/85)

> Just for the sake of information, VMS ignores register declarations and
> automatically decides for itself how frequently you use each variable and
> whether or not to make it a "register declaration".  I personally don't
> think this is the wisest approach but after looking at a number of machine
> code listings it actually appears to work well under most conditions.

The Tartan C compiler for vaxen seems to do equally well with register
allocation for frequently used variables.  I don't know if they pay any
attention to register declarations.

Forced register declarations are useful in their own right.  Sometimes
its its quite convenient to use register declarations and asm statements
here and there to cheat the compiler.  It certainly beats writing whole
modules in assembler.

YEA! I KNOW! All you people out there in netland are saying "GAG ME WITH
A SPOON!"  For sure, for sure.

brent@cadovax.UUCP (Brent Rector) (07/02/85)

In article <421@osu-eddie.UUCP> pritch@osu-eddie.UUCP (Norman Pritchett) writes:
>Just for the sake of information, VMS ignores register declarations and
>automatically decides for itself how frequently you use each variable and
>whether or not to make it a "register declaration".  I personally don't
>think this is the wisest approach but after looking at a number of machine
>code listings it actually appears to work well under most conditions.
>
>Norm Pritchett
>UUCP:   cbosgd!osu-eddie!pritch

So what happens then if you are frequently referencing a memory mapped
device register, will the VMS compiler cache the first reference in a
register?  (Note that I am aware of the proposed 'volatile' definition
in the standard).  Or can you tell the compiler to listen to register
definitions in certain cases.

-- 
--------------------------------------------------------------
Brent E. Rector - CONTEL CADO, Torrance, CA
{ decvax, hplabs, ihnp4, ucbvax, sdcrdcf }!trwrb!cadovax!brent
					 philabs!cadovax!brent

eds@solar.UUCP (E.SCHULZ) (07/03/85)

In our current application, we are writing C code for an 8086-family
processor in an embedded system.  Our objective is to keep the ROM
and RAM down, so that the components will fit on the board and will
be low cost.  We don't think that execution time is as important as
keeping the ROM under 128K bytes.

Given the above, I would prefer to have the compiler assign register
variable(s) based on their static occurrence in the code.  The
references to memory take more code space than references to
registers.  Just another point of view...

	Ed Schulz
	AT&T-IS, Holmdel, NJ
	solar!eds  (201)834-3838

rcd@opus.UUCP (Dick Dunn) (07/04/85)

> I have to admit to getting into the sloppy habit of stopping after
> six register declarations.  But that's not why I'm writing this.
> . . what I really want to do is make another point here, and that
> is that you should declare register variables before ordinary
> variables (in general), since some machines (Pyramids) ignore the
> word ``register'' and just put the first N (12) variables in
> registers.  (Such a machine must, of course, be able to take the
> address of a register.)

Sounds like the Pyramid compiler has a problem there, to the extent that
it's not following the spirit of the `register' declaration.  Who ever said
that "order of declaration" is a hint to the compiler on which variables
are most frequently used?!

Also, it's not generally possible to declare register variables before
ordinary variables--parameters are effectively just initialized local
variables, but the syntax requires that they all be declared before any of
the locals.  The parameter-vs-local distinction is another reason that
compilers ought not to do what the Pyramid compiler is described as doing.
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...A friend of the devil is a friend of mine.

chris@umcp-cs.UUCP (Chris Torek) (07/05/85)

> Sounds like the Pyramid compiler has a problem there, to the extent that
> it's not following the spirit of the `register' declaration.

It *is* kind of tacky.  It works, though.

> Also, it's not generally possible to declare register variables before
> ordinary variables--parameters are effectively just initialized local
> variables, but the syntax requires that they all be declared before any of
> the locals.  The parameter-vs-local distinction is another reason that
> compilers ought not to do what the Pyramid compiler is described as doing.

Actually, since on Pyramids the first 12 arguments to a procedure
are already in registers (different from the 12 local registers)
this doesn't matter.  Again it just ignores the register declarations,
this time because of the subroutine call architecture.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

stern@bnl.UUCP (eric) (07/07/85)

> In article <421@osu-eddie.UUCP> pritch@osu-eddie.UUCP (Norman Pritchett) writes:
> >Just for the sake of information, VMS ignores register declarations and
> >automatically decides for itself how frequently you use each variable and
> >whether or not to make it a "register declaration".  I personally don't
> >think this is the wisest approach but after looking at a number of machine
> >code listings it actually appears to work well under most conditions.
> >
> >Norm Pritchett
> >UUCP:   cbosgd!osu-eddie!pritch
> 
> So what happens then if you are frequently referencing a memory mapped
> device register, will the VMS compiler cache the first reference in a
> register?  (Note that I am aware of the proposed 'volatile' definition
> in the standard).  Or can you tell the compiler to listen to register
> definitions in certain cases.
> 
> -- 
> --------------------------------------------------------------
> Brent E. Rector - CONTEL CADO, Torrance, CA
> { decvax, hplabs, ihnp4, ucbvax, sdcrdcf }!trwrb!cadovax!brent
> 					 philabs!cadovax!brent

The VAX-11C compiler already supports volatile declarations, as
well as variables defined in readonly storage.  In addition,
to avoid allocating program sections (of which there are a
limited number), You can define entry points in your program,
and reference entry points in other programs.  This last feature
is only of use under VMS, since the concept of external names
is totally different between VMS and Unix.


					Eric Stern
					stern@bnl.arpa
					stern@bnl.bitnet
					stern@bnldag.bitnet (new)
					...!philabs!sbcs!bnl!stern

stpeters@steinmetz.UUCP (R L StPeters) (07/09/85)

> The 'register'  storage  class  qualifier should generally be *ignored* by a
> good  compiler:  the  compiler  should  place values (and not just variables
> necessarily, but common subexpressions as well) in registers as it sees fit.
> E.g. a  compiler  can  realize  that  a  variable  is used inside a loop and
> generate code accordingly, etc.

Compilers that use register variables as they see fit can add much to the
overhead of function calls due to large register masks.  This was the only
reason we could figure for a friend's program's execution time being about
twice as long when compiled with the VAX-11 C compiler as when compiled
with our Interactive Systems' IS/1 compiler (multiple comparison runs on
the same 11/782/VMS system under the same average load conditions).

His program spent much of its time calling several fairly large procedures
isolated in a module.  These were called thousands of times and usually
simply returned after making one simple comparison, but occasionally they
did something complex.  This happened seldom enough so it mattered little
whether they used register variables.  The DEC-compiled version apparently
spent an awful lot of time just saving and restoring unchanged registers.

I don't know if he ever tested it using the /noptimize qualifier.  He
just went back to the IS/1 compiler.  It ran fast enough.

Personally, I have a problem with compilers that decide on their own
that something I tell them should be *ignored*.  The VAX-11 C compiler's
optimization has made a number of my own procedures not work.  But then
I have a habit of doing in C things that a compiler-writer might think
god intended to be done only in assembly language.

-- 
R. L. St.Peters (Dick)        The "R" is for "Reptile".
uucp: decvax!mcnc!ncsu!uvacs!edison!steinmetz!stpeters (uucp is forever)
arpa: stpeters@ge-crd                                  (federal express)
	"Any opinions expressed by my employer are probably not mine."

atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (07/17/85)

The semantic meaning of a "register" declaration is NOT that the compiler
must place the variable in a register.  Instead if you stop to think
it is really a declaration that this variable is never affected as a
side effect of an indirect store (* or []), an so a copy of the variable
in a register can still be believed.  The "register" declaration
should really only be interpreted in this sense, even though some compilers
decide to always keep the first few such variables in registers.  Compilers
that do such are not in violation of this interpretation, but are taking
an unneccessarily narrow interpretation, and as a result some times
produce worse code since they lose the use of extra registers when
they would be most useful.  "register" is supposed to be an optimizing
HINT, not suboptimal code requirement.

lcc.niket@UCLA-LOCUS.ARPA (Niket K. Patwardhan) (07/19/85)

>The semantic meaning of a "register" declaration is NOT that the compiler
>must place the variable in a register.  Instead if you stop to think
>it is really a declaration that this variable is never affected as a
>side effect of an indirect store (* or []), an so a copy of the variable
>in a register can still be believed.  The "register" declaration

I never thought of it that way before, but you are right. Interesting......
using register declarations can make a C program much more provable!!!!
:x