mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: allow ops to specify clobbering input registers
Same as clobbering fixed registers, but which register is clobbered depends on which register was assigned to the input. Add code similar to resultInArg0 processing that makes a register copy before allowing the op to clobber the last available copy of a value. (Will be used by subsequent CLs in this stack.) Change-Id: I6bad88b2cb9ac3303d960ff0fb1611727292cfc4 Reviewed-on: https://go-review.googlesource.com/c/go/+/680335 Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Jorropo <jorropo.pgm@gmail.com> Reviewed-by: Mark Freeman <mark@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
5e94d72158
commit
89a0af86b8
3 changed files with 53 additions and 2 deletions
|
|
@ -87,6 +87,10 @@ type regInfo struct {
|
|||
// clobbers encodes the set of registers that are overwritten by
|
||||
// the instruction (other than the output registers).
|
||||
clobbers regMask
|
||||
// Instruction clobbers the register containing input 0.
|
||||
clobbersArg0 bool
|
||||
// Instruction clobbers the register containing input 1.
|
||||
clobbersArg1 bool
|
||||
// outputs[i] encodes the set of registers allowed for the i'th output.
|
||||
outputs []regMask
|
||||
}
|
||||
|
|
@ -293,7 +297,7 @@ func genOp() {
|
|||
fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
|
||||
|
||||
if v.rematerializeable {
|
||||
if v.reg.clobbers != 0 {
|
||||
if v.reg.clobbers != 0 || v.reg.clobbersArg0 || v.reg.clobbersArg1 {
|
||||
log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
|
||||
}
|
||||
if v.clobberFlags {
|
||||
|
|
@ -402,6 +406,12 @@ func genOp() {
|
|||
if v.reg.clobbers > 0 {
|
||||
fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
|
||||
}
|
||||
if v.reg.clobbersArg0 {
|
||||
fmt.Fprintf(w, "clobbersArg0: true,\n")
|
||||
}
|
||||
if v.reg.clobbersArg1 {
|
||||
fmt.Fprintf(w, "clobbersArg1: true,\n")
|
||||
}
|
||||
|
||||
// reg outputs
|
||||
s = s[:0]
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@ type regInfo struct {
|
|||
// clobbers encodes the set of registers that are overwritten by
|
||||
// the instruction (other than the output registers).
|
||||
clobbers regMask
|
||||
// Instruction clobbers the register containing input 0.
|
||||
clobbersArg0 bool
|
||||
// Instruction clobbers the register containing input 1.
|
||||
clobbersArg1 bool
|
||||
// outputs is the same as inputs, but for the outputs of the instruction.
|
||||
outputs []outputInfo
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1686,8 +1686,38 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok:
|
||||
for i := 0; i < 2; i++ {
|
||||
if !(i == 0 && regspec.clobbersArg0 || i == 1 && regspec.clobbersArg1) {
|
||||
continue
|
||||
}
|
||||
if !s.liveAfterCurrentInstruction(v.Args[i]) {
|
||||
// arg is dead. We can clobber its register.
|
||||
continue
|
||||
}
|
||||
if s.values[v.Args[i].ID].rematerializeable {
|
||||
// We can rematerialize the input, don't worry about clobbering it.
|
||||
continue
|
||||
}
|
||||
if countRegs(s.values[v.Args[i].ID].regs) >= 2 {
|
||||
// We have at least 2 copies of arg. We can afford to clobber one.
|
||||
continue
|
||||
}
|
||||
// Possible new registers to copy into.
|
||||
m := s.compatRegs(v.Args[i].Type) &^ s.used
|
||||
if m == 0 {
|
||||
// No free registers. In this case we'll just clobber the
|
||||
// input and future uses of that input must use a restore.
|
||||
// TODO(khr): We should really do this like allocReg does it,
|
||||
// spilling the value with the most distant next use.
|
||||
continue
|
||||
}
|
||||
// Copy input to a new clobberable register.
|
||||
c := s.allocValToReg(v.Args[i], m, true, v.Pos)
|
||||
s.copies[c] = false
|
||||
args[i] = c
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -1709,6 +1739,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
s.tmpused |= regMask(1) << tmpReg
|
||||
}
|
||||
|
||||
if regspec.clobbersArg0 {
|
||||
s.freeReg(register(s.f.getHome(args[0].ID).(*Register).num))
|
||||
}
|
||||
if regspec.clobbersArg1 {
|
||||
s.freeReg(register(s.f.getHome(args[1].ID).(*Register).num))
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue