Ex Bibliotheca
The life and times of Zack Weinberg.
Monday, 11 August 2003
# 6:40 PM
compiler author's advice to CPU designers
This arises out of a discussion a couple weeks back on the
GCC mailing list and IRC channel, where we were talking about
how there isn't much communication between GCC maintainers and
CPU designers, as far as we can tell. We tend to get handed a
finalized instruction set reference and told "make us a back end."
So forthwith what one compiler author (me) would like to say
if he were included in early design discussions for a new CPU
architecture:
- Avoid dedicated, special purpose registers which are relevant to
compiled code generation.
Examples of such include: the link and count registers on the
PPC; the HI and LO multiply-result registers on the MIPS; the
dedicated condition code register on almost all architectures
designed prior to 1985; the stack pointer register on the 8086.
Classes of registers with a dedicated purpose, such as the
predicate registers on the PPC and the Itanium or the floating-point
registers on every architecture ever, are less awkward, but
still not preferred.
It's okay to have special purpose registers that are not of
direct interest to the compiler. For instance, control registers
that will be manipulated only by the operating system are fine.
Yr hmbl crspdt cannot decide whether or not he likes the idea of having
the program counter be a visible integer register (as is done on the
ARM, for instance). On the one hand, it is convenient, in that it
facilitates PC-relative addressing, eliminates the need for a special
category of branch instructions, etc. On the other hand, it does
consume one register. The same is true of the wired-to-zero register
common on RISC architectures; it can be very convenient, but again it
consumes a register.
- Make the
move instruction as general as possible.
Especially, allow move from any register to any other register,
move from any register to memory, and move from memory to any
register. (How the assembly mnemonic is spelled is not
important.) Allow use of all supported addressing modes in all
moves to or from memory.
- Do not expose internal implementation details in the instruction
set. Examples of such exposure include branch delay slots, found
on SPARC, MIPS, etc, and requirements to insert NOPs for correctness,
found on old MIPS and now Itanium. I am personally of the opinion
that windowed register sets (SPARC, Itanium) also fall into this
category, but reasonable people may disagree.
- Make immediate operand fields as wide as possible. This is especially
important for register+offset addressing and relative branch destinations,
but is also desirable for "load immediate" instructions and the like.
- Don't leave out any primitives that you're just going to go back and add
in revision 2. The most common instances of such are integer multiply
and divide instructions, and atomic memory update instructions. Also,
those atomic memory update instructions should be load-linked and
store-conditional, not more limited primitives like test-and-set or
load-and-zero.
|
|