1
0
mirror of https://github.com/golang/go synced 2024-09-30 17:38:33 -06:00

cmd/compile: allow OpVarXXX calls to be duplicated in writebarrier blocks

OpVarXXX Values don't generate instructions,
so there's no reason not to duplicate them,
and duplicating them generates better code
(fewer branches).

This requires changing the start/end accounting
to correctly handle the case in which we have run
of Values beginning with an OpVarXXX, e.g.
OpVarDef, OpZeroWB, OpMoveWB.
In that case, the sequence of values should begin
at the OpZeroWB, not the OpVarDef.

This also lays the groundwork for experimenting
with allowing duplication of some scalar stores.

Shrinks function text sizes a tiny amount:

name        old object-bytes  new object-bytes  delta
Template           381k ± 0%         381k ± 0%  -0.01%  (p=0.008 n=5+5)
Unicode            203k ± 0%         203k ± 0%  -0.04%  (p=0.008 n=5+5)
GoTypes           1.17M ± 0%        1.17M ± 0%  -0.01%  (p=0.008 n=5+5)
SSA               8.24M ± 0%        8.24M ± 0%  -0.00%  (p=0.008 n=5+5)
Flate              230k ± 0%         230k ± 0%    ~     (all equal)
GoParser           286k ± 0%         286k ± 0%    ~     (all equal)
Reflect           1.00M ± 0%        1.00M ± 0%    ~     (all equal)
Tar                189k ± 0%         189k ± 0%    ~     (all equal)
XML                415k ± 0%         415k ± 0%  -0.01%  (p=0.008 n=5+5)

Updates #19838

Change-Id: Ic5ef30855919f1468066eba08ae5c4bd9a01db27
Reviewed-on: https://go-review.googlesource.com/42011
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Josh Bleecher Snyder 2017-04-27 11:56:46 -07:00
parent 5331e7e9df
commit 94a017f3f5

View File

@ -117,18 +117,23 @@ func writebarrier(f *Func) {
var last *Value
var start, end int
values := b.Values
FindSeq:
for i := len(values) - 1; i >= 0; i-- {
w := values[i]
if w.Op == OpStoreWB || w.Op == OpMoveWB || w.Op == OpZeroWB {
switch w.Op {
case OpStoreWB, OpMoveWB, OpZeroWB:
start = i
if last == nil {
last = w
end = i + 1
}
} else {
if last != nil {
start = i + 1
break
case OpVarDef, OpVarLive, OpVarKill:
continue
default:
if last == nil {
continue
}
break FindSeq
}
}
stores = append(stores[:0], b.Values[start:end]...) // copy to avoid aliasing
@ -190,11 +195,17 @@ func writebarrier(f *Func) {
case OpZeroWB:
fn = typedmemclr
typ = &ExternSymbol{Sym: w.Aux.(*types.Type).Symbol()}
case OpVarDef, OpVarLive, OpVarKill:
}
// then block: emit write barrier call
volatile := w.Op == OpMoveWB && isVolatile(val)
memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, volatile)
switch w.Op {
case OpStoreWB, OpMoveWB, OpZeroWB:
volatile := w.Op == OpMoveWB && isVolatile(val)
memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, volatile)
case OpVarDef, OpVarLive, OpVarKill:
memThen = bThen.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memThen)
}
// else block: normal store
switch w.Op {
@ -206,13 +217,18 @@ func writebarrier(f *Func) {
case OpZeroWB:
memElse = bElse.NewValue2I(pos, OpZero, types.TypeMem, w.AuxInt, ptr, memElse)
memElse.Aux = w.Aux
case OpVarDef, OpVarLive, OpVarKill:
memElse = bElse.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memElse)
}
if !f.WBPos.IsKnown() {
f.WBPos = pos
}
if f.fe.Debug_wb() {
f.Warnl(pos, "write barrier")
if fn != nil {
// Note that we set up a writebarrier function call.
if !f.WBPos.IsKnown() {
f.WBPos = pos
}
if f.fe.Debug_wb() {
f.Warnl(pos, "write barrier")
}
}
}