mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: teach regalloc about temporary registers
Temporary registers are sometimes needed for an architecture backend which needs to use several machine instructions to implement a single SSA instruction. Mark such instructions so that regalloc can reserve the temporary register for it. That way we don't have to reserve a fixed register like we do now. Convert the temp-register-using instructions on amd64 to use this new mechanism. Other archs can follow as needed. Change-Id: I1d0c8588afdad5cd18b4398eb5a0f755be5dead7 Reviewed-on: https://go-review.googlesource.com/c/go/+/398556 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
249e51e5d9
commit
5f7abeca5a
9 changed files with 95 additions and 44 deletions
|
|
@ -852,6 +852,9 @@ func (s *regAllocState) isGReg(r register) bool {
|
|||
return s.f.Config.hasGReg && s.GReg == r
|
||||
}
|
||||
|
||||
// Dummy value used to represent the value being held in a temporary register.
|
||||
var tmpVal Value
|
||||
|
||||
func (s *regAllocState) regalloc(f *Func) {
|
||||
regValLiveSet := f.newSparseSet(f.NumValues()) // set of values that may be live in register
|
||||
defer f.retSparseSet(regValLiveSet)
|
||||
|
|
@ -1266,6 +1269,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
|
||||
// Process all the non-phi values.
|
||||
for idx, v := range oldSched {
|
||||
tmpReg := noRegister
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf(" processing %s\n", v.LongString())
|
||||
}
|
||||
|
|
@ -1550,6 +1554,20 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
|
||||
ok:
|
||||
// Pick a temporary register if needed.
|
||||
// It should be distinct from all the input registers, so we
|
||||
// allocate it after all the input registers, but before
|
||||
// the input registers are freed via advanceUses below.
|
||||
// (Not all instructions need that distinct part, but it is conservative.)
|
||||
if opcodeTable[v.Op].needIntTemp {
|
||||
m := s.allocatable & s.f.Config.gpRegMask
|
||||
if m&^desired.avoid != 0 {
|
||||
m &^= desired.avoid
|
||||
}
|
||||
tmpReg = s.allocReg(m, &tmpVal)
|
||||
s.nospill |= regMask(1) << tmpReg
|
||||
}
|
||||
|
||||
// Now that all args are in regs, we're ready to issue the value itself.
|
||||
// Before we pick a register for the output value, allow input registers
|
||||
// to be deallocated. We do this here so that the output can use the
|
||||
|
|
@ -1574,6 +1592,11 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
outRegs := noRegisters // TODO if this is costly, hoist and clear incrementally below.
|
||||
maxOutIdx := -1
|
||||
var used regMask
|
||||
if tmpReg != noRegister {
|
||||
// Ensure output registers are distinct from the temporary register.
|
||||
// (Not all instructions need that distinct part, but it is conservative.)
|
||||
used |= regMask(1) << tmpReg
|
||||
}
|
||||
for _, out := range regspec.outputs {
|
||||
mask := out.regs & s.allocatable &^ used
|
||||
if mask == 0 {
|
||||
|
|
@ -1655,6 +1678,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
s.assignReg(r, v, v)
|
||||
}
|
||||
}
|
||||
if tmpReg != noRegister {
|
||||
// Remember the temp register allocation, if any.
|
||||
if s.f.tempRegs == nil {
|
||||
s.f.tempRegs = map[ID]*Register{}
|
||||
}
|
||||
s.f.tempRegs[v.ID] = &s.registers[tmpReg]
|
||||
}
|
||||
}
|
||||
|
||||
// deallocate dead args, if we have not done so
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue