Dealing with the allocation of data temporaries (as opposed to
address temporaries) will be fairly simple in your compiler for
several reasons:
All data register are "equivalent", and
You can't run out of data temporaries because a
memory temporary can always be used if all the
registers are used up (with merely a performance
penalty).
For data temporaries you should use a fairly simple allocation
scheme.
The low-level code generator will provide "get" and
"free" routines that return/expect operand descriptors
for data temporaries.
Your low-level code generator should maintain a table
with one entry for each data register indicating whether
it is used of free.
When memory temporaries are used and freed, the allocator
should reuse freed slots rather than always
"bumping up the stack pointer".
To do this, maintain a list of freed memory temporaries.
When "get" is called:
First look for a free data register,
Next, look for a freed memory temporary,
If all else failed, bump up the procedure's
local variable space size to make room for an
additional memory temporary.
When "free" is called:
If operand is a constant just free descriptor memory,
If operand is a register, update free register table, or
If operand is a memory temporary, add it to the list
of free temporary locations.
Later in the semester, we will want to know which operand
is in which register (as opposed to which register each
operand is in). In preparation for this, you should
keep a pointer to the operand descriptor using each data
register within your data register status table.