mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: optimize make+copy pattern to avoid memclr
match: m = make([]T, x); copy(m, s) for pointer free T and x==len(s) rewrite to: m = mallocgc(x*elemsize(T), nil, false); memmove(&m, &s, x*elemsize(T)) otherwise rewrite to: m = makeslicecopy([]T, x, s) This avoids memclear and shading of pointers in the newly created slice before the copy. With this CL "s" is only be allowed to bev a variable and not a more complex expression. This restriction could be lifted in future versions of this optimization when it can be proven that "s" is not referencing "m". Triggers 450 times during make.bash.. Reduces go binary size by ~8 kbyte. name old time/op new time/op delta MakeSliceCopy/mallocmove/Byte 71.1ns ± 1% 65.8ns ± 0% -7.49% (p=0.000 n=10+9) MakeSliceCopy/mallocmove/Int 71.2ns ± 1% 66.0ns ± 0% -7.27% (p=0.000 n=10+8) MakeSliceCopy/mallocmove/Ptr 104ns ± 4% 99ns ± 1% -5.13% (p=0.000 n=10+10) MakeSliceCopy/makecopy/Byte 70.3ns ± 0% 68.0ns ± 0% -3.22% (p=0.000 n=10+9) MakeSliceCopy/makecopy/Int 70.3ns ± 0% 68.5ns ± 1% -2.59% (p=0.000 n=9+10) MakeSliceCopy/makecopy/Ptr 102ns ± 0% 99ns ± 1% -2.97% (p=0.000 n=9+9) MakeSliceCopy/nilappend/Byte 75.4ns ± 0% 74.9ns ± 2% -0.63% (p=0.015 n=9+9) MakeSliceCopy/nilappend/Int 75.6ns ± 0% 76.4ns ± 3% ~ (p=0.245 n=9+10) MakeSliceCopy/nilappend/Ptr 107ns ± 0% 108ns ± 1% +0.93% (p=0.005 n=9+10) Fixes #26252 Change-Id: Iec553dd1fef6ded16197216a472351c8799a8e71 Reviewed-on: https://go-review.googlesource.com/c/go/+/146719 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Martin Möhrmann <moehrmann@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
97240d546c
commit
6ed4661807
12 changed files with 1160 additions and 503 deletions
|
|
@ -208,12 +208,16 @@ func (n *Node) MarkNonNil() {
|
|||
// SetBounded indicates whether operation n does not need safety checks.
|
||||
// When n is an index or slice operation, n does not need bounds checks.
|
||||
// When n is a dereferencing operation, n does not need nil checks.
|
||||
// When n is a makeslice+copy operation, n does not need length and cap checks.
|
||||
func (n *Node) SetBounded(b bool) {
|
||||
switch n.Op {
|
||||
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
|
||||
// No bounds checks needed.
|
||||
case ODOTPTR, ODEREF:
|
||||
// No nil check needed.
|
||||
case OMAKESLICECOPY:
|
||||
// No length and cap checks needed
|
||||
// since new slice and copied over slice data have same length.
|
||||
default:
|
||||
Fatalf("SetBounded(%v)", n)
|
||||
}
|
||||
|
|
@ -714,30 +718,38 @@ const (
|
|||
ODCLCONST // const pi = 3.14
|
||||
ODCLTYPE // type Int int or type Int = int
|
||||
|
||||
ODELETE // delete(Left, Right)
|
||||
ODOT // Left.Sym (Left is of struct type)
|
||||
ODOTPTR // Left.Sym (Left is of pointer to struct type)
|
||||
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
|
||||
ODOTINTER // Left.Sym (Left is interface, Right is method name)
|
||||
OXDOT // Left.Sym (before rewrite to one of the preceding)
|
||||
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
|
||||
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
|
||||
OEQ // Left == Right
|
||||
ONE // Left != Right
|
||||
OLT // Left < Right
|
||||
OLE // Left <= Right
|
||||
OGE // Left >= Right
|
||||
OGT // Left > Right
|
||||
ODEREF // *Left
|
||||
OINDEX // Left[Right] (index of array or slice)
|
||||
OINDEXMAP // Left[Right] (index of map)
|
||||
OKEY // Left:Right (key:value in struct/array/map literal)
|
||||
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
|
||||
OLEN // len(Left)
|
||||
OMAKE // make(List) (before type checking converts to one of the following)
|
||||
OMAKECHAN // make(Type, Left) (type is chan)
|
||||
OMAKEMAP // make(Type, Left) (type is map)
|
||||
OMAKESLICE // make(Type, Left, Right) (type is slice)
|
||||
ODELETE // delete(Left, Right)
|
||||
ODOT // Left.Sym (Left is of struct type)
|
||||
ODOTPTR // Left.Sym (Left is of pointer to struct type)
|
||||
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
|
||||
ODOTINTER // Left.Sym (Left is interface, Right is method name)
|
||||
OXDOT // Left.Sym (before rewrite to one of the preceding)
|
||||
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
|
||||
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
|
||||
OEQ // Left == Right
|
||||
ONE // Left != Right
|
||||
OLT // Left < Right
|
||||
OLE // Left <= Right
|
||||
OGE // Left >= Right
|
||||
OGT // Left > Right
|
||||
ODEREF // *Left
|
||||
OINDEX // Left[Right] (index of array or slice)
|
||||
OINDEXMAP // Left[Right] (index of map)
|
||||
OKEY // Left:Right (key:value in struct/array/map literal)
|
||||
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
|
||||
OLEN // len(Left)
|
||||
OMAKE // make(List) (before type checking converts to one of the following)
|
||||
OMAKECHAN // make(Type, Left) (type is chan)
|
||||
OMAKEMAP // make(Type, Left) (type is map)
|
||||
OMAKESLICE // make(Type, Left, Right) (type is slice)
|
||||
OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
|
||||
// OMAKESLICECOPY is created by the order pass and corresponds to:
|
||||
// s = make(Type, Left); copy(s, Right)
|
||||
//
|
||||
// Bounded can be set on the node when Left == len(Right) is known at compile time.
|
||||
//
|
||||
// This node is created so the walk pass can optimize this pattern which would
|
||||
// otherwise be hard to detect after the order pass.
|
||||
OMUL // Left * Right
|
||||
ODIV // Left / Right
|
||||
OMOD // Left % Right
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue