cmd/compile: allow non-pointer writes in the middle of a write barrier

This lets us combine more write barriers, getting rid of some of the
test+branch and gcWriteBarrier* calls.
With the new write barriers, it's easy to add a few non-pointer writes
to the set of values written.

We allow up to 2 non-pointer writes between pointer writes. This is enough
for, for example, adjacent slice fields.

Fixes #62126

Change-Id: I872d0fa9cc4eb855e270ffc0223b39fde1723c4b
Reviewed-on: https://go-review.googlesource.com/c/go/+/521498
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Keith Randall 2023-08-18 12:44:37 -07:00
parent 0163b3b32c
commit 556e9c5f3e
2 changed files with 69 additions and 0 deletions

View File

@ -250,6 +250,7 @@ func writebarrier(f *Func) {
// to a new block.
var last *Value
var start, end int
var nonPtrStores int
values := b.Values
FindSeq:
for i := len(values) - 1; i >= 0; i-- {
@ -261,8 +262,17 @@ func writebarrier(f *Func) {
last = w
end = i + 1
}
nonPtrStores = 0
case OpVarDef, OpVarLive:
continue
case OpStore:
if last == nil {
continue
}
nonPtrStores++
if nonPtrStores > 2 {
break FindSeq
}
default:
if last == nil {
continue
@ -484,6 +494,10 @@ func writebarrier(f *Func) {
mem.Aux = w.Aux
case OpVarDef, OpVarLive:
mem = bEnd.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, mem)
case OpStore:
ptr := w.Args[0]
val := w.Args[1]
mem = bEnd.NewValue3A(pos, OpStore, types.TypeMem, w.Aux, ptr, val, mem)
}
}

View File

@ -0,0 +1,55 @@
// asmcheck
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package codegen
func combine2string(p *[2]string, a, b string) {
// amd64:`.*runtime[.]gcWriteBarrier4\(SB\)`
// arm64:`.*runtime[.]gcWriteBarrier4\(SB\)`
p[0] = a
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[1] = b
}
func combine4string(p *[4]string, a, b, c, d string) {
// amd64:`.*runtime[.]gcWriteBarrier8\(SB\)`
// arm64:`.*runtime[.]gcWriteBarrier8\(SB\)`
p[0] = a
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[1] = b
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[2] = c
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[3] = d
}
func combine2slice(p *[2][]byte, a, b []byte) {
// amd64:`.*runtime[.]gcWriteBarrier4\(SB\)`
// arm64:`.*runtime[.]gcWriteBarrier4\(SB\)`
p[0] = a
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[1] = b
}
func combine4slice(p *[4][]byte, a, b, c, d []byte) {
// amd64:`.*runtime[.]gcWriteBarrier8\(SB\)`
// arm64:`.*runtime[.]gcWriteBarrier8\(SB\)`
p[0] = a
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[1] = b
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[2] = c
// amd64:-`.*runtime[.]gcWriteBarrier`
// arm64:-`.*runtime[.]gcWriteBarrier`
p[3] = d
}