[comp.lang.c] The &

rang@cpsin3.cps.msu.edu (Anton Rang) (12/03/88)

I was thinking about RISC machines, and other machines with a lot of
registers, and came up with a question.  Since the C language doesn't
have call-by-reference, is it possible to allocate variables which are
passed by reference into registers?
  For example, the C code:

	scanf("%d", &N);

  would require that the address of N be taken to read it from the
standard input.  If I then have a loop:

	for (i=0; i<N; i++) { ... }

would the final program have to read N from memory each time?  Or does
the C standard provide that some keyword (like 'volatile') be used to
avoid possibly unsafe optimizations (like moving N into a register in
the above example--the address of N could have been saved in scanf() ).
  Are there any architectures which allow taking the "address" of a
register (say, having a reserved page)?

+---------------------------+------------------------+----------------------+
| Anton Rang (grad student) | "VMS Forever!"         | "Do worry...be SAD!" |
| Michigan State University | rang@cpswh.cps.msu.edu |                      |
+---------------------------+------------------------+----------------------+

tim@crackle.amd.com (Tim Olson) (12/03/88)

In article <1224@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
| I was thinking about RISC machines, and other machines with a lot of
| registers, and came up with a question.  Since the C language doesn't
| have call-by-reference, is it possible to allocate variables which are
| passed by reference into registers?
|   For example, the C code:
| 
| 	scanf("%d", &N);
| 
|   would require that the address of N be taken to read it from the
| standard input.  If I then have a loop:
| 
| 	for (i=0; i<N; i++) { ... }
| 
| would the final program have to read N from memory each time? Or does
| the C standard provide that some keyword (like 'volatile') be used to
| avoid possibly unsafe optimizations (like moving N into a register in
| the above example--the address of N could have been saved in scanf() ).

On most RISC machines (CRISP is the only exception I can think of, but
then it doesn't really have registers), taking the address of a local
variable results in that variable residing in the memory stack rather
than registers.  However, it is not necessarily the case that the
variable has to be read from memory if it is used in a loop.  If there
are no function calls or stores through pointers in the loop, then a
compiler is free to cache the value of the variable in a register. 
However, it normally must re-read the value from memory each time if
there is a function call or a pointer store.  The reason is that the
address of the variable was passed to an external function, and the
compiler does not (normally!) know what that function did with it.  It
may have assigned it to a global variable, causing *every* function to
have a potential alias to the "local" variable which had its address
taken. In that case, any function call has the possibility of modifying
the local variable, so it must be re-read from memory.  This is the type
of thing that the proposed "noalias" keyword for ANSI C was trying to
address (no pun intended ;-)

"Universal" optimizing compilers that perform inter-procedural
assignment-tracking may be able to determine that the variable is not
aliased, and therefore is free to be cached.


	-- Tim Olson
	Advanced Micro Devices
	(tim@crackle.amd.com)

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/03/88)

In article <1224@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>	scanf("%d", &N);
>	for (i=0; i<N; i++) { ... }
>would the final program have to read N from memory each time?  Or does
>the C standard provide that some keyword (like 'volatile') be used to
>avoid possibly unsafe optimizations (like moving N into a register in
>the above example--the address of N could have been saved in scanf() ).

Trying to answer what it is that I think you're really asking:

1.  The C compiler code generator must allocate actual (non-register)
storage for anything whose address is needed, so in the above example
N's primary definition must be in addressable memory.  However, a good
optimizer can copy that location into a register for the loop test, and
if nothing inside the loop could possibly (according to the C virtual
machine model) alter the contents of N, it need not reload that cached
value from memory for each test.  There are optimizers that do this.

2.  scanf() is required to look at its actual arguments each time it is
called -- that's the whole point of function parameters.

3.  It is true that functions, being separately compilable entities,
can be designed so that they stash away pointers for later use, and
that so-called "aliasing" (multiple possible reference paths to the
same object) is a factor that has to be dealt with when designing a
C implementation.  The best example is a function having two pointer
parameters.  What if it is called with both parameters pointing to
the same object?  The rules of C require that each access via one of
the parameters be considered as "killing" the value accessed via the
other parameter, so that the other must be "reloaded" the next time
it is used.  The ill-fated "noalias" type qualifier was intended to
provide a way for the programmer to promise that such pointers would
NOT access overlapping objects, so that the cached contents accessed
via the two pointers would be known to be independently modifiable
without interfering with each other.  That would have allowed a
higher degree of optimization, especially on vector architectures
like many supercomputers.  As it now stands (without "noalias"), a
conforming implementation must make a worst-case assumption and
handle possible aliasing correctly.  No keyword is needed to specify
this; it's the default (and now the only) behavior.

>  Are there any architectures which allow taking the "address" of a
>register (say, having a reserved page)?

Registers also have memory addresses on some architectures, for example
DEC PDP-11.  I've never heard of a compiler exploiting this.

eric@pyrps5 (Eric Bergan) (12/03/88)

In article <1224@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>  Are there any architectures which allow taking the "address" of a
>register (say, having a reserved page)?

	The Pyramid lets you take the address of a register. Basically
the register windows are mapped into the process address space as part
of the stack. 

elg@killer.DALLAS.TX.US (Eric Green) (12/03/88)

in article <1224@cps3xx.UUCP>, rang@cpsin3.cps.msu.edu (Anton Rang) says:
> have call-by-reference, is it possible to allocate variables which are
> passed by reference into registers?
>   For example, the C code:
> 
> 	scanf("%d", &N);
> 
>   would require that the address of N be taken to read it from the
> standard input.  If I then have a loop:
> 
> 	for (i=0; i<N; i++) { ... }
> 
> would the final program have to read N from memory each time?  

There was a discussion in comp.lang.c about this. There's two ways of
doing this: memory-mapped register set, or "smart" compiler that tries
to optimize register usage, e.g. keeping values in registers as long
as possible, and only dumping them to RAM when necessary for things
like the scanf call above. 
     AMD29000, SPARC, etc. don't have memory-mapped registers, and
thus use at least a semi-intelligent compiler. The Pyramid 90x has
memory-mapped registers. I suspect it's because Pyramid's early "C"
compiler was a bit, err, dumb (their "new" compiler, though, is quite
spiffy, global optimizer and all... I tried hand-tweaking the
assembly-language output once, and for the most part failed to make a
bit of difference).

> | Anton Rang (grad student) | "VMS Forever!"         | "Do worry...be SAD!" |
                                 ^^^^^^^^^^^
                                Gag choke BARF (;-)
--
Eric Lee Green    ..!{ames,decwrl,mit-eddie,osu-cis}!killer!elg
          Snail Mail P.O. Box 92191 Lafayette, LA 70509              
"We have treatments for disturbed persons, Nicholas. But, at least for
the moment, we have no treatment for disturbing persons." -- Dr. Island

henry@utzoo.uucp (Henry Spencer) (12/04/88)

In article <1224@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>... Since the C language doesn't
>have call-by-reference, is it possible to allocate variables which are
>passed by reference into registers?

Within limits.  Barring the possibility that the machine allows pointers
to registers, the requirement is that the register and memory copies track
changes to each other.  This is tricky but not entirely impossible, at
least in restricted cases with some arguably-dubious assumptions.

>...the above example--the address of N could have been saved in scanf()...

The compiler may know that it isn't, since scanf is a standard library
function.  It may even know it for your own functions, if it does fancy
interprocedural analysis.

>  Are there any architectures which allow taking the "address" of a
>register...

The original Berkeley RISC design had registers with addresses, carefully
set up in such a way that you could pass pointers to them around freely.
The idea was to maximize the ability to put local variables into registers.
I don't know of anybody commercial who's copied this idea.
-- 
SunOSish, adj:  requiring      |     Henry Spencer at U of Toronto Zoology
32-bit bug numbers.            | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

henry@utzoo.uucp (Henry Spencer) (12/04/88)

In article <9048@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>... As it now stands (without "noalias"), a
>conforming implementation must make a worst-case assumption and
>handle possible aliasing correctly...

Unless one indicates, in some implementation-dependent way, that it's
not an issue, of course.  Compiler options, #pragma (as near as I can
tell at first glance, the October draft has not outlawed the can-change-
semantics interpretation of #pragma), whatever...

>Registers also have memory addresses on some architectures, for example
>DEC PDP-11.  I've never heard of a compiler exploiting this.

On the 11, it can't, because the registers don't *really* have memory
addresses.  Those "addresses" are good only for use from the front panel,
or emulation thereof.  They don't necessarily work for programs.
-- 
SunOSish, adj:  requiring      |     Henry Spencer at U of Toronto Zoology
32-bit bug numbers.            | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

bcase@cup.portal.com (Brian bcase Case) (12/05/88)

>On most RISC machines (CRISP is the only exception I can think of, but
>then it doesn't really have registers), taking the address of a local
>variable results in that variable residing in the memory stack rather
>than registers.

Some would say that the Pyramid machines stretch the definition of RISC,
but they have large, windowed register files (512) registers and the
registers have memory addresses.

dieter@titan.nmt.edu (The Demented Teddy Bear) (12/05/88)

In article <1988Dec3.221843.28966@utzoo.uucp>,
	henry@utzoo (Henry Spencer) writes:
> The original Berkeley RISC design had registers with addresses, carefully
> set up in such a way that you could pass pointers to them around freely.
> The idea was to maximize the ability to put local variables into registers.
> I don't know of anybody commercial who's copied this idea.

Umm, Henry, doesn't a PDP-10 count?  Seemed kinda like a commercial
system to me....  The registers certainly seemed addressable (hey,
you can even point the PC at them and execute code out of them).

Or have I missed something again?

Dieter
-- 
Welcome to the island.  You are number six.
dieter%nmt@relay.cs.net
dieter@jupiter.nmt.edu