-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
Go version
go version go1.23rc2 linux/arm64
Output of go env in your module/workspace:
Pasted part of content:
GO111MODULE='auto'
GOARCH='arm64'
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOOS='linux'
GOROOT='/usr1/GoRelease/go1.23rc2'
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr1/GoRelease/go1.23rc2/pkg/tool/linux_arm64'
GOVERSION='go1.23rc2'
GODEBUG=''
GOTELEMETRY='local'
GOARM64='v8.0'What did you do?
When I look at the call to runtime.newobject in SSA, it looks like the AuxInt value is inaccurate.
I think It is larger than expected. In addition, the value is larger in ARM64 than in AMD64.
My test code temp.go:
package main
var g1 *int64
//go:noinline
func test1(a *int64) *int64 {
g1 = a
return a
}
func main() {
a := new(int64)
test1(a)
}Build, dump SSA and view assembly code:
GOSSAFUNC=main.main go build -a -trimpath temp.go
objdump -rd --disassemble=main.main tempARM64(SSA dump in before insert phis phase):
b1:
v1 (?) = InitMem <mem>
v2 (?) = SP <uintptr>
v3 (?) = SB <uintptr>
v4 (?) = Addr <*uint8> {type:int64} v3
v5 (12) = StaticLECall <*int64,mem> {AuxCall{runtime.newobject}} [24] v4 v1
v6 (12) = SelectN <mem> [1] v5
v7 (12) = SelectN <*int64> [0] v5 (a[*int64])
v8 (13) = StaticLECall <*int64,mem> {AuxCall{main.test1}} [8] v7 v6
v9 (13) = SelectN <mem> [1] v8
v10 (13) = SelectN <*int64> [0] v8
v11 (14) = MakeResult <mem> v9
Ret v11 (14)
name a[*int64]: v7
ARM64(assembly code):
0000000000076f70 <main.main>:
76f70: f9400b90 ldr x16, [x28, #16]
76f74: eb3063ff cmp sp, x16
76f78: 54000169 b.ls 76fa4 <main.main+0x34> // b.plast
76f7c: f81d0ffe str x30, [sp, #-48]!
76f80: f81f83fd stur x29, [sp, #-8]
76f84: d10023fd sub x29, sp, #0x8
76f88: f0000060 adrp x0, 85000 <type:*+0x5000>
76f8c: 910e0000 add x0, x0, #0x380
76f90: 97fe8da8 bl 1a630 <runtime.newobject>
76f94: 97ffffdf bl 76f10 <main.test1>
76f98: a97ffbfd ldp x29, x30, [sp, #-8]
76f9c: 9100c3ff add sp, sp, #0x30
76fa0: d65f03c0 ret
76fa4: aa1e03e3 mov x3, x30
76fa8: 97ffed62 bl 72530 <runtime.morestack_noctxt.abi0>
76fac: 17fffff1 b 76f70 <main.main>AMD64(SSA dump in before insert phis phase):
b1:
v1 (?) = InitMem <mem>
v2 (?) = SP <uintptr>
v3 (?) = SB <uintptr>
v4 (?) = Addr <*uint8> {type:int64} v3
v5 (12) = StaticLECall <*int64,mem> {AuxCall{runtime.newobject}} [16] v4 v1
v6 (12) = SelectN <mem> [1] v5
v7 (12) = SelectN <*int64> [0] v5 (a[*int64])
v8 (13) = StaticLECall <*int64,mem> {AuxCall{main.test1}} [8] v7 v6
v9 (13) = SelectN <mem> [1] v8
v10 (13) = SelectN <*int64> [0] v8
v11 (14) = MakeResult <mem> v9
Ret v11 (14)
name a[*int64]: v7
AMD64(assembly code):
0000000000466820 <main.main>:
466820: 49 3b 66 10 cmp 0x10(%r14),%rsp
466824: 76 1f jbe 466845 <main.main+0x25>
466826: 55 push %rbp
466827: 48 89 e5 mov %rsp,%rbp
46682a: 48 83 ec 10 sub $0x10,%rsp
46682e: 48 8d 05 4b 5b 00 00 lea 0x5b4b(%rip),%rax # 46c380 <type:*+0x5380>
466835: e8 a6 4a fa ff callq 40b2e0 <runtime.newobject>
46683a: e8 81 ff ff ff callq 4667c0 <main.test1>
46683f: 48 83 c4 10 add $0x10,%rsp
466843: 5d pop %rbp
466844: c3 retq
466845: e8 b6 b0 ff ff callq 461900 <runtime.morestack_noctxt.abi0>
46684a: eb d4 jmp 466820 <main.main>In ARM64:
The newobject's AuxInt is 24. The test1's AuxInt is 8. Note the test1 function that has only one input parameter and one return value.
The stack space of the main function uses 48 bytes.
In AMD64:
The newobject's AuxInt is 16. The test1's AuxInt is 8.
The stack space of the main function uses 24 bytes (0x10 + 8).
The StaticLECall in
| {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. |
Here, AuxInt indicates the size of the input parameter, but it is not specified whether the mem parameter is included. It is suspected that the mem parameter is not included.
The auxCallOff in
go/src/cmd/compile/internal/ssa/op.go
Line 365 in 30b6fd6
| auxCallOff // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size |
Here, AuxInt indicates includes the size of the input and output parameters?
The runtime call newobject may emit at (*state).newObject at
go/src/cmd/compile/internal/ssagen/ssa.go
Line 713 in 30b6fd6
| func (s *state) newObject(typ *types.Type, rtype *ssa.Value) *ssa.Value { |
In this way, it call (*state).rtcall at
go/src/cmd/compile/internal/ssagen/ssa.go
Line 5941 in 30b6fd6
| func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value { |
AuxInt appears to be the sum of the size of the input and output parameters and FixedFrameSize.
The common call test1 may emit at (*state).call at
go/src/cmd/compile/internal/ssagen/ssa.go
Line 5353 in 30b6fd6
| func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExtra ir.Expr) *ssa.Value { |
In this way, AuxInt mostly equal to (*ABIParamResultInfo).ArgWidth(), This should be the size of the stack space to be used when calling. The space includes the spill space of the register transfer parameter, and the space on the stack of the input and output parameters of the stack transfer parameter.
So, I've got a lot of explanations for AuxInt of this situation and I'm confused.
From the main function assembly, I think the space used on the stack is larger than what is actually needed.
The gray areas that are marked here are what I consider to be unused space.
For other functions that use the (*state).rtcall, the situation may be similar.
This should have happened in previous versions of go.
I haven't been able to find out if anyone else has had the same problem.
Thank you for your reading.
My understanding may be incorrect, please point it out, thanks.
What did you see happen?
The caller's stack space used by newobject is larger than my expected. It's AuxInt is inaccurate?
What did you expect to see?
More precise AuxInt of newobject and other runtime calls?
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
