cmd/compile: implement too-big-to-SSA struct passing in registers

Added a test that exercises named results

Change-Id: Ie228b68f4f846266595a95e0f65a6e4b8bf79635
Reviewed-on: https://go-review.googlesource.com/c/go/+/297029
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
David Chase 2021-02-23 20:00:31 -05:00
parent 77505c25d8
commit c015f76acb
5 changed files with 190 additions and 26 deletions

View file

@ -118,12 +118,22 @@ func RegisterTypes(apa []ABIParamAssignment) []*types.Type {
if len(pa.Registers) == 0 {
continue
}
rts = appendParamRegs(rts, pa.Type)
rts = appendParamTypes(rts, pa.Type)
}
return rts
}
func appendParamRegs(rts []*types.Type, t *types.Type) []*types.Type {
func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) {
l := len(pa.Registers)
if l == 0 {
return nil, nil
}
typs := make([]*types.Type, 0, l)
offs := make([]int64, 0, l)
return appendParamTypes(typs, pa.Type), appendParamOffsets(offs, 0, pa.Type)
}
func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type {
if t.IsScalar() || t.IsPtrShaped() {
if t.IsComplex() {
c := types.FloatForComplex(t)
@ -146,25 +156,60 @@ func appendParamRegs(rts []*types.Type, t *types.Type) []*types.Type {
switch typ {
case types.TARRAY:
for i := int64(0); i < t.Size(); i++ { // 0 gets no registers, plus future-proofing.
rts = appendParamRegs(rts, t.Elem())
rts = appendParamTypes(rts, t.Elem())
}
case types.TSTRUCT:
for _, f := range t.FieldSlice() {
if f.Type.Size() > 0 { // embedded zero-width types receive no registers
rts = appendParamRegs(rts, f.Type)
rts = appendParamTypes(rts, f.Type)
}
}
case types.TSLICE:
return appendParamRegs(rts, synthSlice)
return appendParamTypes(rts, synthSlice)
case types.TSTRING:
return appendParamRegs(rts, synthString)
return appendParamTypes(rts, synthString)
case types.TINTER:
return appendParamRegs(rts, synthIface)
return appendParamTypes(rts, synthIface)
}
}
return rts
}
// appendParamOffsets appends the offset(s) of type t, starting from "at",
// to input offsets, and returns the longer slice.
func appendParamOffsets(offsets []int64, at int64, t *types.Type) []int64 {
at = align(at, t)
if t.IsScalar() || t.IsPtrShaped() {
if t.IsComplex() || int(t.Width) > types.RegSize { // complex and *int64 on 32-bit
s := t.Width / 2
return append(offsets, at, at+s)
} else {
return append(offsets, at)
}
} else {
typ := t.Kind()
switch typ {
case types.TARRAY:
for i := int64(0); i < t.NumElem(); i++ {
offsets = appendParamOffsets(offsets, at, t.Elem())
}
return offsets
case types.TSTRUCT:
for _, f := range t.FieldSlice() {
offsets = appendParamOffsets(offsets, at, f.Type)
at += f.Type.Width
}
case types.TSLICE:
return appendParamOffsets(offsets, at, synthSlice)
case types.TSTRING:
return appendParamOffsets(offsets, at, synthString)
case types.TINTER:
return appendParamOffsets(offsets, at, synthIface)
}
}
return offsets
}
// SpillOffset returns the offset *within the spill area* for the parameter that "a" describes.
// Registers will be spilled here; if a memory home is needed (for a pointer method e.g.)
// then that will be the address.