]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: write some static data directly
authorJosh Bleecher Snyder <josharian@gmail.com>
Sun, 13 Mar 2016 19:16:43 +0000 (12:16 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Mon, 14 Mar 2016 02:21:43 +0000 (02:21 +0000)
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>
src/cmd/compile/internal/gc/obj.go
src/cmd/internal/obj/data.go

index 52f3354227cdfcccd761ae8b69977a4575a03602..021343868f438647583ceb64e3180849b6bc286e 100644 (file)
@@ -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
+
+               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)
                }
-       }
 
-       p := Thearch.Gins(obj.ADATA, nam, nr)
-       p.From3 = new(obj.Addr)
-       p.From3.Type = obj.TYPE_CONST
-       p.From3.Offset = int64(wid)
+       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)
-
-       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)
+       t := Types[cplxsubtype(nam.Type.Etype)]
+       r := mpgetflt(&cval.Real)
+       i := mpgetflt(&cval.Imag)
+       s := Linksym(nam.Sym)
+
+       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)))
 }
index f4562d993860cf674836971cea7a01d5a68e8bc6..ad31aee7f0857dc3c5672dbdceccbee692fbeea0 100644 (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)