Register spilling size

266 views
Skip to first unread message

eric...@arm.com

unread,
Nov 2, 2020, 6:29:49 AM11/2/20
to golang-nuts
Hi,

Can someone tell me why does OpStoreReg of type int16, int32, etc. occupy 8 bytes on the stack? And where is this handled ? Thanks.

Keith Randall

unread,
Nov 3, 2020, 5:39:30 PM11/3/20
to golang-nuts
It don't think it does. For instance, an int16 will be spilled to a 2-byte slot in the stack frame.
Can you show us what you are seeing? This is what I tried:

package main

func f(p, q *int16) {
x := *p
y := *q
g()
*p = y
*q = x
}
func g()

go tool compile -S tmp.go

0x001d 00029 (tmp1.go:4) MOVQ "".p+24(SP), AX
0x0022 00034 (tmp1.go:4) MOVWLZX (AX), CX
0x0025 00037 (tmp1.go:4) MOVW CX, "".x+6(SP)
0x002a 00042 (tmp1.go:5) MOVQ "".q+32(SP), DX
0x002f 00047 (tmp1.go:5) MOVWLZX (DX), BX
0x0032 00050 (tmp1.go:5) MOVW BX, "".y+4(SP)
0x0037 00055 (tmp1.go:6) CALL "".g(SB)
0x003c 00060 (tmp1.go:7) MOVWLZX "".y+4(SP), AX
0x0041 00065 (tmp1.go:7) MOVQ "".p+24(SP), CX
0x0046 00070 (tmp1.go:7) MOVW AX, (CX)
0x0049 00073 (tmp1.go:8) MOVWLZX "".x+6(SP), AX
0x004e 00078 (tmp1.go:8) MOVQ "".q+32(SP), CX
0x0053 00083 (tmp1.go:8) MOVW AX, (CX)


eric...@arm.com

unread,
Nov 3, 2020, 8:38:12 PM11/3/20
to golang-nuts
Hi Keith, thank you for your response. Sorry I didn't say that I saw this issue on linux/arm64. For your example above, the result on linux/arm64 is like this:
go tool compile -S tmp.go 
 
        0x001c 00028 (spill.go:4)       MOVD    "".p(FP), R0
        0x0020 00032 (spill.go:4)       MOVH    (R0), R1
        0x0024 00036 (spill.go:4)       MOVH    R1, "".x-8(SP)
        0x0028 00040 (spill.go:5)       MOVD    "".q+8(FP), R2
        0x002c 00044 (spill.go:5)       MOVH    (R2), R3
        0x0030 00048 (spill.go:5)       MOVH    R3, "".y-16(SP)
        0x0034 00052 (spill.go:6)       PCDATA  $1, ZR
        0x0034 00052 (spill.go:6)       CALL    "".g(SB)
        0x0038 00056 (spill.go:7)       MOVH    "".y-16(SP), R0
        0x003c 00060 (spill.go:7)       MOVD    "".p(FP), R1
        0x0040 00064 (spill.go:7)       MOVH    R0, (R1)
        0x0044 00068 (spill.go:8)       MOVH    "".x-8(SP), R0
        0x0048 00072 (spill.go:8)       MOVD    "".q+8(FP), R1
        0x004c 00076 (spill.go:8)       MOVH    R0, (R1)

Obviously it is 8 bytes.

eric...@arm.com

unread,
Nov 4, 2020, 3:36:44 AM11/4/20
to golang-nuts
I got it, the code is here https://github.com/golang/go/blob/633f9e206045176a12c301eb2c249c1c1d9a5d2e/src/cmd/compile/internal/gc/pgen.go#L186
I don't know why the slot is required to be aligned at least 8 bytes on these architectures. I will try to see if this requirement can be removed on linux/arm64, 
and to determine the slot size based on the actual size of the variable, just like linux/amd64 does.

Jesper Louis Andersen

unread,
Nov 4, 2020, 8:51:03 AM11/4/20
to eric...@arm.com, golang-nuts
On Wed, Nov 4, 2020 at 9:36 AM eric...@arm.com <eric...@arm.com> wrote:
I got it, the code is here https://github.com/golang/go/blob/633f9e206045176a12c301eb2c249c1c1d9a5d2e/src/cmd/compile/internal/gc/pgen.go#L186
I don't know why the slot is required to be aligned at least 8 bytes on these architectures. I will try to see if this requirement can be removed on linux/arm64, 
and to determine the slot size based on the actual size of the variable, just like linux/amd64 does.


If my memory serves (and it is spotty, you should definitely look it up) arm64 requires sp to be 16-byte aligned (or two times the word size to be precise), and this is a hardware requirement if accessing memory.

There might be other reasons to want aligned access pertaining to atomicity guarantees and memory models. If the garbage collector assumes certain things about memory access when it is doing its unspeakable things to the stack, you may want it to have alignment to ensure certain operations behave nicely. Tread carefully, my friend.


Keith Randall

unread,
Nov 4, 2020, 7:21:34 PM11/4/20
to golang-nuts
Ah, arm64.
That code jesper points to looks like the culprit.
The whole stack frame alignment should be handled separately from the alignment of individual variables, so the total alignment needed shouldn't matter.

Not sure why we do that. A small archaeology dive indicates this code dates from when the compiler was written in C. No indication of why it was added.
I've opened an issue to look at this. https://github.com/golang/go/issues/42386

eric...@arm.com

unread,
Nov 4, 2020, 8:50:19 PM11/4/20
to golang-nuts
Yes, as Keith said, the 16-byte alignment requirement of sp is for the size of the entire stack, and there is no such requirement for a single variable on the stack. We can access a single variable through sp+/-offset.
The code has already dealt with the overall alignment of sp. I tried to remove the alignment requirement for a single variable on linux/arm64, and all the tests in all.bash passed. So I think this alignment requirement for a single variable is unnecessary on linux/arm64. In addition, I also checked the result generated by gcc. In the case of -O0, the alignment of a single variable on the stack is consistent with its own size.

Reply all
Reply to author
Forward
0 new messages