// 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
}
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 {
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]
// 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
}
}
}
}
-
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
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