diff options
author | David Chase <drchase@google.com> | 2021-02-01 13:26:47 -0500 |
---|---|---|
committer | David Chase <drchase@google.com> | 2021-02-24 23:05:10 +0000 |
commit | d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee (patch) | |
tree | f4bb4649d1d39a35620e93d51a2a5859649ae360 /src/cmd/compile/internal/abi/abiutils.go | |
parent | 8027343b6395536aa8bef8158bad8f4c290dd650 (diff) | |
download | go-d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee.tar.gz go-d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee.zip |
cmd/compile: plumb abi info into expandCalls
Work in progress.
TODO:
- insert debugging output for all the steps listed below
- emit modified call instructions w/ multiple register inputs
and Result-typed outputs (next CL)
- initially just change output from "mem" to "Result{mem}"
= most places this hits will be future work.
- change OpArg to use registerized variants
- (done) match abi paramresultinfo with particular arg, use Name
- (this CL) push register offsets for "loads" and "stores" into
recursive decomposition.
- hand registerized Result to exit block
For #40724.
Change-Id: Ie5de9d71f8fd4e092f5ee9260b54de35abf91016
Reviewed-on: https://go-review.googlesource.com/c/go/+/293390
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/abi/abiutils.go')
-rw-r--r-- | src/cmd/compile/internal/abi/abiutils.go | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 7b388ec3dc..4bd27efb59 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -30,6 +30,10 @@ type ABIParamResultInfo struct { config *ABIConfig // to enable String() method } +func (a *ABIParamResultInfo) Config() *ABIConfig { + return a.config +} + func (a *ABIParamResultInfo) InParams() []ABIParamAssignment { return a.inparams } @@ -68,10 +72,11 @@ type RegIndex uint8 // ABIParamAssignment holds information about how a specific param or // result will be passed: in registers (in which case 'Registers' is // populated) or on the stack (in which case 'Offset' is set to a -// non-negative stack offset. The values in 'Registers' are indices (as -// described above), not architected registers. +// non-negative stack offset. The values in 'Registers' are indices +// (as described above), not architected registers. type ABIParamAssignment struct { Type *types.Type + Name types.Object // should always be *ir.Name, used to match with a particular ssa.OpArg. Registers []RegIndex offset int32 } @@ -126,37 +131,36 @@ func (a *ABIConfig) Copy() *ABIConfig { // NumParamRegs returns the number of parameter registers used for a given type, // without regard for the number available. func (a *ABIConfig) NumParamRegs(t *types.Type) int { + var n int if n, ok := a.regsForTypeCache[t]; ok { return n } if t.IsScalar() || t.IsPtrShaped() { - var n int if t.IsComplex() { n = 2 } else { n = (int(t.Size()) + types.RegSize - 1) / types.RegSize } - a.regsForTypeCache[t] = n - return n - } - typ := t.Kind() - n := 0 - switch typ { - case types.TARRAY: - n = a.NumParamRegs(t.Elem()) * int(t.NumElem()) - case types.TSTRUCT: - for _, f := range t.FieldSlice() { - n += a.NumParamRegs(f.Type) + } else { + typ := t.Kind() + switch typ { + case types.TARRAY: + n = a.NumParamRegs(t.Elem()) * int(t.NumElem()) + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + n += a.NumParamRegs(f.Type) + } + case types.TSLICE: + n = a.NumParamRegs(synthSlice) + case types.TSTRING: + n = a.NumParamRegs(synthString) + case types.TINTER: + n = a.NumParamRegs(synthIface) } - case types.TSLICE: - n = a.NumParamRegs(synthSlice) - case types.TSTRING: - n = a.NumParamRegs(synthString) - case types.TINTER: - n = a.NumParamRegs(synthIface) } a.regsForTypeCache[t] = n + return n } @@ -176,14 +180,14 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { if t.NumRecvs() != 0 { rfsl := ft.Receiver.FieldSlice() result.inparams = append(result.inparams, - s.assignParamOrReturn(rfsl[0].Type, false)) + s.assignParamOrReturn(rfsl[0], false)) } // Inputs ifsl := ft.Params.FieldSlice() for _, f := range ifsl { result.inparams = append(result.inparams, - s.assignParamOrReturn(f.Type, false)) + s.assignParamOrReturn(f, false)) } s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) @@ -191,7 +195,7 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { s.rUsed = RegAmounts{} ofsl := ft.Results.FieldSlice() for _, f := range ofsl { - result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, true)) + result.outparams = append(result.outparams, s.assignParamOrReturn(f, true)) } // The spill area is at a register-aligned offset and its size is rounded up to a register alignment. // TODO in theory could align offset only to minimum required by spilled data types. @@ -299,7 +303,7 @@ func (state *assignState) allocateRegs() []RegIndex { // regAllocate creates a register ABIParamAssignment object for a param // or result with the specified type, as a final step (this assumes // that all of the safety/suitability analysis is complete). -func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssignment { +func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn bool) ABIParamAssignment { spillLoc := int64(-1) if !isReturn { // Spill for register-resident t must be aligned for storage of a t. @@ -308,6 +312,7 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi } return ABIParamAssignment{ Type: t, + Name: name, Registers: state.allocateRegs(), offset: int32(spillLoc), } @@ -316,9 +321,10 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi // stackAllocate creates a stack memory ABIParamAssignment object for // a param or result with the specified type, as a final step (this // assumes that all of the safety/suitability analysis is complete). -func (state *assignState) stackAllocate(t *types.Type) ABIParamAssignment { +func (state *assignState) stackAllocate(t *types.Type, name types.Object) ABIParamAssignment { return ABIParamAssignment{ Type: t, + Name: name, offset: int32(state.stackSlot(t)), } } @@ -451,18 +457,20 @@ func (state *assignState) regassign(pt *types.Type) bool { } // assignParamOrReturn processes a given receiver, param, or result -// of type 'pt' to determine whether it can be register assigned. +// of field f to determine whether it can be register assigned. // The result of the analysis is recorded in the result // ABIParamResultInfo held in 'state'. -func (state *assignState) assignParamOrReturn(pt *types.Type, isReturn bool) ABIParamAssignment { +func (state *assignState) assignParamOrReturn(f *types.Field, isReturn bool) ABIParamAssignment { + // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters + pt := f.Type state.pUsed = RegAmounts{} if pt.Width == types.BADWIDTH { panic("should never happen") } else if pt.Width == 0 { - return state.stackAllocate(pt) + return state.stackAllocate(pt, f.Nname) } else if state.regassign(pt) { - return state.regAllocate(pt, isReturn) + return state.regAllocate(pt, f.Nname, isReturn) } else { - return state.stackAllocate(pt) + return state.stackAllocate(pt, f.Nname) } } |