Professional Documents
Culture Documents
A=B
load r0, ads A
load r1, val B
store r1, (r0) ;; r1 --> (r0)
One can see that the main difference is that registers must be allocated, for example, r0 is used
to store temporary result while in stack machine the temporary storage is implicit.
Calling subroutines
The stack structure also plays an important role in the calling of subroutines (or function calls).
When a program transfers the control to another section of program, the current state of
computation is saved (composed of Program Counter, local variables, and other values). The
place where the state of computation is saved is called 'activation record'. When an execution of a
subroutine is completed the previous state of computation is restored (this action is called 'return
from subroutines'). Because many of today programming languages are 'structured' or 'block
oriented' the creation and deletion of activation records behave like LIFO. Stack is used to store
activation records.
These are just some of the possible instructions. An example of their use:
f(X,Y) = X*X + Y*Y
X and Y are the top two items on computation stack when call f().
dup mul ;; X*X
swap ;; Y, X*X
dup mul add ;; Y*Y + X*X
Thinking about rearranging items on stack make it difficult to use pure stack instructions. Having
variables avoids the reordering of items on stack because a variable can be accessed by using
its name. However, current compilation techniques can handle the ordering of stack items
therefore it frees a programmer from this low level detail.
Stack machines have much smaller instructions than the other styles of machines. Loads and stores
to memory are separate and so stack code requires roughly twice as many instructions as the
equivalent code for register machines. The total code size (in bytes) is still less for stack machines.
Simple compilers
Compilers for stack machines are simpler and quicker to build than compilers for other machines.
Code generation is trivial and independent of prior or subsequent code.
Simple interpreters
Some stack machine instruction sets are intended for interpretive execution of a virtual machine,
rather than driving hardware directly. Interpreters for virtual stack machines are easier to build than
interpreters for register or memory-to-memory machines; the logic for handling memory address
modes is in just one place rather than repeated in many instructions.
A virtual machine (VM) is a high level abstraction on top of the native operating system, that
emulates a physical machine. Here, we are talking about process virtual machines and not system
virtual machines. A virtual machine enables the same platform to run on multiple operating systems
and hardware architectures. The Interpreters for Java and Python can be taken as examples, where
the code is compiled into their VM specific bytecode.
A stack based virtual machine implements the general features described as needed by a virtual
machine in the points above, but the memory structure where the operands are stored is a stack
data structure. Operations are carried out by popping data from the stack, processing them and
pushing in back the results in LIFO (Last in First Out) fashion.
In the register based implementation of a virtual machine, the data structure where the operands
are stored is based on the registers of the CPU. There is no PUSH or POP operations here, but the
instructions need to contain the addresses (the registers) of the operands. That is, the operands for
the instructions are explicitly addressed in the instruction, unlike the stack based model where we
had a stack pointer to point to the operand.
The problem with a register based model is that the average register instruction is larger than an
average stack instruction, as we need to specify the operand addresses explicitly. Whereas the
instructions for a stack machine is short due to the stack pointer, the respective register machine
instructions need to contain operand locations, and results in larger register code compared to stack
code.
Since there are no operand fields to decode, stack machines fetch each instruction and its operands
at same time. Stack machines can omit the operand fetching stage of a register machine.
Some in the industry believe that stack machines execute more data cache cycles for temporary
values and local variables than do register machines.
On stack machines, temporary values often get spilled into memory, whereas on machines with
many registers these temps usually remain in registers. (However, these values often need to be
spilled into "activation frames" at the end of a procedure's definition, basic block, or at the very
least, into a memory buffer during interrupt processing). Values spilled to memory add more cache
cycles. This spilling effect depends on the number of hidden registers used to buffer top-of-stack
values, upon the frequency of nested procedure calls, and upon host computer interrupt processing
rates.
In register machines, a common subexpression (a subexpression which is used multiple times with
the same result value) can be evaluated just once and its result saved in a fast register. The
subsequent reuses have no time or code cost, just a register reference. This optimization speeds
simple expressions (for example, loading variable X or pointer P) as well as less-common complex
expressions. With stack machines, in contrast, this is not feasible.
Hybrid machines
Pure stack machines are quite inefficient for procedures which access multiple fields from the same
object. A common fix for this is to add some register-machine features to the stack machine: a
visible register file dedicated to holding addresses, and register-style instructions for doing loads and
simple address calculations. It is uncommon to have the registers be fully general purpose, because
then there is no strong reason to have an expression stack and postfix instructions.
Discussion
Stack machines are arguable almost the simplest kind architecture. Its LIFO structure is quite
suitable for block-oriented language. The code size for a stack machine can be very compact
because most instructions have no operand field. Stack architecture used to be very popular
method to implement high level language machine. Most of modern register machines are faster
but there is some 'renewal' effort to improve stack architecture.