Josh Bleecher Snyder would like Keith Randall to review this change.
cmd/compile: free doomed registers at loop headers
At the header of a loop that makes an unavoidable call,
values that are unused before that call needn't be in registers.
The call will clobber them anyway,
and the back-edge will do pointless reloads.
Free them. They'll be loaded lazily again when needed.
This shrinks total generated code size for std a bit,
from -0.07% to -0.2% depending on GOARCH.
More interesting, I instrumented the toolchain to
count spills at runtime on amd64.
Using the compiler as a test case, this reduces
spills by 3.1% while building std+cmd.
Using a subset of std tests that have fairly
stable execution paths as a test case, spills drop 2%.
There are a few microbenchmarks that jump noticeably,
such as a 16% sort.StableInt1K speed-up on arm64,
and a few minor regressions,
but most I tried are either neutral or small improvements,
which is about what you'd expect from
an average 2% reduction in spills.
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index b2aea33..1aee9b8 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -1379,6 +1379,28 @@
}
}
+ // Look for loop headers of loops that contain unavoidable calls.
+ // That call will clobber all registers.
+ // Any value that's unused before the first such call is doomed.
+ // To avoid pointless backedge reloads, free such doomed values instead,
+ // and reload them lazily at their first use, after the call.
+ //
+ // v := ... // in a register
+ // for ... {
+ // ... // no use of v
+ // f() // clobbers registers
+ // ... = v // reload v here, not on the backedge
+ // }
+ doomDist := int32(math.MaxInt32)
+ if l := s.loopnest.b2l[b.ID]; l != nil && l.header == b && l.containsUnavoidableCall {
+ // The first call, if any, is at s.nextCall[0].
+ // A call in a later block is at least unlikelyDistance away.
+ doomDist = unlikelyDistance
+ if len(s.nextCall) > 0 {
+ doomDist = min(doomDist, s.nextCall[0])
+ }
+ }
+
// Save the starting state for use by merge edges.
// We append to a stack allocated variable that we'll
// later copy into s.startRegs in one fell swoop, to save
@@ -1394,6 +1416,11 @@
// specially during merge edge processing.
continue
}
+ // Drop values doomed by an intervening unavoidable call.
+ if s.values[v.ID].uses.dist >= doomDist && s.allocatable.hasReg(r) && !opcodeTable[v.Op].fixedReg {
+ s.freeReg(r)
+ continue
+ }
regList = append(regList, startReg{r, v, s.regs[r].c, s.values[v.ID].uses.pos})
s.startRegsMask = s.startRegsMask.addReg(r)
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
cmd/compile: free doomed registers at loop headers
At the header of a loop that makes an unavoidable call,
values that are unused before that call needn't be in registers.
The call will clobber them anyway,
and the back-edge will do pointless reloads.
Free them. They'll be loaded lazily again when needed.
This shrinks total generated code size for std a bit,
from -0.07% to -0.2% depending on GOARCH.
More interesting, I instrumented the toolchain to
count spills at runtime on amd64.
Using the compiler as a test case, this reduces
spills by 3.1% while building std+cmd.
Using a subset of std tests that have fairly
stable execution paths as a test case, spills drop 2%.
There are a few microbenchmarks that jump noticeably,
such as a 16% sort.StableInt1K speed-up on arm64,
and a few minor regressions,
but most I tried are either neutral or small improvements,
which is about what you'd expect from
an average 2% reduction in spills.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |