diff options
Diffstat (limited to 'src/cmd/compile/abi-internal.md')
-rw-r--r-- | src/cmd/compile/abi-internal.md | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md index 2bb4055083..3619aea4aa 100644 --- a/src/cmd/compile/abi-internal.md +++ b/src/cmd/compile/abi-internal.md @@ -505,6 +505,128 @@ control bits specified by the ELF AMD64 ABI. The x87 floating-point control word is not used by Go on amd64. +### arm64 architecture + +The arm64 architecture uses R0 – R15 for integer arguments and results. + +It uses F0 – F15 for floating-point arguments and results. + +*Rationale*: 16 integer registers and 16 floating-point registers are +more than enough for passing arguments and results for practically all +functions (see Appendix). While there are more registers available, +using more registers provides little benefit. Additionally, it will add +overhead on code paths where the number of arguments are not statically +known (e.g. reflect call), and will consume more stack space when there +is only limited stack space available to fit in the nosplit limit. + +Registers R16 and R17 are permanent scratch registers. They are also +used as scratch registers by the linker (Go linker and external +linker) in trampolines. + +Register R18 is reserved and never used. It is reserved for the OS +on some platforms (e.g. macOS). + +Registers R19 – R25 are permanent scratch registers. In addition, +R27 is a permanent scratch register used by the assembler when +expanding instructions. + +Floating-point registers F16 – F31 are also permanent scratch +registers. + +Special-purpose registers are as follows: + +| Register | Call meaning | Return meaning | Body meaning | +| --- | --- | --- | --- | +| RSP | Stack pointer | Same | Same | +| R30 | Link register | Same | Scratch (non-leaf functions) | +| R29 | Frame pointer | Same | Same | +| R28 | Current goroutine | Same | Same | +| R27 | Scratch | Scratch | Scratch | +| R26 | Closure context pointer | Scratch | Scratch | +| R18 | Reserved (not used) | Same | Same | +| ZR | Zero value | Same | Same | + +*Rationale*: These register meanings are compatible with Go’s +stack-based calling convention. + +*Rationale*: The link register, R30, holds the function return +address at the function entry. For functions that have frames +(including most non-leaf functions), R30 is saved to stack in the +function prologue and restored in the epilogue. Within the function +body, R30 can be used as a scratch register. + +*Implementation note*: Registers with fixed meaning at calls but not +in function bodies must be initialized by "injected" calls such as +signal-based panics. + +#### Stack layout + +The stack pointer, RSP, grows down and is always aligned to 16 bytes. + +*Rationale*: The arm64 architecture requires the stack pointer to be +16-byte aligned. + +A function's stack frame, after the frame is created, is laid out as +follows: + + +------------------------------+ + | ... locals ... | + | ... outgoing arguments ... | + | return PC | ← RSP points to + | frame pointer on entry | + +------------------------------+ ↓ lower addresses + +The "return PC" is loaded to the link register, R30, as part of the +arm64 `CALL` operation. + +On entry, a function subtracts from RSP to open its stack frame, and +saves the values of R30 and R29 at the bottom of the frame. +Specifically, R30 is saved at 0(RSP) and R29 is saved at -8(RSP), +after RSP is updated. + +A leaf function that does not require any stack space may omit the +saved R30 and R29. + +The Go ABI's use of R29 as a frame pointer register is compatible with +arm64 architecture requirement so that Go can inter-operate with platform +debuggers and profilers. + +This stack layout is used by both register-based (ABIInternal) and +stack-based (ABI0) calling conventions. + +#### Flags + +The arithmetic status flags (NZCV) are treated like scratch registers +and not preserved across calls. +All other bits in PSTATE are system flags and are not modified by Go. + +The floating-point status register (FPSR) is treated like scratch +registers and not preserved across calls. + +At calls, the floating-point control register (FPCR) bits are always +set as follows: + +| Flag | Bit | Value | Meaning | +| --- | --- | --- | --- | +| DN | 25 | 0 | Propagate NaN operands | +| FZ | 24 | 0 | Do not flush to zero | +| RC | 23/22 | 0 (RN) | Round to nearest, choose even if tied | +| IDE | 15 | 0 | Denormal operations trap disabled | +| IXE | 12 | 0 | Inexact trap disabled | +| UFE | 11 | 0 | Underflow trap disabled | +| OFE | 10 | 0 | Overflow trap disabled | +| DZE | 9 | 0 | Divide-by-zero trap disabled | +| IOE | 8 | 0 | Invalid operations trap disabled | +| NEP | 2 | 0 | Scalar operations do not affect higher elements in vector registers | +| AH | 1 | 0 | No alternate handling of de-normal inputs | +| FIZ | 0 | 0 | Do not zero de-normals | + +*Rationale*: Having a fixed FPCR control configuration allows Go +functions to use floating-point and vector (SIMD) operations without +modifying or saving the FPCR. +Functions are allowed to modify it between calls (as long as they +restore it), but as of this writing Go code never does. + ## Future directions ### Spill path improvements |