mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
9a555fc24c
commit
e25040d162
18 changed files with 387 additions and 382 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue