]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: pass arguments to convt2E/I integer functions by value
authorChrisALiles <caveryliles@gmail.com>
Sat, 21 Apr 2018 07:31:21 +0000 (17:31 +1000)
committerJosh Bleecher Snyder <josharian@gmail.com>
Sun, 29 Apr 2018 15:53:39 +0000 (15:53 +0000)
The motivation is avoid generating a pointer to the data being
converted so it can be garbage collected.
The change also slightly reduces binary size by shrinking call sites.

Fixes #24286

Benchmark results:
name                   old time/op  new time/op  delta
ConvT2ESmall-4         2.86ns ± 0%  2.80ns ± 1%  -2.12%  (p=0.000 n=29+28)
ConvT2EUintptr-4       2.88ns ± 1%  2.88ns ± 0%  -0.20%  (p=0.002 n=28+30)
ConvT2ELarge-4         19.6ns ± 0%  20.4ns ± 1%  +4.22%  (p=0.000 n=19+30)
ConvT2ISmall-4         3.01ns ± 0%  2.85ns ± 0%  -5.32%  (p=0.000 n=24+28)
ConvT2IUintptr-4       3.00ns ± 1%  2.87ns ± 0%  -4.44%  (p=0.000 n=29+25)
ConvT2ILarge-4         20.4ns ± 1%  21.3ns ± 1%  +4.41%  (p=0.000 n=30+26)
ConvT2Ezero/zero/16-4  2.84ns ± 1%  2.99ns ± 0%  +5.38%  (p=0.000 n=30+25)
ConvT2Ezero/zero/32-4  2.83ns ± 2%  3.00ns ± 0%  +5.91%  (p=0.004 n=27+3)

Change-Id: I65016ec94c53f97c52113121cab582d0c342b7a8
Reviewed-on: https://go-review.googlesource.com/102636
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/walk.go
src/runtime/iface.go

index 3bb17673a5bb895a0962ec00ecd904db3aa37ada..bdc4974a7c03f92ba543ef5e84098b849b4833f7 100644 (file)
@@ -50,16 +50,16 @@ var runtimeDecls = [...]struct {
        {"slicestringcopy", funcTag, 50},
        {"convI2I", funcTag, 51},
        {"convT2E", funcTag, 52},
-       {"convT2E16", funcTag, 52},
-       {"convT2E32", funcTag, 52},
-       {"convT2E64", funcTag, 52},
+       {"convT2E16", funcTag, 51},
+       {"convT2E32", funcTag, 51},
+       {"convT2E64", funcTag, 51},
        {"convT2Estring", funcTag, 52},
        {"convT2Eslice", funcTag, 52},
        {"convT2Enoptr", funcTag, 52},
        {"convT2I", funcTag, 52},
-       {"convT2I16", funcTag, 52},
-       {"convT2I32", funcTag, 52},
-       {"convT2I64", funcTag, 52},
+       {"convT2I16", funcTag, 51},
+       {"convT2I32", funcTag, 51},
+       {"convT2I64", funcTag, 51},
        {"convT2Istring", funcTag, 52},
        {"convT2Islice", funcTag, 52},
        {"convT2Inoptr", funcTag, 52},
index bda9d1d03cb21299cb7eae975d1087148e8e204c..80294c8e0fdcb8dc7a843e8e82ac2a26d8a10b95 100644 (file)
@@ -62,17 +62,17 @@ func slicestringcopy(to any, fr any) int
 func convI2I(typ *byte, elem any) (ret any)
 
 func convT2E(typ *byte, elem *any) (ret any)
-func convT2E16(typ *byte, elem *any) (ret any)
-func convT2E32(typ *byte, elem *any) (ret any)
-func convT2E64(typ *byte, elem *any) (ret any)
+func convT2E16(typ *byte, val any) (ret any)
+func convT2E32(typ *byte, val any) (ret any)
+func convT2E64(typ *byte, val any) (ret any)
 func convT2Estring(typ *byte, elem *any) (ret any)
 func convT2Eslice(typ *byte, elem *any) (ret any)
 func convT2Enoptr(typ *byte, elem *any) (ret any)
 
 func convT2I(tab *byte, elem *any) (ret any)
-func convT2I16(tab *byte, elem *any) (ret any)
-func convT2I32(tab *byte, elem *any) (ret any)
-func convT2I64(tab *byte, elem *any) (ret any)
+func convT2I16(tab *byte, val any) (ret any)
+func convT2I32(tab *byte, val any) (ret any)
+func convT2I64(tab *byte, val any) (ret any)
 func convT2Istring(tab *byte, elem *any) (ret any)
 func convT2Islice(tab *byte, elem *any) (ret any)
 func convT2Inoptr(tab *byte, elem *any) (ret any)
index c2e5f69d1f4486e84d17243ee9d26e95ff877e77..cb482e23232453722602e0e0b5317cf7cb0615a5 100644 (file)
@@ -388,51 +388,51 @@ func walkexprlistcheap(s []*Node, init *Nodes) {
        }
 }
 
-// Build name of function for interface conversion.
-// Not all names are possible
-// (e.g., we'll never generate convE2E or convE2I or convI2E).
-func convFuncName(from, to *types.Type) string {
+// convFuncName builds the runtime function name for interface conversion.
+// It also reports whether the function expects the data by address.
+// Not all names are possible. For example, we never generate convE2E or convE2I.
+func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
        tkind := to.Tie()
        switch from.Tie() {
        case 'I':
                switch tkind {
                case 'I':
-                       return "convI2I"
+                       return "convI2I", false
                }
        case 'T':
                switch tkind {
                case 'E':
                        switch {
                        case from.Size() == 2 && from.Align == 2:
-                               return "convT2E16"
+                               return "convT2E16", false
                        case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
-                               return "convT2E32"
+                               return "convT2E32", false
                        case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
-                               return "convT2E64"
+                               return "convT2E64", false
                        case from.IsString():
-                               return "convT2Estring"
+                               return "convT2Estring", true
                        case from.IsSlice():
-                               return "convT2Eslice"
+                               return "convT2Eslice", true
                        case !types.Haspointers(from):
-                               return "convT2Enoptr"
+                               return "convT2Enoptr", true
                        }
-                       return "convT2E"
+                       return "convT2E", true
                case 'I':
                        switch {
                        case from.Size() == 2 && from.Align == 2:
-                               return "convT2I16"
+                               return "convT2I16", false
                        case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
-                               return "convT2I32"
+                               return "convT2I32", false
                        case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
-                               return "convT2I64"
+                               return "convT2I64", false
                        case from.IsString():
-                               return "convT2Istring"
+                               return "convT2Istring", true
                        case from.IsSlice():
-                               return "convT2Islice"
+                               return "convT2Islice", true
                        case !types.Haspointers(from):
-                               return "convT2Inoptr"
+                               return "convT2Inoptr", true
                        }
-                       return "convT2I"
+                       return "convT2I", true
                }
        }
        Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
@@ -980,24 +980,24 @@ opswitch:
                        }
                }
 
-               if n.Left.Type.IsInterface() {
-                       ll = append(ll, n.Left)
-               } else {
-                       // regular types are passed by reference to avoid C vararg calls
-                       // orderexpr arranged for n.Left to be a temporary for all
-                       // the conversions it could see. comparison of an interface
+               fnname, needsaddr := convFuncName(n.Left.Type, n.Type)
+               v := n.Left
+               if needsaddr {
+                       // Types of large or unknown size are passed by reference.
+                       // Orderexpr arranged for n.Left to be a temporary for all
+                       // the conversions it could see. Comparison of an interface
                        // with a non-interface, especially in a switch on interface value
                        // with non-interface cases, is not visible to orderstmt, so we
                        // have to fall back on allocating a temp here.
-                       if islvalue(n.Left) {
-                               ll = append(ll, nod(OADDR, n.Left, nil))
-                       } else {
-                               ll = append(ll, nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
+                       if !islvalue(v) {
+                               v = copyexpr(v, v.Type, init)
                        }
-                       dowidth(n.Left.Type)
+                       v = nod(OADDR, v, nil)
                }
+               ll = append(ll, v)
 
-               fn := syslook(convFuncName(n.Left.Type, n.Type))
+               dowidth(n.Left.Type)
+               fn := syslook(fnname)
                fn = substArgTypes(fn, n.Left.Type, n.Type)
                dowidth(fn.Type)
                n = nod(OCALL, fn, nil)
index bd6bc282f4eec3789e14220d5a83ca5b599cc047..4362f2cd5b6da7f8433ca6c0e6c75abc0e9adde0 100644 (file)
@@ -294,57 +294,39 @@ func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
        return
 }
 
-func convT2E16(t *_type, elem unsafe.Pointer) (e eface) {
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E16))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
+func convT2E16(t *_type, val uint16) (e eface) {
        var x unsafe.Pointer
-       if *(*uint16)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(2, t, false)
-               *(*uint16)(x) = *(*uint16)(elem)
+               *(*uint16)(x) = val
        }
        e._type = t
        e.data = x
        return
 }
 
-func convT2E32(t *_type, elem unsafe.Pointer) (e eface) {
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E32))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
+func convT2E32(t *_type, val uint32) (e eface) {
        var x unsafe.Pointer
-       if *(*uint32)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(4, t, false)
-               *(*uint32)(x) = *(*uint32)(elem)
+               *(*uint32)(x) = val
        }
        e._type = t
        e.data = x
        return
 }
 
-func convT2E64(t *_type, elem unsafe.Pointer) (e eface) {
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E64))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
+func convT2E64(t *_type, val uint64) (e eface) {
        var x unsafe.Pointer
-       if *(*uint64)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(8, t, false)
-               *(*uint64)(x) = *(*uint64)(elem)
+               *(*uint64)(x) = val
        }
        e._type = t
        e.data = x
@@ -418,60 +400,42 @@ func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
        return
 }
 
-func convT2I16(tab *itab, elem unsafe.Pointer) (i iface) {
+func convT2I16(tab *itab, val uint16) (i iface) {
        t := tab._type
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I16))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
        var x unsafe.Pointer
-       if *(*uint16)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(2, t, false)
-               *(*uint16)(x) = *(*uint16)(elem)
+               *(*uint16)(x) = val
        }
        i.tab = tab
        i.data = x
        return
 }
 
-func convT2I32(tab *itab, elem unsafe.Pointer) (i iface) {
+func convT2I32(tab *itab, val uint32) (i iface) {
        t := tab._type
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I32))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
        var x unsafe.Pointer
-       if *(*uint32)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(4, t, false)
-               *(*uint32)(x) = *(*uint32)(elem)
+               *(*uint32)(x) = val
        }
        i.tab = tab
        i.data = x
        return
 }
 
-func convT2I64(tab *itab, elem unsafe.Pointer) (i iface) {
+func convT2I64(tab *itab, val uint64) (i iface) {
        t := tab._type
-       if raceenabled {
-               raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I64))
-       }
-       if msanenabled {
-               msanread(elem, t.size)
-       }
        var x unsafe.Pointer
-       if *(*uint64)(elem) == 0 {
+       if val == 0 {
                x = unsafe.Pointer(&zeroVal[0])
        } else {
                x = mallocgc(8, t, false)
-               *(*uint64)(x) = *(*uint64)(elem)
+               *(*uint64)(x) = val
        }
        i.tab = tab
        i.data = x