mirror of
https://github.com/golang/go
synced 2024-11-19 09:44:46 -07:00
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:
parent
368507bb6f
commit
7c18f8cdc3
@ -300,113 +300,97 @@ func dgostrlitptr(s *Sym, off int, lit *string) int {
|
||||
return duintptr(s, off, 0)
|
||||
}
|
||||
off = int(Rnd(int64(off), int64(Widthptr)))
|
||||
p := Thearch.Gins(obj.ADATA, nil, nil)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Name = obj.NAME_EXTERN
|
||||
p.From.Sym = Linksym(s)
|
||||
p.From.Offset = int64(off)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(Widthptr)
|
||||
datagostring(*lit, &p.To)
|
||||
p.To.Type = obj.TYPE_ADDR
|
||||
p.To.Etype = uint8(Simtype[TINT])
|
||||
symhdr, _ := stringsym(*lit)
|
||||
Linksym(s).WriteAddr(Ctxt, int64(off), int64(Widthptr), Linksym(symhdr), 0)
|
||||
off += Widthptr
|
||||
|
||||
return off
|
||||
}
|
||||
|
||||
func dsname(s *Sym, off int, t string) int {
|
||||
p := Thearch.Gins(obj.ADATA, nil, nil)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Name = obj.NAME_EXTERN
|
||||
p.From.Offset = int64(off)
|
||||
p.From.Sym = Linksym(s)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(len(t))
|
||||
|
||||
p.To.Type = obj.TYPE_SCONST
|
||||
p.To.Val = t
|
||||
Linksym(s).WriteString(Ctxt, int64(off), int64(len(t)), t)
|
||||
return off + len(t)
|
||||
}
|
||||
|
||||
func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
|
||||
off = int(Rnd(int64(off), int64(Widthptr)))
|
||||
|
||||
p := Thearch.Gins(obj.ADATA, nil, nil)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Name = obj.NAME_EXTERN
|
||||
p.From.Sym = Linksym(s)
|
||||
p.From.Offset = int64(off)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(Widthptr)
|
||||
p.To.Type = obj.TYPE_ADDR
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = Linksym(x)
|
||||
p.To.Offset = int64(xoff)
|
||||
Linksym(s).WriteAddr(Ctxt, int64(off), int64(Widthptr), Linksym(x), int64(xoff))
|
||||
off += Widthptr
|
||||
|
||||
return off
|
||||
}
|
||||
|
||||
func gdata(nam *Node, nr *Node, wid int) {
|
||||
if nr.Op == OLITERAL {
|
||||
if nam.Op != ONAME {
|
||||
Fatalf("gdata nam op %v", opnames[nam.Op])
|
||||
}
|
||||
if nam.Sym == nil {
|
||||
Fatalf("gdata nil nam sym")
|
||||
}
|
||||
|
||||
switch nr.Op {
|
||||
case OLITERAL:
|
||||
switch nr.Val().Ctype() {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr.Val().U.(*Mpcplx))
|
||||
return
|
||||
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr.Val().U.(string))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
p := Thearch.Gins(obj.ADATA, nam, nr)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(wid)
|
||||
case CTINT, CTRUNE, CTBOOL:
|
||||
i, _ := nr.IntLiteral()
|
||||
Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, int64(wid), i)
|
||||
|
||||
case CTFLT:
|
||||
s := Linksym(nam.Sym)
|
||||
f := mpgetflt(nr.Val().U.(*Mpflt))
|
||||
switch nam.Type.Etype {
|
||||
case TFLOAT32:
|
||||
s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
|
||||
case TFLOAT64:
|
||||
s.WriteFloat64(Ctxt, nam.Xoffset, f)
|
||||
}
|
||||
|
||||
default:
|
||||
// CTNILs don't reach gdata; search for CTNIL in sinit.go. Probably they should, eventually.
|
||||
Fatalf("gdata unhandled OLITERAL %v", nr)
|
||||
}
|
||||
|
||||
case OADDR:
|
||||
if nr.Left.Op != ONAME {
|
||||
Fatalf("gdata ADDR left op %s", opnames[nr.Left.Op])
|
||||
}
|
||||
to := nr.Left
|
||||
Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, int64(wid), Linksym(to.Sym), to.Xoffset)
|
||||
|
||||
case ONAME:
|
||||
if nr.Class != PFUNC {
|
||||
Fatalf("gdata NAME not PFUNC %d", nr.Class)
|
||||
}
|
||||
Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, int64(wid), Linksym(funcsym(nr.Sym)), nr.Xoffset)
|
||||
|
||||
default:
|
||||
Fatalf("gdata unhandled op %v %v\n", nr, opnames[nr.Op])
|
||||
}
|
||||
}
|
||||
|
||||
func gdatacomplex(nam *Node, cval *Mpcplx) {
|
||||
cst := cplxsubtype(nam.Type.Etype)
|
||||
w := int(Types[cst].Width)
|
||||
t := Types[cplxsubtype(nam.Type.Etype)]
|
||||
r := mpgetflt(&cval.Real)
|
||||
i := mpgetflt(&cval.Imag)
|
||||
s := Linksym(nam.Sym)
|
||||
|
||||
p := Thearch.Gins(obj.ADATA, nam, nil)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(w)
|
||||
p.To.Type = obj.TYPE_FCONST
|
||||
p.To.Val = mpgetflt(&cval.Real)
|
||||
|
||||
p = Thearch.Gins(obj.ADATA, nam, nil)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(w)
|
||||
p.From.Offset += int64(w)
|
||||
p.To.Type = obj.TYPE_FCONST
|
||||
p.To.Val = mpgetflt(&cval.Imag)
|
||||
switch t.Etype {
|
||||
case TFLOAT32:
|
||||
s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
|
||||
s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
|
||||
case TFLOAT64:
|
||||
s.WriteFloat64(Ctxt, nam.Xoffset, r)
|
||||
s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
|
||||
}
|
||||
}
|
||||
|
||||
func gdatastring(nam *Node, sval string) {
|
||||
var nod1 Node
|
||||
|
||||
p := Thearch.Gins(obj.ADATA, nam, nil)
|
||||
Datastring(sval, &p.To)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = Types[Tptr].Width
|
||||
p.To.Type = obj.TYPE_ADDR
|
||||
|
||||
//print("%v\n", p);
|
||||
|
||||
Nodconst(&nod1, Types[TINT], int64(len(sval)))
|
||||
|
||||
p = Thearch.Gins(obj.ADATA, nam, &nod1)
|
||||
p.From3 = new(obj.Addr)
|
||||
p.From3.Type = obj.TYPE_CONST
|
||||
p.From3.Offset = int64(Widthint)
|
||||
p.From.Offset += int64(Widthptr)
|
||||
s := Linksym(nam.Sym)
|
||||
_, symdata := stringsym(sval)
|
||||
s.WriteAddr(Ctxt, nam.Xoffset, Types[Tptr].Width, Linksym(symdata), 0)
|
||||
s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), int64(Widthint), int64(len(sval)))
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user