diff options
author | David Chase <drchase@google.com> | 2021-02-04 16:42:35 -0500 |
---|---|---|
committer | David Chase <drchase@google.com> | 2021-02-26 02:52:33 +0000 |
commit | e25040d16288563c89cead5e8da8d3b9c74ab655 (patch) | |
tree | 4e57425c9764cf01ac69447f06d1bb52f07d9e46 /src/cmd/compile/internal/abi/abiutils.go | |
parent | 9a555fc24c318bf1b07bdc07d5c02e372681e401 (diff) | |
download | go-e25040d16288563c89cead5e8da8d3b9c74ab655.tar.gz go-e25040d16288563c89cead5e8da8d3b9c74ab655.zip |
cmd/compile: change StaticCall to return a "Results"
StaticLECall (multiple value in +mem, multiple value result +mem) ->
StaticCall (multiple ergister value in +mem,
multiple register-sized-value result +mem) ->
ARCH CallStatic (multiple ergister value in +mem,
multiple register-sized-value result +mem)
But the architecture-dependent stuff is indifferent to whether
it is mem->mem or (mem)->(mem) until Prog generation.
Deal with OpSelectN -> Prog in ssagen/ssa.go, others, as they
appear.
For #40724.
Change-Id: I1d0436f6371054f1881862641d8e7e418e4a6a16
Reviewed-on: https://go-review.googlesource.com/c/go/+/293391
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/cmd/compile/internal/abi/abiutils.go')
-rw-r--r-- | src/cmd/compile/internal/abi/abiutils.go | 83 |
1 files changed, 72 insertions, 11 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 4bd27efb59..b43d95e976 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -27,6 +27,8 @@ type ABIParamResultInfo struct { outparams []ABIParamAssignment offsetToSpillArea int64 spillAreaSize int64 + inRegistersUsed int + outRegistersUsed int config *ABIConfig // to enable String() method } @@ -42,6 +44,14 @@ func (a *ABIParamResultInfo) OutParams() []ABIParamAssignment { return a.outparams } +func (a *ABIParamResultInfo) InRegistersUsed() int { + return a.inRegistersUsed +} + +func (a *ABIParamResultInfo) OutRegistersUsed() int { + return a.outRegistersUsed +} + func (a *ABIParamResultInfo) InParam(i int) ABIParamAssignment { return a.inparams[i] } @@ -164,6 +174,55 @@ func (a *ABIConfig) NumParamRegs(t *types.Type) int { return n } +// preAllocateParams gets the slice sizes right for inputs and outputs. +func (a *ABIParamResultInfo) preAllocateParams(hasRcvr bool, nIns, nOuts int) { + if hasRcvr { + nIns++ + } + a.inparams = make([]ABIParamAssignment, 0, nIns) + a.outparams = make([]ABIParamAssignment, 0, nOuts) +} + +// ABIAnalyzeTypes takes an optional receiver type, arrays of ins and outs, and returns an ABIParamResultInfo, +// based on the given configuration. This is the same result computed by config.ABIAnalyze applied to the +// corresponding method/function type, except that all the embedded parameter names are nil. +// This is intended for use by ssagen/ssa.go:(*state).rtcall, for runtime functions that lack a parsed function type. +func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Type) *ABIParamResultInfo { + setup() + s := assignState{ + rTotal: config.regAmounts, + } + result := &ABIParamResultInfo{config: config} + result.preAllocateParams(rcvr != nil, len(ins), len(outs)) + + // Receiver + if rcvr != nil { + result.inparams = append(result.inparams, + s.assignParamOrReturn(rcvr, nil, false)) + } + + // Inputs + for _, t := range ins { + result.inparams = append(result.inparams, + s.assignParamOrReturn(t, nil, false)) + } + s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) + result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + + // Outputs + s.rUsed = RegAmounts{} + for _, t := range outs { + result.outparams = append(result.outparams, s.assignParamOrReturn(t, nil, 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. + result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize) + result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) + result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + + return result +} + // ABIAnalyze takes a function type 't' and an ABI rules description // 'config' and analyzes the function to determine how its parameters // and results will be passed (in registers or on the stack), returning @@ -174,33 +233,37 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { rTotal: config.regAmounts, } result := &ABIParamResultInfo{config: config} + ft := t.FuncType() + result.preAllocateParams(t.NumRecvs() != 0, ft.Params.NumFields(), ft.Results.NumFields()) // Receiver - ft := t.FuncType() + // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters if t.NumRecvs() != 0 { - rfsl := ft.Receiver.FieldSlice() + r := ft.Receiver.FieldSlice()[0] result.inparams = append(result.inparams, - s.assignParamOrReturn(rfsl[0], false)) + s.assignParamOrReturn(r.Type, r.Nname, false)) } // Inputs ifsl := ft.Params.FieldSlice() for _, f := range ifsl { result.inparams = append(result.inparams, - s.assignParamOrReturn(f, false)) + s.assignParamOrReturn(f.Type, f.Nname, false)) } s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) + result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs // Outputs s.rUsed = RegAmounts{} ofsl := ft.Results.FieldSlice() for _, f := range ofsl { - result.outparams = append(result.outparams, s.assignParamOrReturn(f, true)) + result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, f.Nname, 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. result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize) result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) + result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs return result } @@ -460,17 +523,15 @@ func (state *assignState) regassign(pt *types.Type) bool { // 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(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 +func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, isReturn bool) ABIParamAssignment { state.pUsed = RegAmounts{} if pt.Width == types.BADWIDTH { panic("should never happen") } else if pt.Width == 0 { - return state.stackAllocate(pt, f.Nname) + return state.stackAllocate(pt, n) } else if state.regassign(pt) { - return state.regAllocate(pt, f.Nname, isReturn) + return state.regAllocate(pt, n, isReturn) } else { - return state.stackAllocate(pt, f.Nname) + return state.stackAllocate(pt, n) } } |