cmd/compile: write some static data directly

Instead of generating ADATA instructions for
static data, write that static data directly
into the linker sym.
This is considerably more efficient.
The assembler still generates
ADATA instructions, so the ADATA machinery
cannot be dismantled yet. (Future work.)
Skipping ADATA has a significant impact
compiling the unicode package, which has lots
of static data.

name     old time/op    new time/op    delta
Unicode     227ms ±10%     192ms ± 4%  -15.61%  (p=0.000 n=29+30)

name     old alloc/op   new alloc/op   delta
Unicode    51.0MB ± 0%    45.8MB ± 0%  -10.29%  (p=0.000 n=30+30)

name     old allocs/op  new allocs/op  delta
Unicode      610k ± 0%      578k ± 0%   -5.29%  (p=0.000 n=30+30)

This does not pass toolstash -cmp, because
this changes the order in which some relocations
get added, and thus it changes the output from
the compiler. It is not worth the execution time
to sort the relocs in the normal case.

However, compiling with -S -v generates identical
output if (1) you suppress printing of ADATA progs
in flushplist and (2) you suppress printing of
cpu timing. It is reasonable to suppress printing
the ADATA progs, since the data itself is dumped
later. I am therefore fairly confident that all
changes are superficial and non-functional.

Fixes #14786, although there's more to do
in general.

Change-Id: I8dfabe7b423b31a30e516cfdf005b62a2e9ccd82
Reviewed-on: https://go-review.googlesource.com/20645
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Josh Bleecher Snyder 2016-03-13 12:16:43 -07:00
parent 368507bb6f
commit 7c18f8cdc3
2 changed files with 122 additions and 80 deletions

View file

@ -52,6 +52,64 @@ func Symgrow(ctxt *Link, s *LSym, lsiz int64) {
s.P = s.P[:siz]
}
// prepwrite prepares to write data of size siz into s at offset off.
func (s *LSym) prepwrite(ctxt *Link, off, siz int64) {
if off < 0 || siz < 0 || off >= 1<<30 || siz >= 100 {
log.Fatalf("prepwrite: bad off=%d siz=%d", off, siz)
}
if s.Type == SBSS || s.Type == STLSBSS {
ctxt.Diag("cannot supply data for BSS var")
}
Symgrow(ctxt, s, off+siz)
}
// WriteFloat32 writes f into s at offset off.
func (s *LSym) WriteFloat32(ctxt *Link, off int64, f float32) {
s.prepwrite(ctxt, off, 4)
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], math.Float32bits(f))
}
// WriteFloat64 writes f into s at offset off.
func (s *LSym) WriteFloat64(ctxt *Link, off int64, f float64) {
s.prepwrite(ctxt, off, 8)
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], math.Float64bits(f))
}
// WriteInt writes an integer i of size siz into s at offset off.
func (s *LSym) WriteInt(ctxt *Link, off, siz int64, i int64) {
s.prepwrite(ctxt, off, siz)
switch siz {
default:
ctxt.Diag("WriteInt bad integer: %d", siz)
case 1:
s.P[off] = byte(i)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(i))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(i))
}
}
// WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off, siz int64, rsym *LSym, roff int64) {
s.prepwrite(ctxt, off, siz)
r := Addrel(s)
r.Off = int32(off)
r.Siz = uint8(siz)
r.Sym = rsym
r.Type = R_ADDR
r.Add = roff
}
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off, siz int64, str string) {
s.prepwrite(ctxt, off, siz)
copy(s.P[off:off+siz], str)
}
func savedata(ctxt *Link, p *Prog) {
s := p.From.Sym
off := int32(p.From.Offset)