mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: pass register parameters to called function
still needs morestack still needs results lots of corner cases also not dealt with. For #40724. Change-Id: I03abdf1e8363d75c52969560b427e488a48cd37a Reviewed-on: https://go-review.googlesource.com/c/go/+/293889 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> Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
parent
95ff296a11
commit
4532467c18
4 changed files with 78 additions and 8 deletions
|
|
@ -771,7 +771,8 @@ func init() {
|
||||||
faultOnNilArg0: true,
|
faultOnNilArg0: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
// With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific registers.
|
||||||
|
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
|
||||||
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
|
||||||
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,54 @@ type AuxCall struct {
|
||||||
abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information.
|
abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reg returns the regInfo for a given call, combining the derived in/out register masks
|
||||||
|
// with the machine-specific register information in the input i. (The machine-specific
|
||||||
|
// regInfo is much handier at the call site than it is when the AuxCall is being constructed,
|
||||||
|
// therefore do this lazily).
|
||||||
|
//
|
||||||
|
// TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices
|
||||||
|
// of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs
|
||||||
|
// and outputs from calls, so that all integer registers come first, then all floating registers.
|
||||||
|
// At this point (active development of register ABI) that is very premature,
|
||||||
|
// but if this turns out to be a cost, we could do it.
|
||||||
|
func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
|
||||||
|
if a.reg.clobbers != 0 {
|
||||||
|
// Already updated
|
||||||
|
return a.reg
|
||||||
|
}
|
||||||
|
if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
|
||||||
|
// Shortcut for zero case, also handles old ABI.
|
||||||
|
a.reg = i
|
||||||
|
return a.reg
|
||||||
|
}
|
||||||
|
a.reg.inputs = append(a.reg.inputs, i.inputs...)
|
||||||
|
for _, p := range a.abiInfo.InParams() {
|
||||||
|
for _, r := range p.Registers {
|
||||||
|
m := archRegForAbiReg(r, c)
|
||||||
|
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: len(a.reg.inputs), regs: (1 << m)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.reg.outputs = append(a.reg.outputs, i.outputs...)
|
||||||
|
for _, p := range a.abiInfo.OutParams() {
|
||||||
|
for _, r := range p.Registers {
|
||||||
|
m := archRegForAbiReg(r, c)
|
||||||
|
a.reg.outputs = append(a.reg.outputs, outputInfo{idx: len(a.reg.outputs), regs: (1 << m)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.reg.clobbers = i.clobbers
|
||||||
|
return a.reg
|
||||||
|
}
|
||||||
|
|
||||||
|
func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
|
||||||
|
var m int8
|
||||||
|
if int(r) < len(c.intParamRegs) {
|
||||||
|
m = c.intParamRegs[r]
|
||||||
|
} else {
|
||||||
|
m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
|
||||||
|
}
|
||||||
|
return uint8(m)
|
||||||
|
}
|
||||||
|
|
||||||
// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
|
// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
|
||||||
func (a *AuxCall) OffsetOfResult(which int64) int64 {
|
func (a *AuxCall) OffsetOfResult(which int64) int64 {
|
||||||
n := int64(a.abiInfo.OutParam(int(which)).Offset())
|
n := int64(a.abiInfo.OutParam(int(which)).Offset())
|
||||||
|
|
@ -217,7 +265,11 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo
|
||||||
if paramResultInfo == nil {
|
if paramResultInfo == nil {
|
||||||
panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
|
panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
|
||||||
}
|
}
|
||||||
return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo}
|
var reg *regInfo
|
||||||
|
if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
|
||||||
|
reg = ®Info{}
|
||||||
|
}
|
||||||
|
return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo, reg: reg}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceAuxCall returns an AuxCall for an interface call.
|
// InterfaceAuxCall returns an AuxCall for an interface call.
|
||||||
|
|
|
||||||
|
|
@ -13229,7 +13229,7 @@ var opcodeTable = [...]opInfo{
|
||||||
{
|
{
|
||||||
name: "CALLstatic",
|
name: "CALLstatic",
|
||||||
auxType: auxCallOff,
|
auxType: auxCallOff,
|
||||||
argLen: 1,
|
argLen: -1,
|
||||||
clobberFlags: true,
|
clobberFlags: true,
|
||||||
call: true,
|
call: true,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,14 @@ type register uint8
|
||||||
|
|
||||||
const noRegister register = 255
|
const noRegister register = 255
|
||||||
|
|
||||||
|
// For bulk initializing
|
||||||
|
var noRegisters [32]register = [32]register{
|
||||||
|
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
|
||||||
|
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
|
||||||
|
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
|
||||||
|
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
|
||||||
|
}
|
||||||
|
|
||||||
// A regMask encodes a set of machine registers.
|
// A regMask encodes a set of machine registers.
|
||||||
// TODO: regMask -> regSet?
|
// TODO: regMask -> regSet?
|
||||||
type regMask uint64
|
type regMask uint64
|
||||||
|
|
@ -818,9 +826,8 @@ func (s *regAllocState) regspec(v *Value) regInfo {
|
||||||
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
||||||
}
|
}
|
||||||
if op.IsCall() {
|
if op.IsCall() {
|
||||||
// TODO Panic if not okay
|
|
||||||
if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
|
if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
|
||||||
return *ac.reg
|
return *ac.Reg(&opcodeTable[op].reg, s.f.Config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return opcodeTable[op].reg
|
return opcodeTable[op].reg
|
||||||
|
|
@ -1456,7 +1463,8 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
|
|
||||||
// Pick registers for outputs.
|
// Pick registers for outputs.
|
||||||
{
|
{
|
||||||
outRegs := [2]register{noRegister, noRegister}
|
outRegs := noRegisters // TODO if this is costly, hoist and clear incrementally below.
|
||||||
|
maxOutIdx := -1
|
||||||
var used regMask
|
var used regMask
|
||||||
for _, out := range regspec.outputs {
|
for _, out := range regspec.outputs {
|
||||||
mask := out.regs & s.allocatable &^ used
|
mask := out.regs & s.allocatable &^ used
|
||||||
|
|
@ -1502,6 +1510,9 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
mask &^= desired.avoid
|
mask &^= desired.avoid
|
||||||
}
|
}
|
||||||
r := s.allocReg(mask, v)
|
r := s.allocReg(mask, v)
|
||||||
|
if out.idx > maxOutIdx {
|
||||||
|
maxOutIdx = out.idx
|
||||||
|
}
|
||||||
outRegs[out.idx] = r
|
outRegs[out.idx] = r
|
||||||
used |= regMask(1) << r
|
used |= regMask(1) << r
|
||||||
s.tmpused |= regMask(1) << r
|
s.tmpused |= regMask(1) << r
|
||||||
|
|
@ -1518,8 +1529,14 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
s.f.setHome(v, outLocs)
|
s.f.setHome(v, outLocs)
|
||||||
// Note that subsequent SelectX instructions will do the assignReg calls.
|
// Note that subsequent SelectX instructions will do the assignReg calls.
|
||||||
} else if v.Type.IsResults() {
|
} else if v.Type.IsResults() {
|
||||||
// TODO register arguments need to make this work
|
// preallocate outLocs to the right size, which is maxOutIdx+1
|
||||||
panic("Oops, implement this.")
|
outLocs := make(LocResults, maxOutIdx+1, maxOutIdx+1)
|
||||||
|
for i := 0; i <= maxOutIdx; i++ {
|
||||||
|
if r := outRegs[i]; r != noRegister {
|
||||||
|
outLocs[i] = &s.registers[r]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.f.setHome(v, outLocs)
|
||||||
} else {
|
} else {
|
||||||
if r := outRegs[0]; r != noRegister {
|
if r := outRegs[0]; r != noRegister {
|
||||||
s.assignReg(r, v, v)
|
s.assignReg(r, v, v)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue