Register variables

R

Roberto Waltman

Keith Thompson said:
I just tried something similar:
================================
#include <stdio.h>

void set_registers(void)
{
register int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
x0 = 100;
x1 = 101;
x2 = 102;
x3 = 103;
x4 = 104;
x5 = 105;
x6 = 106;
x7 = 107;
x8 = 108;
x8 = 109;
^
x9 not initialized.
Your findings are still valid.
}

void read_registers(void)
{
register int y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
printf("%d %d %d %d %d %d %d %d %d %d\n",
y0, y1, y2, y3, y4, y5, y6, y7, y8, y9);
}

int main(void)
{
set_registers();
read_registers();
return 0;
}
================================

On most compilers and platforms, I got garbage output. But using
Sun's C compiler on Solaris/SPARC, I got the following output:

100 101 102 103 104 105 106 107 -12788660 200

Apparently the compiler re-used the same 8 registers for the first 8
"register" variables in each function, and didn't clobber them between
the calls.

You could do the same thing using something like "static register"
variables if there were such a thing.

Yes. I thought of the similarity to global/static variables in a
previous post. Did not mention it because I was not sure if the
analogy breaks somewhere.

Roberto Waltman

[ Please reply to the group,
return address is invalid ]
 
I

Ian Collins

Keith said:
I just tried something similar:
================================
#include <stdio.h>

void set_registers(void)
{
register int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
x0 = 100;
x1 = 101;
x2 = 102;
x3 = 103;
x4 = 104;
x5 = 105;
x6 = 106;
x7 = 107;
x8 = 108;
x8 = 109;
}

void read_registers(void)
{
register int y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
printf("%d %d %d %d %d %d %d %d %d %d\n",
y0, y1, y2, y3, y4, y5, y6, y7, y8, y9);
}

int main(void)
{
set_registers();
read_registers();
return 0;
}
================================

On most compilers and platforms, I got garbage output. But using
Sun's C compiler on Solaris/SPARC, I got the following output:

100 101 102 103 104 105 106 107 -12788660 200

Apparently the compiler re-used the same 8 registers for the first 8
"register" variables in each function, and didn't clobber them between
the calls.

You could do the same thing using something like "static register"
variables if there were such a thing.
That'll be the working registers on the second spoke of the register wheel.

With SPARC, the each function call level (up to in implementation
defined limit) has in, working and out registers. The out registers
from one level become the in for the next, enabling some parameters to
be passed without using the stack.
 
G

Guest

Thanks, I did some time ago. The two versions in Mr. Ritchie's page
predate the introduction of the "register" keyword. (Keyword list is
initialized in c00.c) I guess the expression I used, "original C
compiler", is to vague.

OK, here are some later versions. The v5 version of c00.c has the
register keyword. (I already had it on my system) I didn't check any
of the others.
http://mirror.cc.vt.edu/pub/projects/Ancient_Unix/PDP-11/Distributions/research/

<snip>

I started here: http://minnie.tuhs.org/PUPS/ to get to the above. They
have lots of old stuff.
 
D

Dennis Ritchie

.....
Maybe I am not thinking about this correctly, but I don't see how these
register variables [in V7 C] could possibly be used to return values?
When the
function returns, the register preservation mechanism would overwrite
the registers with their original values would it not?

You're thinking correctly. The call mechanism saved all 3 possible
register variables (no matter how many were in use), and
always restored them. Thus, by chance, you could pass
values in registers as was illustrated, but not get new values back.

Dennis
 
B

Bill Leary

Roberto Waltman said:
Which reminded me of the following. (Can anybody confirm this?
I can not find the original reference.)

I've seen something like this, but perhaps not exactly what you're
remembering.
I read that this compiler had a very simple approach for handling
register declarations. Three of the CPU registers were reserved for
this purpose. The first three variables declared as 'register' were
assigned to them in the order of declaration. Any more were ignored.
Yes.

The contents of these registers was preserved across function calls,
making possible to use register declarations as an alternate parameter
passing mechanism without the overhead of pushing/popping data to the
stack, and it was inevitably used in this fashion by people wanting to
squeeze more performance from the system.

In the case I'm remembering, the registers were pushed onto the stack, but
their former values remained. If the registers variables in the called
function were declared without initialization, they retained, positionally,
their previous values. So, you could get away with what you showed in yoru
code snippet. However, the results of any processing on them was lost on
exit from the function when the previous values were popped from the stack
on exit.

Thus:
f1() {
register a1, b, c;
a = 10; b = 20; c = a + b
f2()
printf("%d %d %d\n", a, b, c);
}

f2() {
register d, e, f;
printf("%d %d %d\n", d, e, f);
d++; e++; f = d + e;
printf("%d %d %d\n", d, e, f);
}

Produced:
10 20 30
11 21 33
10 20 30

Is that similar to what you're remembering?

Even more, the compiler had an automatic register optimization feature.
When this was turned on, the most often used local variables in the function
were put in registers. So, in the above, you could turn on this switch and
omit the "register" key word and get the same results. This was on a
MC68000 compiler I used in the 80's

- Bill
 
T

Tore Sinding Bekkedal

Even more, the compiler had an automatic register optimization feature.
When this was turned on, the most often used local variables in the function
were put in registers. So, in the above, you could turn on this switch and
omit the "register" key word and get the same results. This was on a
MC68000 compiler I used in the 80's

Yes, I believe most modern compilers discard the "register" directive
entirely, because it thinks it knows best. I was surprised the Sun one
didn't.

I guess that to reproduce-ish this, you could find out if there are
any registers the compiler doesn't touch or such, and do inline ASM
storing and retrieval of these... Ugh. :)

-Tore
 
B

Bill Leary

Tore Sinding Bekkedal said:
Yes, I believe most modern compilers discard the "register" directive
entirely, because it thinks it knows best. I was surprised the Sun one
didn't.

I've read the internals notes on a number of compilers and have seen that
some say they permit, but don't utilize, "register." What most of them seem
to say is that they "optimize" or "attempt to optimize" access to variables
declared with "register." They don't actually say they'll use a register
for such a variable.

For embedded system compilers, the Metrowerks we use for Coldfire, for
example, there are explicit notes on how many register variables are
recognized. If I'm recalling correctly, the first seven integers and the
first three pointers declared with "register" are actually put in CPU
registers.
I guess that to reproduce-ish this, you could find out if there are
any registers the compiler doesn't touch or such, and do inline ASM
storing and retrieval of these... Ugh. :)

Thanks, no.

- Bill
 
T

toby

Thanks, I did some time ago. The two versions in Mr. Ritchie's page
predate the introduction of the "register" keyword. (Keyword list is
initialized in c00.c) I guess the expression I used, "original C
compiler", is to vague.



Not that I am recommending to do this, but this would have been a
"very useful arrangement" in systems with very limited resources.
Not different in principle from people finding out what unused opcodes
do in a processor and, against all logic, using them in their code.
There were times when 24K words was considered a lot of memory, and
instruction execution times were measured in microseconds, not
nanoseconds.


If these registers were indeed preserved across function calls, values
could have been transferred in both directions. I wrote "could have"
instead of the more definite "would have" because flow analysis could
allow reusing the register for a different purpose, although I doubt
these compilers did that.


Of course, guilty on all counts ...

Almost. If I read you right, one mechanism falls into the "dirty
tricks" category, but is still (atrociously non portable) C:
exploiting that the callee's register variables overlap the caller's,
effectively passing some parameters in registers as initial values.

Even on the PDP-11 this doesn't seem much of a coup - you might avoid
a stack push and pop, but it also somewhat constrains the callee's use
of the variables in question. (In C, these registers would also still
have to be preserved across the call, precluding returns.)

But "scratch" register *variables* potentially clobbered by function
calls would not be "C", nor re-entrant.

Have I got this right?
Roberto Waltman

[ Please reply to the group,
return address is invalid ]
 
T

toby

This much is true. As C spread to other platforms, this meant that
the first N register declarations were obeyed (for some
machine-specific N),and the rest ignored.

There was a hilarious sequence of benchmarking dirty tricks that
turned up on usenet sometime in the early 1980s:

Intel fan: my machine is faster than Motorola, on the basis of my
benchmark.

Motorola fan: no fair! you didn't use register variables. Now that
I've put all the variables in registers, my machine is faster.

Intel fan: no fair! the order of the variables didn't put the
most-used ones first! I reorded the variable declarations and now my
machine is faster!

I don't remember if there was another round.

The Dhrystone benchmark famously attracted a lot of dirty tricks and
compiler special-casing, since it was almost uselessly simpleminded.
I'm sure other a.f.c regulars can supply spicy details.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top