cmd/compile: add clobberdeadreg mode

When -clobberdeadreg flag is set, the compiler inserts code that
clobbers integer registers at call sites. This may be helpful for
debugging register ABI.

Only implemented on AMD64 for now.

Change-Id: Ia203d3f891c30fd95d0103489056fe01d63a2899
Reviewed-on: https://go-review.googlesource.com/c/go/+/302809
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Zhang 2021-03-17 19:15:38 -04:00
parent 9f2a71b6e7
commit 6ae3b70ef2
17 changed files with 103 additions and 8 deletions

View file

@ -114,6 +114,7 @@
package ssa
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/objabi"
@ -301,6 +302,9 @@ type regAllocState struct {
// blockOrder[b.ID] corresponds to the index of block b in visitOrder.
blockOrder []int32
// whether to insert instructions that clobber dead registers at call sites
doClobber bool
}
type endReg struct {
@ -339,6 +343,17 @@ func (s *regAllocState) freeRegs(m regMask) {
}
}
// clobberRegs inserts instructions that clobber registers listed in m.
func (s *regAllocState) clobberRegs(m regMask) {
m &= s.allocatable & s.f.Config.gpRegMask // only integer register can contain pointers, only clobber them
for m != 0 {
r := pickReg(m)
m &^= 1 << r
x := s.curBlock.NewValue0(src.NoXPos, OpClobberReg, types.TypeVoid)
s.f.setHome(x, &s.registers[r])
}
}
// setOrig records that c's original value is the same as
// v's original value.
func (s *regAllocState) setOrig(c *Value, v *Value) {
@ -700,6 +715,14 @@ func (s *regAllocState) init(f *Func) {
}
}
}
// The clobberdeadreg experiment inserts code to clobber dead registers
// at call sites.
// Ignore huge functions to avoid doing too much work.
if base.Flag.ClobberDeadReg && len(s.f.Blocks) <= 10000 {
// TODO: honor GOCLOBBERDEADHASH, or maybe GOSSAHASH.
s.doClobber = true
}
}
// Adds a use record for id at distance dist from the start of the block.
@ -1314,6 +1337,9 @@ func (s *regAllocState) regalloc(f *Func) {
}
if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
// No register allocation required (or none specified yet)
if s.doClobber && v.Op.IsCall() {
s.clobberRegs(regspec.clobbers)
}
s.freeRegs(regspec.clobbers)
b.Values = append(b.Values, v)
s.advanceUses(v)
@ -1475,6 +1501,11 @@ func (s *regAllocState) regalloc(f *Func) {
}
// Dump any registers which will be clobbered
if s.doClobber && v.Op.IsCall() {
// clobber registers that are marked as clobber in regmask, but
// don't clobber inputs.
s.clobberRegs(regspec.clobbers &^ s.tmpused &^ s.nospill)
}
s.freeRegs(regspec.clobbers)
s.tmpused |= regspec.clobbers