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:

  1. 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.

  2. 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.
  3. 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.
  4. 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.
  5. 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.