Skip to content

cmd/compile: optimize large structs #24416

Open

Description

@randall77

The compiler currently compiles large structs conservatively. If a struct type has more than 4 fields (or a few other conditions), we treat that type as unSSAable. All operations on variables of that type go to the stack, as if their address was taken.

This is suboptimal in various ways. For example:

type T struct {
	a, b, c, d int
}

func f(x *T) {
	t := T{}
	*x = t
}

type U struct {
	a, b, c, d, e int
}

func g(x *U) {
	u := U{}
	*x = u
}

f is compiled optimally, to:

	XORPS	X0, X0
	MOVQ	"".x+8(SP), AX
	MOVUPS	X0, (AX)
	MOVUPS	X0, 16(AX)
	RET

g is quite a bit worse:

	MOVQ	BP, 40(SP)
	LEAQ	40(SP), BP
	MOVQ	$0, "".u(SP)
	XORPS	X0, X0
	MOVUPS	X0, "".u+8(SP)
	MOVUPS	X0, "".u+24(SP)
	MOVQ	"".u(SP), AX
	MOVQ	"".x+56(SP), CX
	MOVQ	AX, (CX)
	LEAQ	8(CX), DI
	LEAQ	"".u+8(SP), SI
	DUFFCOPY	$868
	MOVQ	40(SP), BP
	ADDQ	$48, SP
	RET

We zero a temporary variable on the stack, then copy it to the destination.

We should process large structs through SSA as well. This will require a fair amount of work in the SSA backend to introduce struct builders, selectors of arbitrary width, stack allocation of large types, maybe heap allocation if they are really huge, etc.

Arrays of size > 1 are in a similar state, but they are somewhat harder because non-constant indexes add an additional complication.

Activity

  1. josharian commented on Mar 15, 2018

    @josharian
    Contributor

    Just to ask an obvious question, is the problem that we want to handle all n, or just that n<=4 is too small? If the latter, and a reasonable cap is say 16, it might be easier to just extend the current approach, maybe using a bit of codegen magic. Probably we should Do It Right, but worth asking...

  2. randall77 commented on Mar 15, 2018

    @randall77
    ContributorAuthor

    My intent is to handle all n.

  3. TocarIP commented on Mar 21, 2018

    @TocarIP
    Contributor

    Looks like this should also help #20859

  4. added this to the Go1.11 milestone on Mar 26, 2018
  5. added
    NeedsFixThe path to resolution is known, but the work has not been done.
    on Mar 26, 2018
  6. modified the milestones: Go1.11, Unplanned on Mar 26, 2018
  7. gopherbot commented on Apr 29, 2018

    @gopherbot
    Contributor

    Change https://golang.org/cl/106495 mentions this issue: cmd/compile: add some generic composite type optimizations

  8. gopherbot commented on Nov 12, 2019

    @gopherbot
    Contributor

    Change https://golang.org/cl/206937 mentions this issue: cmd/compile: optimize big structs

  9. zigo101 commented on May 12, 2021

    @zigo101
    Contributor

    It looks, for Go toolchain v1.16, structs with 8 int fields and [8]int values have already been viewed as small-size values.

  10. randall77 commented on May 12, 2021

    @randall77
    ContributorAuthor

    It definitely compiles to better code now, but I think the underlying issue is still there. I think it just needs a better test case.

    package p
    
    type T struct {
    	a, b, c, d int
    }
    
    type U struct {
    	a, b, c, d, e int
    }
    
    func f() int {
    	t := T{1, 2, 3, 4}
    	return t.c
    }
    func g() int {
    	u := U{1, 2, 3, 4, 5}
    	return u.c
    }
    

    f is compiles to MOVL $3, AX; RET. g compiles to

    SUBQ	$48, SP
    MOVQ	BP, 40(SP)
    LEAQ	40(SP), BP
    MOVQ	$1, "".u(SP)
    MOVQ	$2, "".u+8(SP)
    MOVQ	$3, "".u+16(SP)
    MOVQ	$4, "".u+24(SP)
    MOVQ	$5, "".u+32(SP)
    MOVQ	"".u+16(SP), AX
    MOVQ	40(SP), BP
    ADDQ	$48, SP
    RET
    
  11. quasilyte commented on Nov 9, 2021

    @quasilyte
    Contributor

    I'm interested to know what's the status on this?

    The CL206937 was abandoned but it's unclear why.

    Are there any extra insights that came from that experiment?

  12. randall77 commented on Nov 9, 2021

    @randall77
    ContributorAuthor

    It's not abandoned, it just isn't finished. It had issues. Performance wasn't good, and there were pathological cases, like large fields of even larger structs weren't handled well.

  13. gopherbot commented on Sep 5, 2024

    @gopherbot
    Contributor

    Change https://go.dev/cl/611076 mentions this issue: cmd/compile/internal/ssa: bump MaxStruct to 16

  14. gopherbot commented on Sep 5, 2024

    @gopherbot
    Contributor

    Change https://go.dev/cl/611075 mentions this issue: cmd/compile: generalize struct load/store

  15. gopherbot commented on Aug 5, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/810603 mentions this issue: cmd/compile/internal/ssa: split MaxStruct and raise the SSA-ability caps

  16. gopherbot commented on Aug 11, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/813343 mentions this issue: cmd/compile: SSA-decompose small arrays

  17. gopherbot commented on Aug 11, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/813340 mentions this issue: cmd/compile: copy whole pointerful aggregates with a single Move

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions