Skip to content

cmd/compile: Inaccurate AuxInt value for newobject call #68631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
And-ZJ opened this issue Jul 29, 2024 · 5 comments
Open

cmd/compile: Inaccurate AuxInt value for newobject call #68631

And-ZJ opened this issue Jul 29, 2024 · 5 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@And-ZJ
Copy link
Contributor

And-ZJ commented Jul 29, 2024

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 temp

ARM64(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

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

func (s *state) newObject(typ *types.Type, rtype *ssa.Value) *ssa.Value {

In this way, it call (*state).rtcall at

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

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.

image

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?

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 29, 2024
@cherrymui
Copy link
Member

It seems the auxint is computed pre-register-ABI in ssagen/ssa.go. For the stack ABI (ABI0), this would be correct. With register ABI, it can be smaller.

cc @dr2chase

@mknyszek
Copy link
Contributor

Is this an issue that's new to the current release? (Is it observable in older releases?) For now, putting in Backlog under the assumption that it's from an older release.

@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jul 29, 2024
@mknyszek mknyszek added this to the Backlog milestone Jul 29, 2024
@cherrymui
Copy link
Member

I don't think it's new.

@And-ZJ
Copy link
Contributor Author

And-ZJ commented Jul 30, 2024

Hello, Thanks for the reply.
This problem should be existed in previous versions of go. I checked 1.22 and 1.20 under ARM64, AuxInt for newobject is 24, AuxInt for test1 is 8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

6 participants