Skip to content

Commit 4532467

Browse files
committed
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 <[email protected]> Run-TryBot: David Chase <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> Reviewed-by: Jeremy Faller <[email protected]>
1 parent 95ff296 commit 4532467

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

src/cmd/compile/internal/ssa/gen/AMD64Ops.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,8 @@ func init() {
771771
faultOnNilArg0: true,
772772
},
773773

774-
{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
774+
// 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.
775+
{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
775776
{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
776777
{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
777778

src/cmd/compile/internal/ssa/op.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,54 @@ type AuxCall struct {
9696
abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information.
9797
}
9898

99+
// Reg returns the regInfo for a given call, combining the derived in/out register masks
100+
// with the machine-specific register information in the input i. (The machine-specific
101+
// regInfo is much handier at the call site than it is when the AuxCall is being constructed,
102+
// therefore do this lazily).
103+
//
104+
// TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices
105+
// of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs
106+
// and outputs from calls, so that all integer registers come first, then all floating registers.
107+
// At this point (active development of register ABI) that is very premature,
108+
// but if this turns out to be a cost, we could do it.
109+
func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
110+
if a.reg.clobbers != 0 {
111+
// Already updated
112+
return a.reg
113+
}
114+
if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
115+
// Shortcut for zero case, also handles old ABI.
116+
a.reg = i
117+
return a.reg
118+
}
119+
a.reg.inputs = append(a.reg.inputs, i.inputs...)
120+
for _, p := range a.abiInfo.InParams() {
121+
for _, r := range p.Registers {
122+
m := archRegForAbiReg(r, c)
123+
a.reg.inputs = append(a.reg.inputs, inputInfo{idx: len(a.reg.inputs), regs: (1 << m)})
124+
}
125+
}
126+
a.reg.outputs = append(a.reg.outputs, i.outputs...)
127+
for _, p := range a.abiInfo.OutParams() {
128+
for _, r := range p.Registers {
129+
m := archRegForAbiReg(r, c)
130+
a.reg.outputs = append(a.reg.outputs, outputInfo{idx: len(a.reg.outputs), regs: (1 << m)})
131+
}
132+
}
133+
a.reg.clobbers = i.clobbers
134+
return a.reg
135+
}
136+
137+
func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
138+
var m int8
139+
if int(r) < len(c.intParamRegs) {
140+
m = c.intParamRegs[r]
141+
} else {
142+
m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
143+
}
144+
return uint8(m)
145+
}
146+
99147
// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
100148
func (a *AuxCall) OffsetOfResult(which int64) int64 {
101149
n := int64(a.abiInfo.OutParam(int(which)).Offset())
@@ -217,7 +265,11 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo
217265
if paramResultInfo == nil {
218266
panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
219267
}
220-
return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo}
268+
var reg *regInfo
269+
if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
270+
reg = &regInfo{}
271+
}
272+
return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo, reg: reg}
221273
}
222274

223275
// InterfaceAuxCall returns an AuxCall for an interface call.

src/cmd/compile/internal/ssa/opGen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/ssa/regalloc.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ type register uint8
151151

152152
const noRegister register = 255
153153

154+
// For bulk initializing
155+
var noRegisters [32]register = [32]register{
156+
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
157+
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
158+
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
159+
noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
160+
}
161+
154162
// A regMask encodes a set of machine registers.
155163
// TODO: regMask -> regSet?
156164
type regMask uint64
@@ -818,9 +826,8 @@ func (s *regAllocState) regspec(v *Value) regInfo {
818826
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
819827
}
820828
if op.IsCall() {
821-
// TODO Panic if not okay
822829
if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
823-
return *ac.reg
830+
return *ac.Reg(&opcodeTable[op].reg, s.f.Config)
824831
}
825832
}
826833
return opcodeTable[op].reg
@@ -1456,7 +1463,8 @@ func (s *regAllocState) regalloc(f *Func) {
14561463

14571464
// Pick registers for outputs.
14581465
{
1459-
outRegs := [2]register{noRegister, noRegister}
1466+
outRegs := noRegisters // TODO if this is costly, hoist and clear incrementally below.
1467+
maxOutIdx := -1
14601468
var used regMask
14611469
for _, out := range regspec.outputs {
14621470
mask := out.regs & s.allocatable &^ used
@@ -1502,6 +1510,9 @@ func (s *regAllocState) regalloc(f *Func) {
15021510
mask &^= desired.avoid
15031511
}
15041512
r := s.allocReg(mask, v)
1513+
if out.idx > maxOutIdx {
1514+
maxOutIdx = out.idx
1515+
}
15051516
outRegs[out.idx] = r
15061517
used |= regMask(1) << r
15071518
s.tmpused |= regMask(1) << r
@@ -1518,8 +1529,14 @@ func (s *regAllocState) regalloc(f *Func) {
15181529
s.f.setHome(v, outLocs)
15191530
// Note that subsequent SelectX instructions will do the assignReg calls.
15201531
} else if v.Type.IsResults() {
1521-
// TODO register arguments need to make this work
1522-
panic("Oops, implement this.")
1532+
// preallocate outLocs to the right size, which is maxOutIdx+1
1533+
outLocs := make(LocResults, maxOutIdx+1, maxOutIdx+1)
1534+
for i := 0; i <= maxOutIdx; i++ {
1535+
if r := outRegs[i]; r != noRegister {
1536+
outLocs[i] = &s.registers[r]
1537+
}
1538+
}
1539+
s.f.setHome(v, outLocs)
15231540
} else {
15241541
if r := outRegs[0]; r != noRegister {
15251542
s.assignReg(r, v, v)

0 commit comments

Comments
 (0)