mirror of
https://github.com/golang/go
synced 2024-11-24 10:50:13 -07:00
cmd/compile: optimize remaining convT2I calls
See #14874 Updates #6853 This change adds a compiler optimization for non pointer shaped convT2I. Since itab symbols are now emitted by the compiler, the itab address can be passed directly to convT2I instead of passing the iface type and a cache pointer argument. Compilebench results for the 5-commits series ending here: name old time/op new time/op delta Template 336ms ± 4% 344ms ± 4% +2.61% (p=0.027 n=9+8) Unicode 165ms ± 6% 173ms ± 7% +5.11% (p=0.014 n=9+9) GoTypes 1.09s ± 1% 1.06s ± 2% -3.29% (p=0.000 n=9+9) Compiler 5.09s ±10% 4.75s ±10% -6.64% (p=0.011 n=10+10) MakeBash 31.1s ± 5% 30.3s ± 3% ~ (p=0.089 n=10+10) name old text-bytes new text-bytes delta HelloSize 558k ± 0% 558k ± 0% +0.02% (p=0.000 n=10+10) CmdGoSize 6.24M ± 0% 6.11M ± 0% -2.11% (p=0.000 n=10+10) name old data-bytes new data-bytes delta HelloSize 3.66k ± 0% 3.74k ± 0% +2.41% (p=0.000 n=10+10) CmdGoSize 134k ± 0% 162k ± 0% +20.76% (p=0.000 n=10+10) name old bss-bytes new bss-bytes delta HelloSize 126k ± 0% 126k ± 0% ~ (all samples are equal) CmdGoSize 149k ± 0% 146k ± 0% -2.17% (p=0.000 n=10+10) name old exe-bytes new exe-bytes delta HelloSize 924k ± 0% 924k ± 0% +0.05% (p=0.000 n=10+10) CmdGoSize 9.77M ± 0% 9.62M ± 0% -1.47% (p=0.000 n=10+10) Change-Id: Ib230ddc04988824035c32287ae544a965fedd344 Reviewed-on: https://go-review.googlesource.com/20902 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: David Crawshaw <crawshaw@golang.org> Run-TryBot: Michel Lespinasse <walken@google.com>
This commit is contained in:
parent
7427f2c4bd
commit
859b63cc09
@ -46,11 +46,10 @@ const runtimeimport = "" +
|
|||||||
"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" +
|
"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" +
|
||||||
"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr \"unsafe-uintptr\") (? int)\n" +
|
"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr \"unsafe-uintptr\") (? int)\n" +
|
||||||
"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" +
|
"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" +
|
||||||
"func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" +
|
|
||||||
"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
|
"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
|
||||||
"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" +
|
"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" +
|
||||||
"func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
|
"func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
|
||||||
"func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any, @\"\".buf·6 *any) (@\"\".ret·1 any)\n" +
|
"func @\"\".convT2I (@\"\".tab·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
|
||||||
"func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
|
"func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
|
||||||
"func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
|
"func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
|
||||||
"func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
|
"func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
|
||||||
|
@ -60,11 +60,10 @@ func slicecopy(to any, fr any, wid uintptr) int
|
|||||||
func slicestringcopy(to any, fr any) int
|
func slicestringcopy(to any, fr any) int
|
||||||
|
|
||||||
// interface conversions
|
// interface conversions
|
||||||
func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
|
|
||||||
func convI2E(elem any) (ret any)
|
func convI2E(elem any) (ret any)
|
||||||
func convI2I(typ *byte, elem any) (ret any)
|
func convI2I(typ *byte, elem any) (ret any)
|
||||||
func convT2E(typ *byte, elem, buf *any) (ret any)
|
func convT2E(typ *byte, elem, buf *any) (ret any)
|
||||||
func convT2I(typ *byte, typ2 *byte, cache **byte, elem, buf *any) (ret any)
|
func convT2I(tab *byte, elem, buf *any) (ret any)
|
||||||
|
|
||||||
// interface type assertions x.(T)
|
// interface type assertions x.(T)
|
||||||
func assertE2E(typ *byte, iface any, ret *any)
|
func assertE2E(typ *byte, iface any, ret *any)
|
||||||
|
@ -248,9 +248,7 @@ var localpkg *Pkg // package being compiled
|
|||||||
|
|
||||||
var importpkg *Pkg // package being imported
|
var importpkg *Pkg // package being imported
|
||||||
|
|
||||||
var itabpkg *Pkg // fake pkg for itab cache
|
var itabpkg *Pkg // fake pkg for itab entries
|
||||||
|
|
||||||
var itab2pkg *Pkg // fake pkg for itab entries
|
|
||||||
|
|
||||||
var itablinkpkg *Pkg // fake package for runtime itab entries
|
var itablinkpkg *Pkg // fake package for runtime itab entries
|
||||||
|
|
||||||
|
@ -109,17 +109,14 @@ func Main() {
|
|||||||
|
|
||||||
// pseudo-package, for scoping
|
// pseudo-package, for scoping
|
||||||
builtinpkg = mkpkg("go.builtin")
|
builtinpkg = mkpkg("go.builtin")
|
||||||
|
|
||||||
builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
|
builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
|
||||||
|
|
||||||
// pseudo-package, accessed by import "unsafe"
|
// pseudo-package, accessed by import "unsafe"
|
||||||
unsafepkg = mkpkg("unsafe")
|
unsafepkg = mkpkg("unsafe")
|
||||||
|
|
||||||
unsafepkg.Name = "unsafe"
|
unsafepkg.Name = "unsafe"
|
||||||
|
|
||||||
// real package, referred to by generated runtime calls
|
// real package, referred to by generated runtime calls
|
||||||
Runtimepkg = mkpkg("runtime")
|
Runtimepkg = mkpkg("runtime")
|
||||||
|
|
||||||
Runtimepkg.Name = "runtime"
|
Runtimepkg.Name = "runtime"
|
||||||
|
|
||||||
// pseudo-packages used in symbol tables
|
// pseudo-packages used in symbol tables
|
||||||
@ -127,10 +124,6 @@ func Main() {
|
|||||||
itabpkg.Name = "go.itab"
|
itabpkg.Name = "go.itab"
|
||||||
itabpkg.Prefix = "go.itab" // not go%2eitab
|
itabpkg.Prefix = "go.itab" // not go%2eitab
|
||||||
|
|
||||||
itab2pkg = mkpkg("go.itab2")
|
|
||||||
itab2pkg.Name = "go.itab2"
|
|
||||||
itab2pkg.Prefix = "go.itab2" // not go%2eitab2
|
|
||||||
|
|
||||||
typelinkpkg = mkpkg("go.typelink")
|
typelinkpkg = mkpkg("go.typelink")
|
||||||
typelinkpkg.Name = "go.typelink"
|
typelinkpkg.Name = "go.typelink"
|
||||||
typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
|
typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
|
||||||
@ -140,12 +133,10 @@ func Main() {
|
|||||||
itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
|
itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
|
||||||
|
|
||||||
trackpkg = mkpkg("go.track")
|
trackpkg = mkpkg("go.track")
|
||||||
|
|
||||||
trackpkg.Name = "go.track"
|
trackpkg.Name = "go.track"
|
||||||
trackpkg.Prefix = "go.track" // not go%2etrack
|
trackpkg.Prefix = "go.track" // not go%2etrack
|
||||||
|
|
||||||
typepkg = mkpkg("type")
|
typepkg = mkpkg("type")
|
||||||
|
|
||||||
typepkg.Name = "type"
|
typepkg.Name = "type"
|
||||||
|
|
||||||
goroot = obj.Getgoroot()
|
goroot = obj.Getgoroot()
|
||||||
|
@ -951,7 +951,7 @@ func itabname(t, itype *Type) *Node {
|
|||||||
if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
|
if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
|
||||||
Fatalf("itabname %v", t)
|
Fatalf("itabname %v", t)
|
||||||
}
|
}
|
||||||
s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itab2pkg)
|
s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itabpkg)
|
||||||
if s.Def == nil {
|
if s.Def == nil {
|
||||||
n := newname(s)
|
n := newname(s)
|
||||||
n.Type = Types[TUINT8]
|
n.Type = Types[TUINT8]
|
||||||
|
@ -1003,63 +1003,15 @@ opswitch:
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ll []*Node
|
var ll []*Node
|
||||||
if !Isinter(n.Left.Type) {
|
if isnilinter(n.Type) {
|
||||||
ll = append(ll, typename(n.Left.Type))
|
if !Isinter(n.Left.Type) {
|
||||||
}
|
ll = append(ll, typename(n.Left.Type))
|
||||||
if !isnilinter(n.Type) {
|
|
||||||
ll = append(ll, typename(n.Type))
|
|
||||||
}
|
|
||||||
if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
|
|
||||||
sym := Pkglookup(Tconv(n.Left.Type, FmtLeft)+"."+Tconv(n.Type, FmtLeft), itabpkg)
|
|
||||||
if sym.Def == nil {
|
|
||||||
l := Nod(ONAME, nil, nil)
|
|
||||||
l.Sym = sym
|
|
||||||
l.Type = Ptrto(Types[TUINT8])
|
|
||||||
l.Addable = true
|
|
||||||
l.Class = PEXTERN
|
|
||||||
l.Xoffset = 0
|
|
||||||
sym.Def = l
|
|
||||||
ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
l := Nod(OADDR, sym.Def, nil)
|
if Isinter(n.Left.Type) {
|
||||||
l.Addable = true
|
ll = append(ll, typename(n.Type))
|
||||||
ll = append(ll, l)
|
} else {
|
||||||
|
ll = append(ll, itabname(n.Left.Type, n.Type))
|
||||||
if isdirectiface(n.Left.Type) {
|
|
||||||
// For pointer types, we can make a special form of optimization
|
|
||||||
//
|
|
||||||
// These statements are put onto the expression init list:
|
|
||||||
// Itab *tab = atomicloadtype(&cache);
|
|
||||||
// if(tab == nil)
|
|
||||||
// tab = typ2Itab(type, itype, &cache);
|
|
||||||
//
|
|
||||||
// The CONVIFACE expression is replaced with this:
|
|
||||||
// OEFACE{tab, ptr};
|
|
||||||
l := temp(Ptrto(Types[TUINT8]))
|
|
||||||
|
|
||||||
n1 := Nod(OAS, l, sym.Def)
|
|
||||||
n1 = typecheck(n1, Etop)
|
|
||||||
init.Append(n1)
|
|
||||||
|
|
||||||
fn := syslook("typ2Itab")
|
|
||||||
n1 = Nod(OCALL, fn, nil)
|
|
||||||
n1.List.Set(ll)
|
|
||||||
n1 = typecheck(n1, Erv)
|
|
||||||
n1 = walkexpr(n1, init)
|
|
||||||
|
|
||||||
n2 := Nod(OIF, nil, nil)
|
|
||||||
n2.Left = Nod(OEQ, l, nodnil())
|
|
||||||
n2.Nbody.Set1(Nod(OAS, l, n1))
|
|
||||||
n2.Likely = -1
|
|
||||||
n2 = typecheck(n2, Etop)
|
|
||||||
init.Append(n2)
|
|
||||||
|
|
||||||
l = Nod(OEFACE, l, n.Left)
|
|
||||||
l.Typecheck = n.Typecheck
|
|
||||||
l.Type = n.Type
|
|
||||||
n = l
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,12 +147,6 @@ func itabsinit() {
|
|||||||
unlock(&ifaceLock)
|
unlock(&ifaceLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
|
|
||||||
tab := getitab(inter, t, false)
|
|
||||||
atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
|
|
||||||
return tab
|
|
||||||
}
|
|
||||||
|
|
||||||
func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
|
func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
|
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
|
||||||
@ -176,18 +170,14 @@ func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
|
func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
|
||||||
|
t := tab._type
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2I))
|
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2I))
|
||||||
}
|
}
|
||||||
if msanenabled {
|
if msanenabled {
|
||||||
msanread(elem, t.size)
|
msanread(elem, t.size)
|
||||||
}
|
}
|
||||||
tab := (*itab)(atomic.Loadp(unsafe.Pointer(cache)))
|
|
||||||
if tab == nil {
|
|
||||||
tab = getitab(inter, t, false)
|
|
||||||
atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
|
|
||||||
}
|
|
||||||
if isDirectIface(t) {
|
if isDirectIface(t) {
|
||||||
i.tab = tab
|
i.tab = tab
|
||||||
typedmemmove(t, unsafe.Pointer(&i.data), elem)
|
typedmemmove(t, unsafe.Pointer(&i.data), elem)
|
||||||
|
Loading…
Reference in New Issue
Block a user