C stack frame sizes

Chris Torek chris at umcp-cs.UUCP
Tue Dec 4 10:18:03 AEST 1984


[Before I begin, I have to add a disclaimer that the information given
here was obtained almost entirely by examining the output of the C
compiler on one particular Pyramid 90-X.  Nothing stated herein should
be taken as official.  End disclaimer.]

The Pyramid is a wonderful machine for exercising ``portable'' C code!
Not only are unions and structs kept only on the stack, the evaluation
order for subroutine calls is different.

First, here's a little bit of information about the hardware
architecture.  There are always 64 registers avaliable at any point in
code.  They are divided into four groups of sixteen registers.  Four
registers in each group are used for special things, so you really wind
up with 12 registers in each group.

-----------------------------------------------------------------

			proc A
			-------
			| pr0 |
			-------
			| ... |
			-------
			| pr15|
			-------
			| lr0 |
			-------
			| ... |
			-------
			| lr15| proc B
			------- -------
			| tr0 | | pr0 |
			------- -------
			| ... | | ... |
			------- -------
			| tr15| | pr15|
			------- -------
				| ... |
				| ... |
				-------
				| tr0 |
				-------
				| ... |
				-------
				| tr15|
				-------

	     Register mapping: proc A calls proc B
			    Figure 1.
-----------------------------------------------------------------

The registers are named by a group description and a number.  The four
groups are "global", "parameter", "local", and "transfer".  The 16
(really 12) global registers, gr0 through gr15 (gr11), are the same in
every procedure; the others are windowed, with some hardware and
software taking care of overflows when calling and returning.  Transfer
registers are used to pass parameters (where they become parameter
registers); parameter registers are used for local parameters and
return values; and local registers are used as in conventional
architectures.  See Figure 1 for a pictorial representation of
parameter, local, and transfer registers.

As shown in Figure 1, a called procedure's registers (the parameter
registers for proc B) and the calling procedure's registers (the
transfer registers for proc A) overlap, allowing the "transfer" of
"parameters" through registers (clever, no?).  Now, of course, only
fixed-size units can be passed via registers; when arrays or other
"large" parameters are passed, conventional mechanisms are used.
(There are no special cases for "small" structures in the present
implementation of the C compiler.)

Now, this presents another problem: what if more than 12 parameters
are passed?  Again, the Pyramid compiler uses conventional mechanisms
-- but only when the first 12 registers are used up.  This means
that if you compile the code

	f() {
		g(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
	}

the last four arguments (12 through 15) are passed on the stack, with
the first 12 (0 through 11) being in the corresponding transfer/parameter
register.

Since the transfer registers are also used as temporary registers when
evaluating expressions, the compiler naturally evaluates parameters
which will be placed on the stack before those that will go into
registers.  As with the Vax compilers, these are evaluated in reverse
order (right to left), so that each can be pushed onto the stack as
soon as the actual value is known.  However, the compiler evaluates the
first 12 parameters left to right!

In other words, the Pyramid compiler evaluates arguments from the
outside in.

----------

By the way, this reminds me of a bug we discovered: if you have a
C function that returns a value which is an expression involving the
first parameter, the compiler accidently clobbers the parameter
before completing the evaluation.  That is, since pr0 (the caller's
tr0) is used hold the return value, someone decided to make it
available for temporary storage, resulting in code like

	get pr0
	mask with 0xff
	shift left 8 bits
	store in pr0		# oops!
	get pr0
	mask with 0xff00
	shift right 8 bits
	or into pr0
	return

for

	return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);

This is not good, to say the least.

----------

[In case you've read this far: we (Maryland) have an info-pyramid mailing
list to discuss anything to do with Pyramid machines; if you'd like to
be added to the list, send mail to info-pyramid-request at MARYLAND.ARPA,
info-pyramid-request at umcp-cs.CSNet, or seismo!umcp-cs!info-pyramid-request.]
-- 
(This line accidently left nonblank.)

In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris at umcp-cs		ARPA:	chris at maryland



More information about the Comp.lang.c mailing list