mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: decouple emitted block order from regalloc block order
While tinkering with different block orders for the preemptible loop experiment, crashed the register allocator with a "bad" one (these exist). Realized that one knob was controlling two things (register allocation and branch patterns) and decided that life would be simpler if the two orders were independent. Ran some experiments and determined that we have probably, mostly, been optimizing for register allocation effects, not branch effects. Bad block orders for register allocation are somewhat costly. This will also allow separate experimentation with perhaps- better block orders for register allocation. Change-Id: I6ecf2f24cca178b6f8acc0d3c4caaef043c11ed9 Reviewed-on: https://go-review.googlesource.com/47314 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
a66af7280d
commit
c18ff18465
2 changed files with 50 additions and 15 deletions
|
|
@ -283,6 +283,9 @@ type regAllocState struct {
|
|||
copies map[*Value]bool
|
||||
|
||||
loopnest *loopnest
|
||||
|
||||
// choose a good order in which to visit blocks for allocation purposes.
|
||||
visitOrder []*Block
|
||||
}
|
||||
|
||||
type endReg struct {
|
||||
|
|
@ -589,11 +592,23 @@ func (s *regAllocState) init(f *Func) {
|
|||
s.allocatable &^= 1 << 15 // X7 disallowed (one 387 register is used as scratch space during SSE->387 generation in ../x86/387.go)
|
||||
}
|
||||
|
||||
// Linear scan register allocation can be influenced by the order in which blocks appear.
|
||||
// Decouple the register allocation order from the generated block order.
|
||||
// This also creates an opportunity for experiments to find a better order.
|
||||
s.visitOrder = layoutRegallocOrder(f)
|
||||
|
||||
// Compute block order. This array allows us to distinguish forward edges
|
||||
// from backward edges and compute how far they go.
|
||||
blockOrder := make([]int32, f.NumBlocks())
|
||||
for i, b := range s.visitOrder {
|
||||
blockOrder[b.ID] = int32(i)
|
||||
}
|
||||
|
||||
s.regs = make([]regState, s.numRegs)
|
||||
s.values = make([]valState, f.NumValues())
|
||||
s.orig = make([]*Value, f.NumValues())
|
||||
s.copies = make(map[*Value]bool)
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
for _, v := range b.Values {
|
||||
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
|
||||
s.values[v.ID].needReg = true
|
||||
|
|
@ -606,16 +621,9 @@ func (s *regAllocState) init(f *Func) {
|
|||
}
|
||||
s.computeLive()
|
||||
|
||||
// Compute block order. This array allows us to distinguish forward edges
|
||||
// from backward edges and compute how far they go.
|
||||
blockOrder := make([]int32, f.NumBlocks())
|
||||
for i, b := range f.Blocks {
|
||||
blockOrder[b.ID] = int32(i)
|
||||
}
|
||||
|
||||
// Compute primary predecessors.
|
||||
s.primary = make([]int32, f.NumBlocks())
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
best := -1
|
||||
for i, e := range b.Preds {
|
||||
p := e.b
|
||||
|
|
@ -728,7 +736,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
f.Fatalf("entry block must be first")
|
||||
}
|
||||
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("Begin processing block %v\n", b)
|
||||
}
|
||||
|
|
@ -1544,7 +1552,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
}
|
||||
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
i := 0
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpInvalid {
|
||||
|
|
@ -1562,7 +1570,7 @@ func (s *regAllocState) placeSpills() {
|
|||
|
||||
// Precompute some useful info.
|
||||
phiRegs := make([]regMask, f.NumBlocks())
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
var m regMask
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi {
|
||||
|
|
@ -1672,7 +1680,7 @@ func (s *regAllocState) placeSpills() {
|
|||
|
||||
// Insert spill instructions into the block schedules.
|
||||
var oldSched []*Value
|
||||
for _, b := range f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
nphi := 0
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi {
|
||||
|
|
@ -1701,7 +1709,7 @@ func (s *regAllocState) shuffle(stacklive [][]ID) {
|
|||
fmt.Println(s.f.String())
|
||||
}
|
||||
|
||||
for _, b := range s.f.Blocks {
|
||||
for _, b := range s.visitOrder {
|
||||
if len(b.Preds) <= 1 {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue