mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/internal/gc, cmd/internal/ld, cmd/internal/obj: teach compiler about local symbols
This lets us avoid loading string constants via the GOT and (together with http://golang.org/cl/9102) results in the fannkuch benchmark having very similar register usage with -dynlink as without. Change-Id: Ic3892b399074982b76773c3e547cfbba5dabb6f9 Reviewed-on: https://go-review.googlesource.com/9103 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
0e6a6c510f
commit
029c7bbdfe
11 changed files with 55 additions and 37 deletions
|
|
@ -299,7 +299,7 @@ func proginfo(p *obj.Prog) {
|
||||||
if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
|
if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || p.From.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_EXTERN {
|
if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || (p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local) || (p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local) {
|
||||||
info.Reguse |= R15
|
info.Reguse |= R15
|
||||||
info.Regset |= R15
|
info.Regset |= R15
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,15 @@ func ggloblnod(nam *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ggloblsym(s *Sym, width int32, flags int8) {
|
func ggloblsym(s *Sym, width int32, flags int16) {
|
||||||
p := Thearch.Gins(obj.AGLOBL, nil, nil)
|
p := Thearch.Gins(obj.AGLOBL, nil, nil)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_EXTERN
|
p.From.Name = obj.NAME_EXTERN
|
||||||
p.From.Sym = Linksym(s)
|
p.From.Sym = Linksym(s)
|
||||||
|
if flags&obj.LOCAL != 0 {
|
||||||
|
p.From.Sym.Local = true
|
||||||
|
flags &= ^obj.LOCAL
|
||||||
|
}
|
||||||
p.To.Type = obj.TYPE_CONST
|
p.To.Type = obj.TYPE_CONST
|
||||||
p.To.Offset = int64(width)
|
p.To.Offset = int64(width)
|
||||||
p.From3.Offset = int64(flags)
|
p.From3.Offset = int64(flags)
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ func stringsym(s string) *Sym {
|
||||||
|
|
||||||
off = duint8(sym, off, 0) // terminating NUL for runtime
|
off = duint8(sym, off, 0) // terminating NUL for runtime
|
||||||
off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
|
off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
|
||||||
ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA)
|
ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||||
|
|
||||||
return sym
|
return sym
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +269,7 @@ func slicebytes(nam *Node, s string, len int) {
|
||||||
off = dsname(sym, off, s[n:n+m])
|
off = dsname(sym, off, s[n:n+m])
|
||||||
}
|
}
|
||||||
|
|
||||||
ggloblsym(sym, int32(off), obj.NOPTR)
|
ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
|
||||||
|
|
||||||
if nam.Op != ONAME {
|
if nam.Op != ONAME {
|
||||||
Fatal("slicebytes %v", nam)
|
Fatal("slicebytes %v", nam)
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ func emitptrargsmap() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ggloblsym(sym, int32(off), obj.RODATA)
|
ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the list of stack variables. Autos after anything else,
|
// Sort the list of stack variables. Autos after anything else,
|
||||||
|
|
|
||||||
|
|
@ -814,7 +814,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
||||||
for i := 0; i < 2*Widthptr; i++ {
|
for i := 0; i < 2*Widthptr; i++ {
|
||||||
duint8(sbits, i, gcmask[i])
|
duint8(sbits, i, gcmask[i])
|
||||||
}
|
}
|
||||||
ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA)
|
ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
ot = dsymptr(s, ot, sbits, 0)
|
ot = dsymptr(s, ot, sbits, 0)
|
||||||
|
|
@ -1203,7 +1203,7 @@ ok:
|
||||||
}
|
}
|
||||||
|
|
||||||
ot = dextratype(s, ot, t, xt)
|
ot = dextratype(s, ot, t, xt)
|
||||||
ggloblsym(s, int32(ot), int8(dupok|obj.RODATA))
|
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
|
||||||
|
|
||||||
// generate typelink.foo pointing at s = type.foo.
|
// generate typelink.foo pointing at s = type.foo.
|
||||||
// The linker will leave a table of all the typelinks for
|
// The linker will leave a table of all the typelinks for
|
||||||
|
|
@ -1229,7 +1229,7 @@ ok:
|
||||||
case TARRAY, TCHAN, TFUNC, TMAP:
|
case TARRAY, TCHAN, TFUNC, TMAP:
|
||||||
slink := typelinksym(t)
|
slink := typelinksym(t)
|
||||||
dsymptr(slink, 0, s, 0)
|
dsymptr(slink, 0, s, 0)
|
||||||
ggloblsym(slink, int32(Widthptr), int8(dupok|obj.RODATA))
|
ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,12 @@ func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
|
||||||
if v != 0 && v != 1 {
|
if v != 0 && v != 1 {
|
||||||
log.Fatalf("invalid symbol version %d", v)
|
log.Fatalf("invalid symbol version %d", v)
|
||||||
}
|
}
|
||||||
dupok := int(rdint(f))
|
flags := int(rdint(f))
|
||||||
dupok &= 1
|
dupok := flags & 1
|
||||||
|
local := false
|
||||||
|
if flags&2 != 0 {
|
||||||
|
local = true
|
||||||
|
}
|
||||||
size := int(rdint(f))
|
size := int(rdint(f))
|
||||||
typ := rdsym(ctxt, f, pkg)
|
typ := rdsym(ctxt, f, pkg)
|
||||||
var data []byte
|
var data []byte
|
||||||
|
|
@ -125,6 +129,7 @@ overwrite:
|
||||||
if s.Size < int64(size) {
|
if s.Size < int64(size) {
|
||||||
s.Size = int64(size)
|
s.Size = int64(size)
|
||||||
}
|
}
|
||||||
|
s.Local = local
|
||||||
if typ != nil { // if bss sym defined multiple times, take type from any one def
|
if typ != nil { // if bss sym defined multiple times, take type from any one def
|
||||||
s.Gotype = typ
|
s.Gotype = typ
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -373,15 +373,7 @@ func symtab() {
|
||||||
// just defined above will be first.
|
// just defined above will be first.
|
||||||
// hide the specific symbols.
|
// hide the specific symbols.
|
||||||
for s := Ctxt.Allsym; s != nil; s = s.Allsym {
|
for s := Ctxt.Allsym; s != nil; s = s.Allsym {
|
||||||
if !s.Reachable || s.Special != 0 {
|
if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(s.Name, "..gostring.") || strings.Contains(s.Name, "..gobytes.") {
|
|
||||||
s.Local = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Type != obj.SRODATA {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,7 @@ const (
|
||||||
A_ARCHSPECIFIC
|
A_ARCHSPECIFIC
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// An LSym is the sort of symbol that is written to an object file.
|
||||||
type LSym struct {
|
type LSym struct {
|
||||||
Name string
|
Name string
|
||||||
Type int16
|
Type int16
|
||||||
|
|
@ -283,6 +284,13 @@ type LSym struct {
|
||||||
Leaf uint8
|
Leaf uint8
|
||||||
Seenglobl uint8
|
Seenglobl uint8
|
||||||
Onlist uint8
|
Onlist uint8
|
||||||
|
// Local means make the symbol local even when compiling Go code to reference Go
|
||||||
|
// symbols in other shared libraries, as in this mode symbols are global by
|
||||||
|
// default. "local" here means in the sense of the dynamic linker, i.e. not
|
||||||
|
// visible outside of the module (shared library or executable) that contains its
|
||||||
|
// definition. (When not compiling to support Go shared libraries, all symbols are
|
||||||
|
// local in this sense unless there is a cgo_export_* directive).
|
||||||
|
Local bool
|
||||||
Args int32
|
Args int32
|
||||||
Locals int32
|
Locals int32
|
||||||
Value int64
|
Value int64
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,11 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) {
|
||||||
wrint(b, int64(s.Type))
|
wrint(b, int64(s.Type))
|
||||||
wrstring(b, s.Name)
|
wrstring(b, s.Name)
|
||||||
wrint(b, int64(s.Version))
|
wrint(b, int64(s.Version))
|
||||||
wrint(b, int64(s.Dupok))
|
flags := int64(s.Dupok)
|
||||||
|
if s.Local {
|
||||||
|
flags |= 2
|
||||||
|
}
|
||||||
|
wrint(b, flags)
|
||||||
wrint(b, s.Size)
|
wrint(b, s.Size)
|
||||||
wrsym(b, s.Gotype)
|
wrsym(b, s.Gotype)
|
||||||
wrdata(b, s.P)
|
wrdata(b, s.P)
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,7 @@ const (
|
||||||
|
|
||||||
// This function uses its incoming context register.
|
// This function uses its incoming context register.
|
||||||
NEEDCTXT = 64
|
NEEDCTXT = 64
|
||||||
|
|
||||||
|
// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
|
||||||
|
LOCAL = 128
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_EXTERN
|
p.From.Name = obj.NAME_EXTERN
|
||||||
p.From.Sym = s
|
p.From.Sym = s
|
||||||
|
p.From.Sym.Local = true
|
||||||
p.From.Offset = 0
|
p.From.Offset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,6 +295,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_EXTERN
|
p.From.Name = obj.NAME_EXTERN
|
||||||
p.From.Sym = s
|
p.From.Sym = s
|
||||||
|
p.From.Sym.Local = true
|
||||||
p.From.Offset = 0
|
p.From.Offset = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -327,11 +329,11 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctxt.Flag_dynlink {
|
if ctxt.Flag_dynlink {
|
||||||
if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN {
|
if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
p.As = AMOVQ
|
p.As = AMOVQ
|
||||||
p.From.Type = obj.TYPE_ADDR
|
p.From.Type = obj.TYPE_ADDR
|
||||||
}
|
}
|
||||||
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN {
|
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
if p.As != AMOVQ {
|
if p.As != AMOVQ {
|
||||||
ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
|
ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
|
||||||
}
|
}
|
||||||
|
|
@ -356,12 +358,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||||
ctxt.Diag("don't know how to handle %v with -dynlink", p)
|
ctxt.Diag("don't know how to handle %v with -dynlink", p)
|
||||||
}
|
}
|
||||||
var source *obj.Addr
|
var source *obj.Addr
|
||||||
if p.From.Name == obj.NAME_EXTERN {
|
if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
if p.To.Name == obj.NAME_EXTERN {
|
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
|
||||||
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
|
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
|
||||||
}
|
}
|
||||||
source = &p.From
|
source = &p.From
|
||||||
} else if p.To.Name == obj.NAME_EXTERN {
|
} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
|
||||||
source = &p.To
|
source = &p.To
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue