1
0
mirror of https://github.com/golang/go synced 2024-07-03 08:51:14 +00:00

cmd/compile: optimize Move with all-zero ro sym src to Zero

We set up static symbols during walk that
we later make copies of to initialize local variables.
It is difficult to ascertain at that time exactly
when copying a symbol is profitable vs locally
initializing an autotmp.

During SSA, we are much better placed to optimize.
This change recognizes when we are copying from a
global readonly all-zero symbol and replaces it with
direct zeroing.

This often allows the all-zero symbol to be
deadcode eliminated at link time.
This is not ideal--it makes for large object files,
and longer link times--but it is the cleanest fix I could find.

This makes the final binary for the program in #38554
shrink from >500mb to ~2.2mb.

It also shrinks the standard binaries:

file      before    after     Δ       %
addr2line 4412496   4404304   -8192   -0.186%
buildid   2893816   2889720   -4096   -0.142%
cgo       4841048   4832856   -8192   -0.169%
compile   19926480  19922432  -4048   -0.020%
cover     5281816   5277720   -4096   -0.078%
link      6734648   6730552   -4096   -0.061%
nm        4366240   4358048   -8192   -0.188%
objdump   4755968   4747776   -8192   -0.172%
pprof     14653060  14612100  -40960  -0.280%
trace     11805940  11777268  -28672  -0.243%
vet       7185560   7181416   -4144   -0.058%
total     113588440 113465560 -122880 -0.108%

And not just by removing unnecessary symbols;
the program text shrinks a bit as well.

Fixes #38554

Change-Id: I8381ae6084ae145a5e0cd9410c451e52c0dc51c8
Reviewed-on: https://go-review.googlesource.com/c/go/+/229704
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Josh Bleecher Snyder 2020-04-23 13:28:14 -07:00
parent b3e8a00060
commit 4a7e363288
4 changed files with 55 additions and 0 deletions

View File

@ -2020,6 +2020,7 @@
=> (Zero {t} [n] dst1 mem)
(Move {t} [n] dst1 src mem:(VarDef (Zero {t} [n] dst0 _))) && isSamePtr(src, dst0)
=> (Zero {t} [n] dst1 mem)
(Move {t} [n] dst (Addr {sym} (SB)) mem) && symIsROZero(sym) => (Zero {t} [n] dst mem)
// Don't Store to variables that are about to be overwritten by Move/Zero.
(Zero {t1} [n] p1 store:(Store {t2} (OffPtr [o2] p2) _ mem))

View File

@ -1381,6 +1381,20 @@ func symIsRO(sym interface{}) bool {
return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
}
// symIsROZero reports whether sym is a read-only global whose data contains all zeros.
func symIsROZero(sym Sym) bool {
lsym := sym.(*obj.LSym)
if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
return false
}
for _, b := range lsym.P {
if b != 0 {
return false
}
}
return true
}
// read8 reads one byte from the read-only global sym at offset off.
func read8(sym interface{}, off int64) uint8 {
lsym := sym.(*obj.LSym)

View File

@ -12447,6 +12447,31 @@ func rewriteValuegeneric_OpMove(v *Value) bool {
v.AddArg2(dst1, mem)
return true
}
// match: (Move {t} [n] dst (Addr {sym} (SB)) mem)
// cond: symIsROZero(sym)
// result: (Zero {t} [n] dst mem)
for {
n := auxIntToInt64(v.AuxInt)
t := auxToType(v.Aux)
dst := v_0
if v_1.Op != OpAddr {
break
}
sym := auxToSym(v_1.Aux)
v_1_0 := v_1.Args[0]
if v_1_0.Op != OpSB {
break
}
mem := v_2
if !(symIsROZero(sym)) {
break
}
v.reset(OpZero)
v.AuxInt = int64ToAuxInt(n)
v.Aux = typeToAux(t)
v.AddArg2(dst, mem)
return true
}
// match: (Move {t1} [n] dst1 src1 store:(Store {t2} op:(OffPtr [o2] dst2) _ mem))
// cond: isSamePtr(dst1, dst2) && store.Uses == 1 && n >= o2 + t2.Size() && disjoint(src1, n, op, t2.Size()) && clobber(store)
// result: (Move {t1} [n] dst1 src1 mem)

View File

@ -0,0 +1,15 @@
// asmcheck
// Copyright 2020 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.
// Test that we are zeroing directly instead of
// copying a large zero value. Issue 38554.
package codegen
func retlarge() [256]byte {
// amd64:-"DUFFCOPY"
return [256]byte{}
}