Skip to content
Will Clinger edited this page May 26, 2016 · 3 revisions

Fence/ARMv7 code generator

For now, we're just using the 32-bit instruction set.

The ARMv7 code generator is in pretty good shape, but it's starved for registers. The first four arguments to a procedure are passed in hardware registers REG1 through REG4, but all other arguments are passed as a list in REG5. Adding two or three more argument registers should help a lot.

On Linux, which is the only OS for which we're creating an ARM public release, it should be possible to add two or three more argument registers.

For other platforms, the conservative approach taken by Lars's original register assignment is the safest way to go.

So we probably want to refactor the ARMv7 code generator, using a Linux-specific register assignment for Linux and the conservative register assignment for all other target operating systems. The code generator proper is already almost independent of the register assignment, but some conditional compilation will be needed for millicode and for the compiler; we already have some infrastructure in place for that, and this will give us incentive to clean up that infrastructure.

We should be able to build and test both register assignments under Linux.

There are 13 general purpose 32-bit registers (R0-R12) along with three more (R13-R15) that have special names and purposes. Based on Lars's notes in src/Asm/Fence/pass5p2-arm.sch, the the ARMv7 architecture reference manuals, and the Procedure Call Standard for the ARM Architecture (AAPCS), the registers are intended to be used as shown below. The last two columns show Larceny's existing conservative register assignment and my proposed Linux-specific assignment:

     typical use             conservative    Linux-specific
r0   a1                         RESULT          REG0
r1   a2                         SECOND          REG1
r2   a3                         GLOBALS         REG2
r3   a4                         STKP            REG3
r4   v1                         TMP0            REG4
r5   v2                         REG0            REG5
r6   v3                         REG1            REG6
r7   v4                         REG2            REG7
r8   v5                         REG3            REG8
r9   v6 or (static base)                        GLOBALS
r10  v7                         REG4            RESULT
r11  v8                         REG5            SECOND
r12  IP  scratch                TMP1            TMP0
r13  SP  stack pointer                          STKP
r14  LR  link register                          TMP1
r15  PC  program counter

a1 through a4 are caller-save registers used to pass arguments and return results. v1 through v8 are callee-save registers, except r9 (v6) is the "platform register" that may be reserved for some special purpose. Linux apparently does not reserve register r9. The gcc compiler uses r9 as a static base register when compiling position-independent code, but that usage does not preclude other uses in code compiled by Larceny's compiler.

The AAPCS explicitly sanctions private calling conventions but also says stack invariants must be preserved. The stack must always be word-aligned (multiple of 4) and must be double-word-aligned (multiple of 8) at a "public interface"; the generic Fence code generator already guarantees double-word alignment. We'll need a red zone as well.

Some uses of SP are deprecated, but it looks as though using it as a stack pointer for Larceny's stack cache is within the intended use of the register and should be okay.

Will has built and tested experimental versions of ARM Larceny in which r9 is used as REG3 or REG4 (he's forgotten which) and r12 is used as TMP1, so that much is known to work. Using r13 (SP) as STKP will take a little more work.

Clone this wiki locally