From 0e4c013b6743507ebce2c08991cf1e3ab49cf7ac Mon Sep 17 00:00:00 2001
From: Richard Musiol
Date: Tue, 25 Sep 2018 13:45:08 +0200
Subject: [PATCH 001/240] syscall: use asynchronous operations on js/wasm
This commit makes syscall on js/wasm use the asynchronous variants
of functions in Node.js' fs module. This enables concurrency
and allows the API of the fs module to be implemented with an
alternative backend that only supports asynchronous operations.
Updates #26051.
Change-Id: Ibe1dcc988469fc11c3b8d8d49de439c12ddaafce
Reviewed-on: https://go-review.googlesource.com/c/137236
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/syscall/fs_js.go | 94 ++++++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 34 deletions(-)
diff --git a/src/syscall/fs_js.go b/src/syscall/fs_js.go
index 00d6c76979..22a055a040 100644
--- a/src/syscall/fs_js.go
+++ b/src/syscall/fs_js.go
@@ -81,15 +81,15 @@ func Open(path string, openmode int, perm uint32) (int, error) {
return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm")
}
- jsFD, err := fsCall("openSync", path, flags, perm)
+ jsFD, err := fsCall("open", path, flags, perm)
if err != nil {
return 0, err
}
fd := jsFD.Int()
var entries []string
- if stat, err := fsCall("fstatSync", fd); err == nil && stat.Call("isDirectory").Bool() {
- dir, err := fsCall("readdirSync", path)
+ if stat, err := fsCall("fstat", fd); err == nil && stat.Call("isDirectory").Bool() {
+ dir, err := fsCall("readdir", path)
if err != nil {
return 0, err
}
@@ -113,7 +113,7 @@ func Close(fd int) error {
filesMu.Lock()
delete(files, fd)
filesMu.Unlock()
- _, err := fsCall("closeSync", fd)
+ _, err := fsCall("close", fd)
return err
}
@@ -125,7 +125,7 @@ func Mkdir(path string, perm uint32) error {
if err := checkPath(path); err != nil {
return err
}
- _, err := fsCall("mkdirSync", path, perm)
+ _, err := fsCall("mkdir", path, perm)
return err
}
@@ -182,7 +182,7 @@ func Stat(path string, st *Stat_t) error {
if err := checkPath(path); err != nil {
return err
}
- jsSt, err := fsCall("statSync", path)
+ jsSt, err := fsCall("stat", path)
if err != nil {
return err
}
@@ -194,7 +194,7 @@ func Lstat(path string, st *Stat_t) error {
if err := checkPath(path); err != nil {
return err
}
- jsSt, err := fsCall("lstatSync", path)
+ jsSt, err := fsCall("lstat", path)
if err != nil {
return err
}
@@ -203,7 +203,7 @@ func Lstat(path string, st *Stat_t) error {
}
func Fstat(fd int, st *Stat_t) error {
- jsSt, err := fsCall("fstatSync", fd)
+ jsSt, err := fsCall("fstat", fd)
if err != nil {
return err
}
@@ -215,7 +215,7 @@ func Unlink(path string) error {
if err := checkPath(path); err != nil {
return err
}
- _, err := fsCall("unlinkSync", path)
+ _, err := fsCall("unlink", path)
return err
}
@@ -223,7 +223,7 @@ func Rmdir(path string) error {
if err := checkPath(path); err != nil {
return err
}
- _, err := fsCall("rmdirSync", path)
+ _, err := fsCall("rmdir", path)
return err
}
@@ -231,12 +231,12 @@ func Chmod(path string, mode uint32) error {
if err := checkPath(path); err != nil {
return err
}
- _, err := fsCall("chmodSync", path, mode)
+ _, err := fsCall("chmod", path, mode)
return err
}
func Fchmod(fd int, mode uint32) error {
- _, err := fsCall("fchmodSync", fd, mode)
+ _, err := fsCall("fchmod", fd, mode)
return err
}
@@ -267,7 +267,7 @@ func UtimesNano(path string, ts []Timespec) error {
}
atime := ts[0].Sec
mtime := ts[1].Sec
- _, err := fsCall("utimesSync", path, atime, mtime)
+ _, err := fsCall("utimes", path, atime, mtime)
return err
}
@@ -278,7 +278,7 @@ func Rename(from, to string) error {
if err := checkPath(to); err != nil {
return err
}
- _, err := fsCall("renameSync", from, to)
+ _, err := fsCall("rename", from, to)
return err
}
@@ -286,12 +286,12 @@ func Truncate(path string, length int64) error {
if err := checkPath(path); err != nil {
return err
}
- _, err := fsCall("truncateSync", path, length)
+ _, err := fsCall("truncate", path, length)
return err
}
func Ftruncate(fd int, length int64) error {
- _, err := fsCall("ftruncateSync", fd, length)
+ _, err := fsCall("ftruncate", fd, length)
return err
}
@@ -299,7 +299,7 @@ func Getcwd(buf []byte) (n int, err error) {
defer recoverErr(&err)
cwd := jsProcess.Call("cwd").String()
n = copy(buf, cwd)
- return n, nil
+ return
}
func Chdir(path string) (err error) {
@@ -323,7 +323,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
if err := checkPath(path); err != nil {
return 0, err
}
- dst, err := fsCall("readlinkSync", path)
+ dst, err := fsCall("readlink", path)
if err != nil {
return 0, err
}
@@ -338,7 +338,7 @@ func Link(path, link string) error {
if err := checkPath(link); err != nil {
return err
}
- _, err := fsCall("linkSync", path, link)
+ _, err := fsCall("link", path, link)
return err
}
@@ -349,12 +349,12 @@ func Symlink(path, link string) error {
if err := checkPath(link); err != nil {
return err
}
- _, err := fsCall("symlinkSync", path, link)
+ _, err := fsCall("symlink", path, link)
return err
}
func Fsync(fd int) error {
- _, err := fsCall("fsyncSync", fd)
+ _, err := fsCall("fsync", fd)
return err
}
@@ -371,7 +371,7 @@ func Read(fd int, b []byte) (int, error) {
}
a := js.TypedArrayOf(b)
- n, err := fsCall("readSync", fd, a, 0, len(b))
+ n, err := fsCall("read", fd, a, 0, len(b), nil)
a.Release()
if err != nil {
return 0, err
@@ -394,7 +394,7 @@ func Write(fd int, b []byte) (int, error) {
}
a := js.TypedArrayOf(b)
- n, err := fsCall("writeSync", fd, a, 0, len(b))
+ n, err := fsCall("write", fd, a, 0, len(b), nil)
a.Release()
if err != nil {
return 0, err
@@ -406,7 +406,7 @@ func Write(fd int, b []byte) (int, error) {
func Pread(fd int, b []byte, offset int64) (int, error) {
a := js.TypedArrayOf(b)
- n, err := fsCall("readSync", fd, a, 0, len(b), offset)
+ n, err := fsCall("read", fd, a, 0, len(b), offset)
a.Release()
if err != nil {
return 0, err
@@ -416,7 +416,7 @@ func Pread(fd int, b []byte, offset int64) (int, error) {
func Pwrite(fd int, b []byte, offset int64) (int, error) {
a := js.TypedArrayOf(b)
- n, err := fsCall("writeSync", fd, a, 0, len(b), offset)
+ n, err := fsCall("write", fd, a, 0, len(b), offset)
a.Release()
if err != nil {
return 0, err
@@ -467,10 +467,31 @@ func Pipe(fd []int) error {
return ENOSYS
}
-func fsCall(name string, args ...interface{}) (res js.Value, err error) {
- defer recoverErr(&err)
- res = jsFS.Call(name, args...)
- return
+func fsCall(name string, args ...interface{}) (js.Value, error) {
+ type callResult struct {
+ val js.Value
+ err error
+ }
+
+ c := make(chan callResult)
+ jsFS.Call(name, append(args, js.NewCallback(func(args []js.Value) {
+ var res callResult
+
+ if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments
+ if jsErr := args[0]; jsErr != js.Null() {
+ res.err = mapJSError(jsErr)
+ }
+ }
+
+ res.val = js.Undefined()
+ if len(args) >= 2 {
+ res.val = args[1]
+ }
+
+ c <- res
+ }))...)
+ res := <-c
+ return res.val, res.err
}
// checkPath checks that the path is not empty and that it contains no null characters.
@@ -492,10 +513,15 @@ func recoverErr(errPtr *error) {
if !ok {
panic(err)
}
- errno, ok := errnoByCode[jsErr.Get("code").String()]
- if !ok {
- panic(err)
- }
- *errPtr = errnoErr(Errno(errno))
+ *errPtr = mapJSError(jsErr.Value)
}
}
+
+// mapJSError maps an error given by Node.js to the appropriate Go error
+func mapJSError(jsErr js.Value) error {
+ errno, ok := errnoByCode[jsErr.Get("code").String()]
+ if !ok {
+ panic(jsErr)
+ }
+ return errnoErr(Errno(errno))
+}
From f1973f3164e5b570b8601c18fa484be7e97171f4 Mon Sep 17 00:00:00 2001
From: uropek
Date: Wed, 3 Oct 2018 23:52:49 +0000
Subject: [PATCH 002/240] test: fix spelling of `caught be the compiler` to
`caught by the compiler`
Change-Id: Id21cdce35963dcdb96cc06252170590224c5aa17
GitHub-Last-Rev: 429dad0ceba123415af308179d0d2aa9773e6323
GitHub-Pull-Request: golang/go#28000
Reviewed-on: https://go-review.googlesource.com/c/139424
Reviewed-by: Ian Lance Taylor
---
test/typeswitch2.go | 2 +-
test/typeswitch3.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/typeswitch2.go b/test/typeswitch2.go
index 1160b62e14..5958b7db8e 100644
--- a/test/typeswitch2.go
+++ b/test/typeswitch2.go
@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Verify that various erroneous type switches are caught be the compiler.
+// Verify that various erroneous type switches are caught by the compiler.
// Does not compile.
package main
diff --git a/test/typeswitch3.go b/test/typeswitch3.go
index 58d4cba2d0..1388187566 100644
--- a/test/typeswitch3.go
+++ b/test/typeswitch3.go
@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Verify that erroneous type switches are caught be the compiler.
+// Verify that erroneous type switches are caught by the compiler.
// Issue 2700, among other things.
// Does not compile.
From c6483b61a9096e3076439079c88eab84c9e6d859 Mon Sep 17 00:00:00 2001
From: Michael Fraenkel
Date: Wed, 3 Oct 2018 20:42:05 -0400
Subject: [PATCH 003/240] expvar: add Map.Delete
Fixes #13491
Change-Id: Ic0525d8ee90f47d0d23c1485919aee13d2400494
Reviewed-on: https://go-review.googlesource.com/c/139537
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/expvar/expvar.go | 13 ++++++++++++-
src/expvar/expvar_test.go | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index b7928aab17..976b300d63 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -137,7 +137,7 @@ func (v *Map) Init() *Map {
return v
}
-// updateKeys updates the sorted list of keys in v.keys.
+// addKey updates the sorted list of keys in v.keys.
func (v *Map) addKey(key string) {
v.keysMu.Lock()
defer v.keysMu.Unlock()
@@ -199,6 +199,17 @@ func (v *Map) AddFloat(key string, delta float64) {
}
}
+// Deletes the given key from the map.
+func (v *Map) Delete(key string) {
+ v.keysMu.Lock()
+ defer v.keysMu.Unlock()
+ i := sort.SearchStrings(v.keys, key)
+ if i < len(v.keys) && key == v.keys[i] {
+ v.keys = append(v.keys[:i], v.keys[i+1:]...)
+ v.m.Delete(key)
+ }
+}
+
// Do calls f for each entry in the map.
// The map is locked during the iteration,
// but existing entries may be concurrently updated.
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 728e763896..804b56c1aa 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -183,6 +183,43 @@ func TestMapInit(t *testing.T) {
}
}
+func TestMapDelete(t *testing.T) {
+ RemoveAll()
+ colors := NewMap("bike-shed-colors")
+
+ colors.Add("red", 1)
+ colors.Add("red", 2)
+ colors.Add("blue", 4)
+
+ n := 0
+ colors.Do(func(KeyValue) { n++ })
+ if n != 2 {
+ t.Errorf("after two Add calls with distinct keys, Do should invoke f 2 times; got %v", n)
+ }
+
+ colors.Delete("red")
+ n = 0
+ colors.Do(func(KeyValue) { n++ })
+ if n != 1 {
+ t.Errorf("removed red, Do should invoke f 1 times; got %v", n)
+ }
+
+ colors.Delete("notfound")
+ n = 0
+ colors.Do(func(KeyValue) { n++ })
+ if n != 1 {
+ t.Errorf("attempted to remove notfound, Do should invoke f 1 times; got %v", n)
+ }
+
+ colors.Delete("blue")
+ colors.Delete("blue")
+ n = 0
+ colors.Do(func(KeyValue) { n++ })
+ if n != 0 {
+ t.Errorf("all keys removed, Do should invoke f 0 times; got %v", n)
+ }
+}
+
func TestMapCounter(t *testing.T) {
RemoveAll()
colors := NewMap("bike-shed-colors")
From 2f1ef6be000fdf4ab74cb306e448c9e0e49bf148 Mon Sep 17 00:00:00 2001
From: Kir Kolyshkin
Date: Wed, 3 Oct 2018 18:41:18 -0700
Subject: [PATCH 004/240] crypto/x509: fix getting user home dir on darwin
As pointed out in https://github.com/golang/go/issues/26463,
HOME (or equivalent) environment variable (rather than the
value obtained by parsing /etc/passwd or the like) should be
used to obtain user's home directory.
Since commit fa1a49aa556d8 there's a method to obtain
user's home directory -- use it here.
Change-Id: I852fbb24249bcfe08f3874fae6e7b9d01d869190
Reviewed-on: https://go-review.googlesource.com/c/139426
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/crypto/x509/root_darwin.go | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 9d7b3a6ffb..ae69a2fadd 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.go
@@ -16,7 +16,6 @@ import (
"io/ioutil"
"os"
"os/exec"
- "os/user"
"path/filepath"
"strings"
"sync"
@@ -67,17 +66,17 @@ func execSecurityRoots() (*CertPool, error) {
"/Library/Keychains/System.keychain",
}
- u, err := user.Current()
- if err != nil {
+ home := os.UserHomeDir()
+ if home == "" {
if debugExecDarwinRoots {
- println(fmt.Sprintf("crypto/x509: get current user: %v", err))
+ println("crypto/x509: can't get user home directory")
}
} else {
args = append(args,
- filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"),
+ filepath.Join(home, "/Library/Keychains/login.keychain"),
// Fresh installs of Sierra use a slightly different path for the login keychain
- filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain-db"),
+ filepath.Join(home, "/Library/Keychains/login.keychain-db"),
)
}
From 5e8beed149c77ee8f0bc4eee6a97faa4cec23027 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Mon, 6 Nov 2017 14:41:06 -0800
Subject: [PATCH 005/240] cmd/compile: remove pointer arithmetic
Change-Id: Ie4bab0b74d5a4e1aecd8501a48176b2e9a3d8c42
Reviewed-on: https://go-review.googlesource.com/c/76311
Run-TryBot: Matthew Dempsky
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/range.go | 23 ++++++++++++++++-------
src/cmd/compile/internal/gc/ssa.go | 2 --
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 13f45e164d..ac03cc5ea7 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -286,13 +286,7 @@ func walkrange(n *Node) *Node {
// This runs *after* the condition check, so we know
// advancing the pointer is safe and won't go past the
// end of the allocation.
- tmp = nod(OADD, hp, nodintconst(t.Elem().Width))
-
- tmp.Type = hp.Type
- tmp.SetTypecheck(1)
- tmp.Right.Type = types.Types[types.Tptr]
- tmp.Right.SetTypecheck(1)
- a = nod(OAS, hp, tmp)
+ a = nod(OAS, hp, addptr(hp, t.Elem().Width))
a = typecheck(a, Etop)
n.List.Set1(a)
@@ -613,3 +607,18 @@ func arrayClear(n, v1, v2, a *Node) bool {
n = walkstmt(n)
return true
}
+
+// addptr returns (*T)(uintptr(p) + n).
+func addptr(p *Node, n int64) *Node {
+ t := p.Type
+
+ p = nod(OCONVNOP, p, nil)
+ p.Type = types.Types[TUINTPTR]
+
+ p = nod(OADD, p, nodintconst(n))
+
+ p = nod(OCONVNOP, p, nil)
+ p.Type = t
+
+ return p
+}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 138ce08fec..2b67ef9a6f 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1247,10 +1247,8 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OADD, TUINT16}: ssa.OpAdd16,
opAndType{OADD, TINT32}: ssa.OpAdd32,
opAndType{OADD, TUINT32}: ssa.OpAdd32,
- opAndType{OADD, TPTR32}: ssa.OpAdd32,
opAndType{OADD, TINT64}: ssa.OpAdd64,
opAndType{OADD, TUINT64}: ssa.OpAdd64,
- opAndType{OADD, TPTR64}: ssa.OpAdd64,
opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
From d397d4bffc0fa917fa53970ded4b4d3524f88a5b Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Wed, 3 Oct 2018 15:47:16 -0700
Subject: [PATCH 006/240] cmd/compile: handle TPTR32 like TPTR64 in
smallintconst
In preparation for followup CL merging TPTR32 and TPTR64, move TPTR32
from the small-types fast path to the generic 64-bit fallback code so
that it's in the same case clause as TPTR64.
This should be safe, but theoretically it could change semantics
because TPTR32 used to always be assumed to be "small", whereas now it
will only be considered small for values less than 1<<31.
This change is done in a separate CL so that it's more easily
identified by git bisection in case it does introduce regressions.
Change-Id: I6c7bb253d4e4d95c530a6e05a1147905674b55ca
Reviewed-on: https://go-review.googlesource.com/c/139517
Run-TryBot: Matthew Dempsky
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/const.go | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 02d51678be..a80455a30c 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -1479,11 +1479,10 @@ func smallintconst(n *Node) bool {
TUINT16,
TINT32,
TUINT32,
- TBOOL,
- TPTR32:
+ TBOOL:
return true
- case TIDEAL, TINT64, TUINT64, TPTR64:
+ case TIDEAL, TINT64, TUINT64, TPTR32, TPTR64:
v, ok := n.Val().U.(*Mpint)
if ok && v.Cmp(minintval[TINT32]) > 0 && v.Cmp(maxintval[TINT32]) < 0 {
return true
From 62e5215a2a12d95d1ce08cb6c996c3667e346779 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Mon, 6 Nov 2017 14:50:30 -0800
Subject: [PATCH 007/240] cmd/compile: merge TPTR32 and TPTR64 as TPTR
Change-Id: I0490098a7235458c5aede1135426a9f19f8584a7
Reviewed-on: https://go-review.googlesource.com/c/76312
Run-TryBot: Matthew Dempsky
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/alg.go | 2 +-
src/cmd/compile/internal/gc/align.go | 8 ++----
src/cmd/compile/internal/gc/bexport.go | 2 +-
src/cmd/compile/internal/gc/const.go | 4 +--
src/cmd/compile/internal/gc/esc.go | 2 +-
src/cmd/compile/internal/gc/fmt.go | 2 +-
src/cmd/compile/internal/gc/iexport.go | 4 +--
src/cmd/compile/internal/gc/pgen_test.go | 2 +-
src/cmd/compile/internal/gc/plive.go | 5 ++--
src/cmd/compile/internal/gc/reflect.go | 17 ++++++-------
src/cmd/compile/internal/gc/ssa.go | 6 ++---
src/cmd/compile/internal/gc/subr.go | 6 ++---
src/cmd/compile/internal/gc/typecheck.go | 3 +--
src/cmd/compile/internal/gc/types.go | 4 +--
src/cmd/compile/internal/gc/universe.go | 23 ++++++-----------
src/cmd/compile/internal/gc/walk.go | 2 +-
src/cmd/compile/internal/ssa/export_test.go | 1 -
src/cmd/compile/internal/types/type.go | 28 ++++++++-------------
src/cmd/compile/internal/types/utils.go | 3 ---
19 files changed, 45 insertions(+), 79 deletions(-)
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index b7d88531fd..9a13ed368b 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -102,7 +102,7 @@ func algtype1(t *types.Type) (AlgKind, *types.Type) {
case TINT8, TUINT8, TINT16, TUINT16,
TINT32, TUINT32, TINT64, TUINT64,
TINT, TUINT, TUINTPTR,
- TBOOL, TPTR32, TPTR64,
+ TBOOL, TPTR,
TCHAN, TUNSAFEPTR:
return AMEM, nil
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 9e752fc628..fb761d2339 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -250,12 +250,8 @@ func dowidth(t *types.Type) {
w = 16
t.Align = uint8(Widthreg)
- case TPTR32:
- w = 4
- checkwidth(t.Elem())
-
- case TPTR64:
- w = 8
+ case TPTR:
+ w = int64(Widthptr)
checkwidth(t.Elem())
case TUNSAFEPTR:
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 3ef1e6af4d..7c09ab5a34 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -43,7 +43,7 @@ func (p *exporter) markType(t *types.Type) {
// the user already needs some way to construct values of
// those types.
switch t.Etype {
- case TPTR32, TPTR64, TARRAY, TSLICE, TCHAN:
+ case TPTR, TARRAY, TSLICE, TCHAN:
// TODO(mdempsky): Skip marking element type for
// send-only channels?
p.markType(t.Elem())
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index a80455a30c..effed1f4ac 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -347,7 +347,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
case TARRAY:
goto bad
- case TPTR32, TPTR64, TUNSAFEPTR:
+ case TPTR, TUNSAFEPTR:
n.SetVal(Val{new(Mpint)})
case TCHAN, TFUNC, TINTER, TMAP, TSLICE:
@@ -1482,7 +1482,7 @@ func smallintconst(n *Node) bool {
TBOOL:
return true
- case TIDEAL, TINT64, TUINT64, TPTR32, TPTR64:
+ case TIDEAL, TINT64, TUINT64, TPTR:
v, ok := n.Val().U.(*Mpint)
if ok && v.Cmp(minintval[TINT32]) > 0 && v.Cmp(maxintval[TINT32]) < 0 {
return true
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 145007f5e1..94190f0020 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -1507,7 +1507,7 @@ func (e *EscState) addDereference(n *Node) *Node {
e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth
ind.Pos = n.Pos
t := n.Type
- if t.IsKind(types.Tptr) || t.IsSlice() {
+ if t.IsPtr() || t.IsSlice() {
// This should model our own sloppy use of OIND to encode
// decreasing levels of indirection; i.e., "indirecting" a slice
// yields the type of an element.
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 5d2e36ee51..28e9b9b6dc 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -697,7 +697,7 @@ func typefmt(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
}
switch t.Etype {
- case TPTR32, TPTR64:
+ case TPTR:
switch mode {
case FTypeId, FTypeIdName:
if flag&FmtShort != 0 {
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index 3007c9cabf..d90c97ad92 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -617,7 +617,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
}
switch t.Etype {
- case TPTR32, TPTR64:
+ case TPTR:
w.startType(pointerType)
w.typ(t.Elem())
@@ -743,7 +743,7 @@ func constTypeOf(typ *types.Type) Ctype {
return CTSTR
case TINT, TINT8, TINT16, TINT32, TINT64,
TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR,
- TPTR32, TPTR64, TUNSAFEPTR:
+ TPTR, TUNSAFEPTR:
return CTINT
case TFLOAT32, TFLOAT64:
return CTFLT
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
index d75c5b8239..89b977de85 100644
--- a/src/cmd/compile/internal/gc/pgen_test.go
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -20,7 +20,7 @@ func typeWithoutPointers() *types.Type {
func typeWithPointers() *types.Type {
t := types.New(TSTRUCT)
- f := &types.Field{Type: types.New(TPTR64)}
+ f := &types.Field{Type: types.New(TPTR)}
t.SetFields([]*types.Field{f})
return t
}
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 563b425db7..a38c33647e 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -534,7 +534,7 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
TINT, TUINT, TUINTPTR, TBOOL,
TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
- case TPTR32, TPTR64, TUNSAFEPTR, TFUNC, TCHAN, TMAP:
+ case TPTR, TUNSAFEPTR, TFUNC, TCHAN, TMAP:
if off&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
@@ -1163,8 +1163,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) {
return
}
switch t.Etype {
- case TPTR32,
- TPTR64,
+ case TPTR,
TUNSAFEPTR,
TFUNC,
TCHAN,
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 935c3b0503..3ef5682301 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -656,7 +656,7 @@ func typePkg(t *types.Type) *types.Pkg {
tsym := t.Sym
if tsym == nil {
switch t.Etype {
- case TARRAY, TSLICE, TPTR32, TPTR64, TCHAN:
+ case TARRAY, TSLICE, TPTR, TCHAN:
if t.Elem() != nil {
tsym = t.Elem().Sym
}
@@ -714,8 +714,7 @@ var kinds = []int{
TFLOAT64: objabi.KindFloat64,
TBOOL: objabi.KindBool,
TSTRING: objabi.KindString,
- TPTR32: objabi.KindPtr,
- TPTR64: objabi.KindPtr,
+ TPTR: objabi.KindPtr,
TSTRUCT: objabi.KindStruct,
TINTER: objabi.KindInterface,
TCHAN: objabi.KindChan,
@@ -736,8 +735,7 @@ func typeptrdata(t *types.Type) int64 {
}
switch t.Etype {
- case TPTR32,
- TPTR64,
+ case TPTR,
TUNSAFEPTR,
TFUNC,
TCHAN,
@@ -1035,8 +1033,7 @@ func isreflexive(t *types.Type) bool {
TINT64,
TUINT64,
TUINTPTR,
- TPTR32,
- TPTR64,
+ TPTR,
TUNSAFEPTR,
TSTRING,
TCHAN:
@@ -1071,7 +1068,7 @@ func isreflexive(t *types.Type) bool {
func needkeyupdate(t *types.Type) bool {
switch t.Etype {
case TBOOL, TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32,
- TINT64, TUINT64, TUINTPTR, TPTR32, TPTR64, TUNSAFEPTR, TCHAN:
+ TINT64, TUINT64, TUINTPTR, TPTR, TUNSAFEPTR, TCHAN:
return false
case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, // floats and complex can be +0/-0
@@ -1279,7 +1276,7 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = duint8(lsym, ot, uint8(obj.Bool2int(needkeyupdate(t.Key()))))
ot = dextratype(lsym, ot, t, 0)
- case TPTR32, TPTR64:
+ case TPTR:
if t.Elem().Etype == TANY {
// ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(lsym, t)
@@ -1356,7 +1353,7 @@ func dtypesym(t *types.Type) *obj.LSym {
// functions must return the existing type structure rather
// than creating a new one.
switch t.Etype {
- case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
+ case TPTR, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
keep = true
}
}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 2b67ef9a6f..469fbb8c96 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1363,8 +1363,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
opAndType{OEQ, TMAP}: ssa.OpEqPtr,
opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
- opAndType{OEQ, TPTR32}: ssa.OpEqPtr,
- opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
+ opAndType{OEQ, TPTR}: ssa.OpEqPtr,
opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
@@ -1384,8 +1383,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
opAndType{ONE, TMAP}: ssa.OpNeqPtr,
opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
- opAndType{ONE, TPTR32}: ssa.OpNeqPtr,
- opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
+ opAndType{ONE, TPTR}: ssa.OpNeqPtr,
opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 7e450e2e66..9a6c61a651 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -772,8 +772,7 @@ func assignop(src *types.Type, dst *types.Type, why *string) Op {
// 5. src is the predeclared identifier nil and dst is a nillable type.
if src.Etype == TNIL {
switch dst.Etype {
- case TPTR32,
- TPTR64,
+ case TPTR,
TFUNC,
TMAP,
TCHAN,
@@ -2003,8 +2002,7 @@ func isdirectiface(t *types.Type) bool {
}
switch t.Etype {
- case TPTR32,
- TPTR64,
+ case TPTR,
TCHAN,
TMAP,
TFUNC,
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 4831ecca34..897dd710b9 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -87,8 +87,7 @@ var _typekind = []string{
TFLOAT64: "float64",
TBOOL: "bool",
TSTRING: "string",
- TPTR32: "pointer",
- TPTR64: "pointer",
+ TPTR: "pointer",
TUNSAFEPTR: "unsafe.Pointer",
TSTRUCT: "struct",
TINTER: "interface",
diff --git a/src/cmd/compile/internal/gc/types.go b/src/cmd/compile/internal/gc/types.go
index aa0f066a46..ce82c3a52e 100644
--- a/src/cmd/compile/internal/gc/types.go
+++ b/src/cmd/compile/internal/gc/types.go
@@ -32,9 +32,7 @@ const (
TBOOL = types.TBOOL
- TPTR32 = types.TPTR32
- TPTR64 = types.TPTR64
-
+ TPTR = types.TPTR
TFUNC = types.TFUNC
TSLICE = types.TSLICE
TARRAY = types.TARRAY
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index dbc2d647c9..96980ad500 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -177,11 +177,8 @@ func typeinit() {
simtype[et] = et
}
- types.Types[TPTR32] = types.New(TPTR32)
- dowidth(types.Types[TPTR32])
-
- types.Types[TPTR64] = types.New(TPTR64)
- dowidth(types.Types[TPTR64])
+ types.Types[TPTR] = types.New(TPTR)
+ dowidth(types.Types[TPTR])
t := types.New(TUNSAFEPTR)
types.Types[TUNSAFEPTR] = t
@@ -190,11 +187,6 @@ func typeinit() {
asNode(t.Sym.Def).Name = new(Name)
dowidth(types.Types[TUNSAFEPTR])
- types.Tptr = TPTR32
- if Widthptr == 8 {
- types.Tptr = TPTR64
- }
-
for et := TINT8; et <= TUINT64; et++ {
isInt[et] = true
}
@@ -263,8 +255,7 @@ func typeinit() {
okforlen[TSLICE] = true
okforlen[TSTRING] = true
- okforeq[TPTR32] = true
- okforeq[TPTR64] = true
+ okforeq[TPTR] = true
okforeq[TUNSAFEPTR] = true
okforeq[TINTER] = true
okforeq[TCHAN] = true
@@ -357,10 +348,10 @@ func typeinit() {
types.Types[TINTER] = types.New(TINTER)
// simple aliases
- simtype[TMAP] = types.Tptr
- simtype[TCHAN] = types.Tptr
- simtype[TFUNC] = types.Tptr
- simtype[TUNSAFEPTR] = types.Tptr
+ simtype[TMAP] = TPTR
+ simtype[TCHAN] = TPTR
+ simtype[TFUNC] = TPTR
+ simtype[TUNSAFEPTR] = TPTR
array_array = int(Rnd(0, int64(Widthptr)))
array_nel = int(Rnd(int64(array_array)+int64(Widthptr), int64(Widthptr)))
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 1b1d36b61d..5aa2146a8c 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -2138,7 +2138,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
on = syslook("printiface")
}
on = substArgTypes(on, n.Type) // any-1
- case TPTR32, TPTR64, TCHAN, TMAP, TFUNC, TUNSAFEPTR:
+ case TPTR, TCHAN, TMAP, TFUNC, TUNSAFEPTR:
on = syslook("printpointer")
on = substArgTypes(on, n.Type) // any-1
case TSLICE:
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 5832050a8a..9c776d4b16 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -163,7 +163,6 @@ func init() {
}
types.Dowidth = func(t *types.Type) {}
- types.Tptr = types.TPTR64
for _, typ := range [...]struct {
width int64
et types.EType
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 25f8f826e6..e6e6127405 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -43,9 +43,7 @@ const (
TBOOL
- TPTR32
- TPTR64
-
+ TPTR
TFUNC
TSLICE
TARRAY
@@ -137,7 +135,7 @@ type Type struct {
// TFUNCARGS: FuncArgs
// TCHANARGS: ChanArgs
// TCHAN: *Chan
- // TPTR32, TPTR64: Ptr
+ // TPTR: Ptr
// TARRAY: *Array
// TSLICE: Slice
Extra interface{}
@@ -461,7 +459,7 @@ func New(et EType) *Type {
t.Extra = new(Struct)
case TINTER:
t.Extra = new(Interface)
- case TPTR32, TPTR64:
+ case TPTR:
t.Extra = Ptr{}
case TCHANARGS:
t.Extra = ChanArgs{}
@@ -560,11 +558,7 @@ func NewPtr(elem *Type) *Type {
return t
}
- if Tptr == 0 {
- Fatalf("NewPtr: Tptr not initialized")
- }
-
- t := New(Tptr)
+ t := New(TPTR)
t.Extra = Ptr{Elem: elem}
t.Width = int64(Widthptr)
t.Align = uint8(Widthptr)
@@ -619,7 +613,7 @@ func SubstAny(t *Type, types *[]*Type) *Type {
t = (*types)[0]
*types = (*types)[1:]
- case TPTR32, TPTR64:
+ case TPTR:
elem := SubstAny(t.Elem(), types)
if elem != t.Elem() {
t = t.copy()
@@ -790,7 +784,7 @@ func (t *Type) Key() *Type {
// Usable with pointers, channels, arrays, slices, and maps.
func (t *Type) Elem() *Type {
switch t.Etype {
- case TPTR32, TPTR64:
+ case TPTR:
return t.Extra.(Ptr).Elem
case TARRAY:
return t.Extra.(*Array).Elem
@@ -1101,7 +1095,7 @@ func (t *Type) cmp(x *Type) Cmp {
}
return t.Elem().cmp(x.Elem())
- case TPTR32, TPTR64, TSLICE:
+ case TPTR, TSLICE:
// No special cases for these, they are handled
// by the general code after the switch.
@@ -1199,7 +1193,7 @@ func (t *Type) cmp(x *Type) Cmp {
panic(e)
}
- // Common element type comparison for TARRAY, TCHAN, TPTR32, TPTR64, and TSLICE.
+ // Common element type comparison for TARRAY, TCHAN, TPTR, and TSLICE.
return t.Elem().cmp(x.Elem())
}
@@ -1261,7 +1255,7 @@ func (t *Type) IsComplex() bool {
// IsPtr reports whether t is a regular Go pointer type.
// This does not include unsafe.Pointer.
func (t *Type) IsPtr() bool {
- return t.Etype == TPTR32 || t.Etype == TPTR64
+ return t.Etype == TPTR
}
// IsUnsafePtr reports whether t is an unsafe pointer.
@@ -1275,7 +1269,7 @@ func (t *Type) IsUnsafePtr() bool {
// that consist of a single pointer shaped type.
// TODO(mdempsky): Should it? See golang.org/issue/15028.
func (t *Type) IsPtrShaped() bool {
- return t.Etype == TPTR32 || t.Etype == TPTR64 || t.Etype == TUNSAFEPTR ||
+ return t.Etype == TPTR || t.Etype == TUNSAFEPTR ||
t.Etype == TMAP || t.Etype == TCHAN || t.Etype == TFUNC
}
@@ -1449,7 +1443,7 @@ func Haspointers1(t *Type, ignoreNotInHeap bool) bool {
}
return false
- case TPTR32, TPTR64, TSLICE:
+ case TPTR, TSLICE:
return !(ignoreNotInHeap && t.Elem().NotInHeap())
case TTUPLE:
diff --git a/src/cmd/compile/internal/types/utils.go b/src/cmd/compile/internal/types/utils.go
index 0eac402f8e..caaeb889fb 100644
--- a/src/cmd/compile/internal/types/utils.go
+++ b/src/cmd/compile/internal/types/utils.go
@@ -11,9 +11,6 @@ import (
const BADWIDTH = -1000000000
-// Initialized by frontend. Exists only here.
-var Tptr EType // either TPTR32 or TPTR64
-
// The following variables must be initialized early by the frontend.
// They are here to break import cycles.
// TODO(gri) eliminate these dependencies.
From d6ab653c78df74d49d882774228bda459de6c584 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 3 Oct 2018 14:40:09 -0700
Subject: [PATCH 008/240] go/types: determine hasPtrRecv property from source
rather than type
LookupFieldOrMethod needs to know if a method receiver is a pointer
type. Until now this was computed from the the method signature's
receiver, which required the method signature to be type-checked.
Furthermore, it required the receiver to be set before the method
signature was fully type-checked in some cases (see issue #6638).
This CL remembers this property during object resolution, when we
know it from the source.
With this CL, method signatures don't need to be type-checked before
they can be looked up; this is a first step towards separating
type checking of types and type-checking of associated methods.
Updates #23203.
Updates #26854.
Change-Id: Ie3eb7976e8fe8176ea1b284fa7471a4b7000f80b
Reviewed-on: https://go-review.googlesource.com/c/139422
Run-TryBot: Robert Griesemer
TryBot-Result: Gobot Gobot
Reviewed-by: Alan Donovan
---
src/go/types/methodset.go | 15 ++++++++++++---
src/go/types/object.go | 3 ++-
src/go/types/resolver.go | 2 ++
src/go/types/typexpr.go | 10 +++++++---
4 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
index 2b810da728..c25236656e 100644
--- a/src/go/types/methodset.go
+++ b/src/go/types/methodset.go
@@ -255,8 +255,17 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
}
// ptrRecv reports whether the receiver is of the form *T.
-// The receiver must exist.
func ptrRecv(f *Func) bool {
- _, isPtr := deref(f.typ.(*Signature).recv.typ)
- return isPtr
+ // If a method's type is set, use that as the source of truth for the receiver.
+ if f.typ != nil {
+ _, isPtr := deref(f.typ.(*Signature).recv.typ)
+ return isPtr
+ }
+
+ // If a method's type is not set it may be a method/function that is:
+ // 1) client-supplied (via NewFunc with no signature), or
+ // 2) internally created but not yet type-checked.
+ // For case 1) we can't do anything; the client must know what they are doing.
+ // For case 2) we can use the information gathered by the resolver.
+ return f.hasPtrRecv
}
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 07adfbc34c..cf773238a0 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -294,6 +294,7 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
// An abstract method may belong to many interfaces due to embedding.
type Func struct {
object
+ hasPtrRecv bool // only valid for methods that don't have a type yet
}
// NewFunc returns a new function with the given signature, representing
@@ -304,7 +305,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
if sig != nil {
typ = sig
}
- return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}}
+ return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false}
}
// FullName returns the package- or receiver-type-qualified name of
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index ec7e4ed1c5..c2726f4dd2 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -465,6 +465,8 @@ func (check *Checker) collectObjects() {
typ := unparen(list[0].Type)
if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
typ = unparen(ptr.X)
+ // TODO(gri): This may not be sufficient. See issue #27995.
+ f.hasPtrRecv = true
}
if base, _ := typ.(*ast.Ident); base != nil {
// base is a potential base type name; determine
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index 12c5c7b0a5..bcdbc5906d 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -558,9 +558,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
pos := name.Pos()
// Don't type-check signature yet - use an
// empty signature now and update it later.
- // Since we know the receiver, set it up now
- // (required to avoid crash in ptrRecv; see
- // e.g. test case for issue 6638).
+ // But set up receiver since we know it and
+ // its position, and because interface method
+ // signatures don't get a receiver via regular
+ // type-checking (there isn't a receiver in the
+ // the method's AST). Setting the correct receiver
+ // type is also important for ptrRecv() (see methodset.go).
+ //
// TODO(gri) Consider marking methods signatures
// as incomplete, for better error messages. See
// also the T4 and T5 tests in testdata/cycles2.src.
From 6606cd3d3bee550e0693e1bfc5678e35f1a289bf Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Thu, 4 Oct 2018 15:37:49 +0200
Subject: [PATCH 009/240] cmd/compile: regenerate known formats for TestFormats
This fixes the build for long-running tests after CL 139338
Change-Id: Ib8adfa785d41c736188e2ff7e14125de045b96b9
Reviewed-on: https://go-review.googlesource.com/c/139637
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/fmt_test.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index 65f88dfff9..6dfdea1a34 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -583,7 +583,6 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"*cmd/compile/internal/types.Field %p": "",
"*cmd/compile/internal/types.Field %v": "",
- "*cmd/compile/internal/types.Sym %+v": "",
"*cmd/compile/internal/types.Sym %0S": "",
"*cmd/compile/internal/types.Sym %S": "",
"*cmd/compile/internal/types.Sym %p": "",
From 011b8eb6bb9783ec6b22697810863f30ca7bda1f Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 30 Jun 2017 12:18:27 -0400
Subject: [PATCH 010/240] runtime: don't double-zero treap nodes
mheap_.treapalloc.alloc() already returns a zeroed treapNode. Don't
bother re-zeroing all of the fields.
Change-Id: Iea317040fbb72dfe5ef1e2c56c287680b065f2d9
Reviewed-on: https://go-review.googlesource.com/c/139460
Run-TryBot: Austin Clements
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/runtime/mgclarge.go | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/src/runtime/mgclarge.go b/src/runtime/mgclarge.go
index e7fa831937..11a977d6ba 100644
--- a/src/runtime/mgclarge.go
+++ b/src/runtime/mgclarge.go
@@ -46,15 +46,6 @@ type treapNode struct {
priority uint32 // random number used by treap algorithm to keep tree probabilistically balanced
}
-func (t *treapNode) init() {
- t.right = nil
- t.left = nil
- t.parent = nil
- t.spanKey = nil
- t.npagesKey = 0
- t.priority = 0
-}
-
// isSpanInTreap is handy for debugging. One should hold the heap lock, usually
// mheap_.lock().
func (t *treapNode) isSpanInTreap(s *mspan) bool {
@@ -140,7 +131,6 @@ func (root *mTreap) insert(span *mspan) {
// https://faculty.washington.edu/aragon/pubs/rst89.pdf
t := (*treapNode)(mheap_.treapalloc.alloc())
- t.init()
t.npagesKey = span.npages
t.priority = fastrand()
t.spanKey = span
@@ -188,8 +178,6 @@ func (root *mTreap) removeNode(t *treapNode) {
root.treap = nil
}
// Return the found treapNode's span after freeing the treapNode.
- t.spanKey = nil
- t.npagesKey = 0
mheap_.treapalloc.free(unsafe.Pointer(t))
}
From 4c1c839a3d2270d846f5a6d1cd1287e8560f0265 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Thu, 4 Oct 2018 10:46:20 -0400
Subject: [PATCH 011/240] runtime: clarify table of arena sizes
Currently the table of arena sizes mixes the number of entries in the
L1 with the size of the L2. While the size of the L2 is important,
this makes it hard to see what's actually going on because there's an
implicit factor of sys.PtrSize.
This changes the L2 column to say both the number of entries and the
size that results in. This should hopefully make the relations between
the columns of the table clearer, since they can now be plugged
directly into the given formula.
Change-Id: Ie677adaef763b893a2f620bd4fc3b8db314b3a1e
Reviewed-on: https://go-review.googlesource.com/c/139697
Reviewed-by: Brad Fitzpatrick
---
src/runtime/malloc.go | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index c3fe1169dc..791bbe7850 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -216,16 +216,16 @@ const (
// The number of bits in a heap address, the size of heap
// arenas, and the L1 and L2 arena map sizes are related by
//
- // (1 << addrBits) = arenaBytes * L1entries * L2entries
+ // (1 << addr bits) = arena size * L1 entries * L2 entries
//
// Currently, we balance these as follows:
//
- // Platform Addr bits Arena size L1 entries L2 size
- // -------------- --------- ---------- ---------- -------
- // */64-bit 48 64MB 1 32MB
- // windows/64-bit 48 4MB 64 8MB
- // */32-bit 32 4MB 1 4KB
- // */mips(le) 31 4MB 1 2KB
+ // Platform Addr bits Arena size L1 entries L2 entries
+ // -------------- --------- ---------- ---------- -----------
+ // */64-bit 48 64MB 1 4M (32MB)
+ // windows/64-bit 48 4MB 64 1M (8MB)
+ // */32-bit 32 4MB 1 1024 (4KB)
+ // */mips(le) 31 4MB 1 512 (2KB)
// heapArenaBytes is the size of a heap arena. The heap
// consists of mappings of size heapArenaBytes, aligned to
From f22c357a34521404c445dc2e848657ecbfa4ad5e Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick
Date: Thu, 4 Oct 2018 15:26:04 +0000
Subject: [PATCH 012/240] os: make UserHomeDir specialize behavior for
GOOS=android
Change-Id: I69582662aeee7344226856c24907516ddfc92f60
Reviewed-on: https://go-review.googlesource.com/c/139717
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
Reviewed-by: Elias Naur
---
src/os/file.go | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/os/file.go b/src/os/file.go
index eb2277dece..61f37f2489 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -387,16 +387,16 @@ func UserCacheDir() (string, error) {
// On Windows, it returns the concatenation of %HOMEDRIVE% and %HOMEPATH%.
// On Plan 9, it returns the $home environment variable.
func UserHomeDir() string {
- if runtime.GOOS == "windows" {
+ switch runtime.GOOS {
+ case "windows":
return Getenv("HOMEDRIVE") + Getenv("HOMEPATH")
- }
- if runtime.GOOS == "plan9" {
+ case "plan9":
return Getenv("home")
- }
- if runtime.GOOS == "nacl" {
+ case "nacl", "android":
return "/"
+ default:
+ return Getenv("HOME")
}
- return Getenv("HOME")
}
// Chmod changes the mode of the named file to mode.
From 497d24178fdc321a037150656d51bec40f93e6d6 Mon Sep 17 00:00:00 2001
From: Plekhanov Maxim
Date: Thu, 21 Dec 2017 02:14:55 +0300
Subject: [PATCH 013/240] math: use Abs in Mod rather than if x < 0 { x = -x}
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
goos: linux
goarch: amd64
pkg: math
name old time/op new time/op delta
Mod 64.7ns ± 2% 63.7ns ± 2% -1.52% (p=0.003 n=8+10)
Change-Id: I851bec0fd6c223dab73e4a680b7393d49e81a0e8
Reviewed-on: https://go-review.googlesource.com/c/85095
Reviewed-by: Brad Fitzpatrick
---
src/math/mod.go | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/math/mod.go b/src/math/mod.go
index e1a414e5f9..7efc018a5d 100644
--- a/src/math/mod.go
+++ b/src/math/mod.go
@@ -24,16 +24,12 @@ func mod(x, y float64) float64 {
if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) {
return NaN()
}
- if y < 0 {
- y = -y
- }
+ y = Abs(y)
yfr, yexp := Frexp(y)
- sign := false
r := x
if x < 0 {
r = -x
- sign = true
}
for r >= y {
@@ -43,7 +39,7 @@ func mod(x, y float64) float64 {
}
r = r - Ldexp(y, rexp-yexp)
}
- if sign {
+ if x < 0 {
r = -r
}
return r
From 47e71f3b6917113660a65a180e66c91fc6318458 Mon Sep 17 00:00:00 2001
From: Plekhanov Maxim
Date: Sat, 23 Dec 2017 02:25:35 +0300
Subject: [PATCH 014/240] math: use Abs in Pow rather than if x < 0 { x = -x }
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
name old time/op new time/op delta
PowInt 55.7ns ± 1% 53.4ns ± 2% -4.15% (p=0.000 n=9+9)
PowFrac 133ns ± 1% 133ns ± 2% ~ (p=0.587 n=8+9)
Change-Id: Ica0f4c2cbd554f2195c6d1762ed26742ff8e3924
Reviewed-on: https://go-review.googlesource.com/c/85375
Reviewed-by: Brad Fitzpatrick
---
src/math/pow.go | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/src/math/pow.go b/src/math/pow.go
index 336193bce1..2219a906b8 100644
--- a/src/math/pow.go
+++ b/src/math/pow.go
@@ -83,13 +83,7 @@ func pow(x, y float64) float64 {
return 1 / Sqrt(x)
}
- absy := y
- flip := false
- if absy < 0 {
- absy = -absy
- flip = true
- }
- yi, yf := Modf(absy)
+ yi, yf := Modf(Abs(y))
if yf != 0 && x < 0 {
return NaN()
}
@@ -147,9 +141,9 @@ func pow(x, y float64) float64 {
}
// ans = a1*2**ae
- // if flip { ans = 1 / ans }
+ // if y < 0 { ans = 1 / ans }
// but in the opposite order
- if flip {
+ if y < 0 {
a1 = 1 / a1
ae = -ae
}
From 6d73537128ad7ff35ba1dbc55fc2837b0989b6b2 Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick
Date: Thu, 4 Oct 2018 17:06:21 +0000
Subject: [PATCH 015/240] debug/pe: skip a test on windows/arm
It requires a DLL that's not available on windows/arm apparently.
Fixes #27904
Change-Id: I082a273f62976b7184636c6aeca6201a7871d238
Reviewed-on: https://go-review.googlesource.com/c/139720
Run-TryBot: Brad Fitzpatrick
Reviewed-by: Katie Hockman
TryBot-Result: Gobot Gobot
---
src/debug/pe/file_test.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index 24cd673254..c65c82d342 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -535,7 +535,11 @@ func TestBuildingWindowsGUI(t *testing.T) {
func TestImportTableInUnknownSection(t *testing.T) {
if runtime.GOOS != "windows" {
- t.Skip("skipping windows only test")
+ t.Skip("skipping Windows-only test")
+ }
+ if runtime.GOARCH == "arm" {
+ // Issue 27904
+ t.Skip("skipping test on arm; no atmfd.dll available")
}
// first we need to find this font driver
From d2170040617231a26ab0722d093ecb19e2ba8302 Mon Sep 17 00:00:00 2001
From: Alberto Donizetti
Date: Wed, 3 Oct 2018 21:11:31 +0200
Subject: [PATCH 016/240] runtime: skip TestLldbPython when lldb is too old
The TestLldbPython test is known to fail with very old lldb releases
(3.8 and older). Skip the test when the lldb found on the system is
too old.
Fixes #22299
Change-Id: I8f78d6c0d995118f806dae87f3f04a9726473116
Reviewed-on: https://go-review.googlesource.com/c/139397
Reviewed-by: Ian Lance Taylor
---
src/runtime/runtime-lldb_test.go | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index fe3a0eb90d..c74e6ef029 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -10,7 +10,9 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
+ "strconv"
"strings"
"testing"
)
@@ -25,6 +27,27 @@ func checkLldbPython(t *testing.T) {
}
lldbPath = strings.TrimSpace(string(out))
+ // Check lldb version. The test is known to fail with 3.8 or older
+ // (see Issue #22299).
+ cmd = exec.Command("lldb", "--version")
+ out, err = cmd.CombinedOutput()
+
+ // lldb --version should print "lldb version a.b.c"
+ re := regexp.MustCompile(` ([[:digit:]]+)\.([[:digit:]]+)`)
+ lldbVersion := re.FindStringSubmatch(string(out))
+ if len(lldbVersion) != 3 {
+ t.Errorf("bad lldb --version output: %s", out)
+ }
+ major, err1 := strconv.Atoi(lldbVersion[1])
+ minor, err2 := strconv.Atoi(lldbVersion[2])
+ if err1 != nil || err2 != nil {
+ t.Errorf("bad lldb --version output: %s", out)
+ }
+
+ if (major < 3) || (major == 3 && minor < 9) {
+ t.Skipf("skipping because lldb version %v.%v is too old (need >= 3.9)", major, minor)
+ }
+
cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
out, err = cmd.CombinedOutput()
From 808186203b9786c11073c7056767fdf82f49def6 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Tue, 11 Sep 2018 08:55:10 +0000
Subject: [PATCH 017/240] cmd/internal/obj/arm64: simplify ADD and SUB
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently "ADD $0x123456, Rs, Rd" will load pre-stored 0x123456
from the constant pool and use it for the addition. Total 12 bytes
are cost. And so does SUB.
This CL breaks it to "ADD 0x123000, Rs, Rd" + "ADD 0x000456, Rd, Rd".
Both "0x123000" and "0x000456" can be directly encoded into the
instruction binary code. So 4 bytes are saved.
1. The total size of pkg/android_arm64 decreases about 0.3KB.
2. The go1 benchmark show little regression (excluding noise).
name old time/op new time/op delta
BinaryTree17-4 15.9s ± 0% 15.9s ± 1% +0.10% (p=0.044 n=29+29)
Fannkuch11-4 8.72s ± 0% 8.75s ± 0% +0.34% (p=0.000 n=30+24)
FmtFprintfEmpty-4 173ns ± 0% 173ns ± 0% ~ (all equal)
FmtFprintfString-4 368ns ± 0% 368ns ± 0% ~ (p=0.593 n=30+30)
FmtFprintfInt-4 417ns ± 0% 417ns ± 0% ~ (all equal)
FmtFprintfIntInt-4 673ns ± 0% 661ns ± 1% -1.70% (p=0.000 n=30+30)
FmtFprintfPrefixedInt-4 805ns ± 0% 805ns ± 0% +0.10% (p=0.011 n=30+30)
FmtFprintfFloat-4 1.09µs ± 0% 1.09µs ± 0% ~ (p=0.125 n=30+29)
FmtManyArgs-4 2.68µs ± 0% 2.68µs ± 0% +0.07% (p=0.004 n=30+30)
GobDecode-4 32.9ms ± 0% 33.2ms ± 1% +1.07% (p=0.000 n=29+29)
GobEncode-4 29.5ms ± 0% 29.6ms ± 0% +0.26% (p=0.000 n=28+28)
Gzip-4 1.38s ± 1% 1.35s ± 3% -1.94% (p=0.000 n=28+30)
Gunzip-4 139ms ± 0% 139ms ± 0% +0.10% (p=0.000 n=28+29)
HTTPClientServer-4 745µs ± 5% 742µs ± 3% ~ (p=0.405 n=28+29)
JSONEncode-4 49.5ms ± 1% 49.9ms ± 0% +0.89% (p=0.000 n=30+30)
JSONDecode-4 264ms ± 1% 264ms ± 0% +0.25% (p=0.001 n=30+30)
Mandelbrot200-4 16.6ms ± 0% 16.6ms ± 0% ~ (p=0.507 n=29+29)
GoParse-4 15.9ms ± 0% 16.0ms ± 1% +0.91% (p=0.002 n=23+30)
RegexpMatchEasy0_32-4 379ns ± 0% 379ns ± 0% ~ (all equal)
RegexpMatchEasy0_1K-4 1.31µs ± 0% 1.31µs ± 0% +0.09% (p=0.008 n=27+30)
RegexpMatchEasy1_32-4 357ns ± 0% 358ns ± 0% +0.28% (p=0.000 n=28+29)
RegexpMatchEasy1_1K-4 2.04µs ± 0% 2.04µs ± 0% ~ (p=0.850 n=30+30)
RegexpMatchMedium_32-4 587ns ± 0% 589ns ± 0% +0.33% (p=0.000 n=30+30)
RegexpMatchMedium_1K-4 162µs ± 0% 163µs ± 0% ~ (p=0.351 n=30+29)
RegexpMatchHard_32-4 9.54µs ± 0% 9.60µs ± 0% +0.59% (p=0.000 n=28+30)
RegexpMatchHard_1K-4 287µs ± 0% 287µs ± 0% +0.11% (p=0.000 n=26+29)
Revcomp-4 2.50s ± 0% 2.50s ± 0% -0.13% (p=0.012 n=28+27)
Template-4 312ms ± 1% 312ms ± 1% +0.20% (p=0.015 n=27+30)
TimeParse-4 1.68µs ± 0% 1.68µs ± 0% -0.35% (p=0.000 n=30+30)
TimeFormat-4 1.66µs ± 0% 1.64µs ± 0% -1.20% (p=0.000 n=25+29)
[Geo mean] 246µs 246µs -0.00%
name old speed new speed delta
GobDecode-4 23.3MB/s ± 0% 23.1MB/s ± 1% -1.05% (p=0.000 n=29+29)
GobEncode-4 26.0MB/s ± 0% 25.9MB/s ± 0% -0.25% (p=0.000 n=29+28)
Gzip-4 14.1MB/s ± 1% 14.4MB/s ± 3% +1.94% (p=0.000 n=27+30)
Gunzip-4 139MB/s ± 0% 139MB/s ± 0% -0.10% (p=0.000 n=28+29)
JSONEncode-4 39.2MB/s ± 1% 38.9MB/s ± 0% -0.88% (p=0.000 n=30+30)
JSONDecode-4 7.37MB/s ± 0% 7.35MB/s ± 0% -0.26% (p=0.001 n=30+30)
GoParse-4 3.65MB/s ± 0% 3.62MB/s ± 1% -0.86% (p=0.001 n=23+30)
RegexpMatchEasy0_32-4 84.3MB/s ± 0% 84.3MB/s ± 0% ~ (p=0.126 n=27+26)
RegexpMatchEasy0_1K-4 784MB/s ± 0% 783MB/s ± 0% -0.10% (p=0.003 n=27+30)
RegexpMatchEasy1_32-4 89.5MB/s ± 0% 89.3MB/s ± 0% -0.20% (p=0.000 n=27+29)
RegexpMatchEasy1_1K-4 502MB/s ± 0% 502MB/s ± 0% ~ (p=0.858 n=30+28)
RegexpMatchMedium_32-4 1.70MB/s ± 0% 1.70MB/s ± 0% -0.25% (p=0.000 n=30+30)
RegexpMatchMedium_1K-4 6.30MB/s ± 0% 6.30MB/s ± 0% ~ (all equal)
RegexpMatchHard_32-4 3.35MB/s ± 0% 3.33MB/s ± 0% -0.47% (p=0.000 n=30+30)
RegexpMatchHard_1K-4 3.57MB/s ± 0% 3.56MB/s ± 0% -0.20% (p=0.000 n=27+30)
Revcomp-4 102MB/s ± 0% 102MB/s ± 0% +0.14% (p=0.008 n=28+28)
Template-4 6.23MB/s ± 0% 6.21MB/s ± 1% -0.21% (p=0.009 n=21+30)
[Geo mean] 24.1MB/s 24.0MB/s -0.16%
Change-Id: Ifcef3edb667540e2d86e586c23afcfbc2cf1340b
Reviewed-on: https://go-review.googlesource.com/c/134536
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/cmd/asm/internal/asm/testdata/arm64.s | 12 ++++++++
src/cmd/internal/obj/arm64/a.out.go | 1 +
src/cmd/internal/obj/arm64/anames7.go | 1 +
src/cmd/internal/obj/arm64/asm7.go | 34 +++++++++++++++++++++--
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 9e2e2b1dc5..079c620f9b 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -25,6 +25,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADD R1, R2, R3
ADD R1, ZR, R3
ADD $1, R2, R3
+ ADD $0x000aaa, R2, R3 // ADD $2730, R2, R3 // 43a82a91
+ ADD $0x000aaa, R2 // ADD $2730, R2 // 42a82a91
+ ADD $0xaaa000, R2, R3 // ADD $11182080, R2, R3 // 43a86a91
+ ADD $0xaaa000, R2 // ADD $11182080, R2 // 42a86a91
+ ADD $0xaaaaaa, R2, R3 // ADD $11184810, R2, R3 // 43a82a9163a86a91
+ ADD $0xaaaaaa, R2 // ADD $11184810, R2 // 42a82a9142a86a91
+ SUB $0x000aaa, R2, R3 // SUB $2730, R2, R3 // 43a82ad1
+ SUB $0x000aaa, R2 // SUB $2730, R2 // 42a82ad1
+ SUB $0xaaa000, R2, R3 // SUB $11182080, R2, R3 // 43a86ad1
+ SUB $0xaaa000, R2 // SUB $11182080, R2 // 42a86ad1
+ SUB $0xaaaaaa, R2, R3 // SUB $11184810, R2, R3 // 43a82ad163a86ad1
+ SUB $0xaaaaaa, R2 // SUB $11184810, R2 // 42a82ad142a86ad1
ADD R1>>11, R2, R3
ADD R1<<22, R2, R3
ADD R1->33, R2, R3
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index 65647c37ae..37df688b21 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -411,6 +411,7 @@ const (
C_MBCON // could be C_MOVCON or C_BITCON
C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
C_BITCON // bitfield and logical immediate masks
+ C_ADDCON2 // 24-bit constant
C_LCON // 32-bit constant
C_VCON // 64-bit constant
C_FCON // floating-point constant
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index 92f0cec942..a768f2cbef 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -27,6 +27,7 @@ var cnames7 = []string{
"MBCON",
"MOVCON",
"BITCON",
+ "ADDCON2",
"LCON",
"VCON",
"FCON",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 46fdcdcf7d..67cefe3aeb 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -192,6 +192,8 @@ var optab = []Optab{
{AADD, C_BITCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0},
{AADD, C_BITCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0},
{ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
+ {AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, 0, 0},
+ {AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, 0, 0},
{AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 8, 0, LFROM, 0},
@@ -1046,6 +1048,7 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
C_NOREG4K,
C_LOREG,
C_LACON,
+ C_ADDCON2,
C_LCON,
C_VCON:
if a.Name == obj.NAME_EXTERN {
@@ -1537,6 +1540,10 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
return C_BITCON
}
+ if 0 <= v && v <= 0xffffff {
+ return C_ADDCON2
+ }
+
if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) {
return C_LCON
}
@@ -1595,7 +1602,12 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
}
a1 = int(p.From.Class)
if a1 == 0 {
- a1 = c.aclass(&p.From) + 1
+ a0 := c.aclass(&p.From)
+ // do not break C_ADDCON2 when S bit is set
+ if (p.As == AADDS || p.As == AADDSW || p.As == ASUBS || p.As == ASUBSW) && a0 == C_ADDCON2 {
+ a0 = C_LCON
+ }
+ a1 = a0 + 1
p.From.Class = int8(a1)
}
@@ -1681,8 +1693,13 @@ func cmp(a int, b int) bool {
return true
}
+ case C_ADDCON2:
+ if b == C_ZCON || b == C_ADDCON || b == C_ADDCON0 {
+ return true
+ }
+
case C_LCON:
- if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON {
+ if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON || b == C_ADDCON2 {
return true
}
@@ -3474,6 +3491,19 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 |= 0x1c1<<21 | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
+ case 48: /* ADD $C_ADDCON2, Rm, Rd */
+ op := c.opirr(p, p.As)
+ if op&Sbit != 0 {
+ c.ctxt.Diag("can not break addition/subtraction when S bit is set", p)
+ }
+ rt := int(p.To.Reg)
+ r := int(p.Reg)
+ if r == 0 {
+ r = rt
+ }
+ o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From)) & 0x000fff, r, rt)
+ o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From)) & 0xfff000, rt, rt)
+
case 50: /* sys/sysl */
o1 = c.opirr(p, p.As)
From fa179eb89d881565238a21a8a740de6ca3cf9bc2 Mon Sep 17 00:00:00 2001
From: Mikio Hara
Date: Fri, 5 Oct 2018 04:47:09 +0900
Subject: [PATCH 018/240] vendor: update golang_org/x/net/route from upstream
Updates the route package to git rev 68fc911 for:
- 68fc911 re-adjust routing message alignment for FreeBSD 386 emulation
- 4dfa261 fix typos in comments
- ae89d30 avoid unnecessary type conversions
Change-Id: I915e614e464acf85a8fc80f36f05a85a9246bb01
Reviewed-on: https://go-review.googlesource.com/c/139817
Run-TryBot: Mikio Hara
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/vendor/golang_org/x/net/route/interface.go | 2 +-
src/vendor/golang_org/x/net/route/sys_freebsd.go | 5 ++++-
src/vendor/golang_org/x/net/route/syscall.go | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/vendor/golang_org/x/net/route/interface.go b/src/vendor/golang_org/x/net/route/interface.go
index 854906d9c4..05ef2a9ce3 100644
--- a/src/vendor/golang_org/x/net/route/interface.go
+++ b/src/vendor/golang_org/x/net/route/interface.go
@@ -37,7 +37,7 @@ func (m *InterfaceAddrMessage) Sys() []Sys { return nil }
// address message.
type InterfaceMulticastAddrMessage struct {
Version int // message version
- Type int // messsage type
+ Type int // message type
Flags int // interface flags
Index int // interface index
Addrs []Addr // addresses
diff --git a/src/vendor/golang_org/x/net/route/sys_freebsd.go b/src/vendor/golang_org/x/net/route/sys_freebsd.go
index 89ba1c4e26..a1a0d79b61 100644
--- a/src/vendor/golang_org/x/net/route/sys_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_freebsd.go
@@ -57,7 +57,7 @@ func (m *InterfaceMessage) Sys() []Sys {
func probeRoutingStack() (int, map[int]*wireFormat) {
var p uintptr
wordSize := int(unsafe.Sizeof(p))
- align := int(unsafe.Sizeof(p))
+ align := wordSize
// In the case of kern.supported_archs="amd64 i386", we need
// to know the underlying kernel's architecture because the
// alignment for routing facilities are set at the build time
@@ -129,6 +129,9 @@ func probeRoutingStack() (int, map[int]*wireFormat) {
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD11
}
+ if rel >= 1102000 { // see https://github.com/freebsd/freebsd/commit/027c7f4d66ff8d8c4a46c3665a5ee7d6d8462034#diff-ad4e5b7f1449ea3fc87bc97280de145b
+ align = wordSize
+ }
}
rtm.parse = rtm.parseRouteMessage
ifm.parse = ifm.parseInterfaceMessage
diff --git a/src/vendor/golang_org/x/net/route/syscall.go b/src/vendor/golang_org/x/net/route/syscall.go
index c211188b10..5f69ea63d9 100644
--- a/src/vendor/golang_org/x/net/route/syscall.go
+++ b/src/vendor/golang_org/x/net/route/syscall.go
@@ -20,7 +20,7 @@ func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
} else {
p = unsafe.Pointer(&zero)
}
- _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), newlen)
if errno != 0 {
return error(errno)
}
From 1bca6cecc627cd708c6c5440eb14f84a99d5324b Mon Sep 17 00:00:00 2001
From: Jason Keene
Date: Wed, 12 Sep 2018 20:35:58 -0600
Subject: [PATCH 019/240] cmd/go: ensure git attributes are set
This change disables the export-subst and export-ignore attributes when
creating zip files for modules. This is done to prevent the ziphash for
a given repo/revision from differing based on variables such as git
version or size of repo. The full rational for this change is detailed
here:
https://github.com/golang/go/issues/27153#issuecomment-420763082
Fixes #27153
Change-Id: Ib33f525d91d2581fa0b5d26e70d29620c7e685e9
Reviewed-on: https://go-review.googlesource.com/c/135175
Run-TryBot: Bryan C. Mills
TryBot-Result: Gobot Gobot
Reviewed-by: Bryan C. Mills
---
src/cmd/go/internal/modfetch/codehost/git.go | 44 +++++++++++++++++++
.../testdata/script/mod_git_export_subst.txt | 21 +++++++++
2 files changed, 65 insertions(+)
create mode 100644 src/cmd/go/testdata/script/mod_git_export_subst.txt
diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go
index 87940a8f02..bcf8609826 100644
--- a/src/cmd/go/internal/modfetch/codehost/git.go
+++ b/src/cmd/go/internal/modfetch/codehost/git.go
@@ -694,6 +694,10 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return nil, "", err
}
+ if err := ensureGitAttributes(r.dir); err != nil {
+ return nil, "", err
+ }
+
// Incredibly, git produces different archives depending on whether
// it is running on a Windows system or not, in an attempt to normalize
// text file line endings. Setting -c core.autocrlf=input means only
@@ -709,3 +713,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
}
+
+// ensureGitAttributes makes sure export-subst and export-ignore features are
+// disabled for this repo. This is intended to be run prior to running git
+// archive so that zip files are generated that produce consistent ziphashes
+// for a given revision, independent of variables such as git version and the
+// size of the repo.
+//
+// See: https://github.com/golang/go/issues/27153
+func ensureGitAttributes(repoDir string) (err error) {
+ const attr = "\n* -export-subst -export-ignore\n"
+
+ d := repoDir + "/info"
+ p := d + "/attributes"
+
+ if err := os.MkdirAll(d, 0755); err != nil {
+ return err
+ }
+
+ f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ closeErr := f.Close()
+ if closeErr != nil {
+ err = closeErr
+ }
+ }()
+
+ b, err := ioutil.ReadAll(f)
+ if err != nil {
+ return err
+ }
+ if !bytes.HasSuffix(b, []byte(attr)) {
+ _, err := f.WriteString(attr)
+ return err
+ }
+
+ return nil
+}
diff --git a/src/cmd/go/testdata/script/mod_git_export_subst.txt b/src/cmd/go/testdata/script/mod_git_export_subst.txt
new file mode 100644
index 0000000000..2b8e2bc7bc
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_git_export_subst.txt
@@ -0,0 +1,21 @@
+env GO111MODULE=on
+env GOPROXY=
+
+# Testing that git export-subst is disabled
+[!net] skip
+[!exec:git] skip
+go build
+
+-- x.go --
+package x
+
+import _ "github.com/jasonkeene/export-subst"
+
+-- go.mod --
+module x
+
+require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626
+
+-- go.sum --
+github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0=
+github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw=
From 48e22da1d24dc5b038bd83a78553173af5474e76 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Thu, 4 Oct 2018 16:32:21 -0700
Subject: [PATCH 020/240] cmd/link: fix deferreturn location on wasm
On wasm, pcln tables are indexed by "resumption point ID" instead of
by pc offset. When finding a deferreturn call, we must find the
associated resumption point ID for the deferreturn call.
Update #27518
Fixes wasm bug introduced in CL 134637.
Change-Id: I3d178a3f5203a06c0180a1aa2309bfb7f3014f0f
Reviewed-on: https://go-review.googlesource.com/c/139898
Reviewed-by: Cherry Zhang
---
src/cmd/link/internal/ld/pcln.go | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 24398fcc87..3eb3d05882 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -7,6 +7,7 @@ package ld
import (
"cmd/internal/objabi"
"cmd/internal/src"
+ "cmd/internal/sys"
"cmd/link/internal/sym"
"log"
"os"
@@ -314,13 +315,26 @@ func (ctxt *Link) pclntab() {
// deferreturn
deferreturn := uint32(0)
+ lastWasmAddr := uint32(0)
for _, r := range s.R {
+ if ctxt.Arch.Family == sys.Wasm && r.Type == objabi.R_ADDR {
+ // Wasm does not have a live variable set at the deferreturn
+ // call itself. Instead it has one identified by the
+ // resumption point immediately preceding the deferreturn.
+ // The wasm code has a R_ADDR relocation which is used to
+ // set the resumption point to PC_B.
+ lastWasmAddr = uint32(r.Add)
+ }
if r.Sym != nil && r.Sym.Name == "runtime.deferreturn" && r.Add == 0 {
- // Note: the relocation target is in the call instruction, but
- // is not necessarily the whole instruction (for instance, on
- // x86 the relocation applies to bytes [1:5] of the 5 byte call
- // instruction).
- deferreturn = uint32(r.Off)
+ if ctxt.Arch.Family == sys.Wasm {
+ deferreturn = lastWasmAddr
+ } else {
+ // Note: the relocation target is in the call instruction, but
+ // is not necessarily the whole instruction (for instance, on
+ // x86 the relocation applies to bytes [1:5] of the 5 byte call
+ // instruction).
+ deferreturn = uint32(r.Off)
+ }
break // only need one
}
}
From 8256bcdae0da68644db1e33c0db86f5ac4395c4b Mon Sep 17 00:00:00 2001
From: Alex Brainman
Date: Sat, 16 Jun 2018 16:23:52 +1000
Subject: [PATCH 021/240] cmd/link: move .rel symbol from .rdata into .text
.rel symbol type is sym.SELFROSECT, and that makes .rel written
into .rdata section. But .rel stores code - jump table used for
external C functions. So we have to mark whole .rdata section
as executable (IMAGE_SCN_MEM_EXECUTE), because of .rel presence
in it.
Move .rel into .text section, and make .rdata section non executable.
I also had to move code that adjusted the size of .rel symbol
before calling textaddress, otherwise textaddress would not
calculate size of .text section correctly.
Fixes #25926
Change-Id: I4962f5de7b367410154c8709adfcd8472de9ac1a
Reviewed-on: https://go-review.googlesource.com/c/125455
Run-TryBot: Alex Brainman
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/link/internal/ld/data.go | 38 +++++++++++++++++++++++---------
src/cmd/link/internal/ld/main.go | 1 +
src/cmd/link/internal/ld/pe.go | 9 --------
3 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index ee98aef20d..3cc9e294d2 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -529,11 +529,7 @@ func (ctxt *Link) reloc() {
}
}
-func windynrelocsym(ctxt *Link, s *sym.Symbol) {
- rel := ctxt.Syms.Lookup(".rel", 0)
- if s == rel {
- return
- }
+func windynrelocsym(ctxt *Link, rel, s *sym.Symbol) {
for ri := range s.R {
r := &s.R[ri]
targ := r.Sym
@@ -576,14 +572,31 @@ func windynrelocsym(ctxt *Link, s *sym.Symbol) {
}
}
-func dynrelocsym(ctxt *Link, s *sym.Symbol) {
- if ctxt.HeadType == objabi.Hwindows {
- if ctxt.LinkMode == LinkInternal {
- windynrelocsym(ctxt, s)
- }
+// windynrelocsyms generates jump table to C library functions that will be
+// added later. windynrelocsyms writes the table into .rel symbol.
+func (ctxt *Link) windynrelocsyms() {
+ if !(ctxt.HeadType == objabi.Hwindows && iscgo && ctxt.LinkMode == LinkInternal) {
return
}
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f windynrelocsyms\n", Cputime())
+ }
+ /* relocation table */
+ rel := ctxt.Syms.Lookup(".rel", 0)
+ rel.Attr |= sym.AttrReachable
+ rel.Type = sym.STEXT
+ ctxt.Textp = append(ctxt.Textp, rel)
+
+ for _, s := range ctxt.Textp {
+ if s == rel {
+ continue
+ }
+ windynrelocsym(ctxt, rel, s)
+ }
+}
+
+func dynrelocsym(ctxt *Link, s *sym.Symbol) {
for ri := range s.R {
r := &s.R[ri]
if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
@@ -605,9 +618,12 @@ func dynrelocsym(ctxt *Link, s *sym.Symbol) {
}
func dynreloc(ctxt *Link, data *[sym.SXREF][]*sym.Symbol) {
+ if ctxt.HeadType == objabi.Hwindows {
+ return
+ }
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
- if *FlagD && ctxt.HeadType != objabi.Hwindows {
+ if *FlagD {
return
}
if ctxt.Debugvlog != 0 {
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 905380a1db..2c5152f2e3 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -222,6 +222,7 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.dostkcheck()
if ctxt.HeadType == objabi.Hwindows {
ctxt.dope()
+ ctxt.windynrelocsyms()
}
ctxt.addexport()
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index db269c78e5..cf197f50b0 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -1461,12 +1461,6 @@ func addPEBaseReloc(ctxt *Link) {
}
func (ctxt *Link) dope() {
- /* relocation table */
- rel := ctxt.Syms.Lookup(".rel", 0)
-
- rel.Attr |= sym.AttrReachable
- rel.Type = sym.SELFROSECT
-
initdynimport(ctxt)
initdynexport(ctxt)
}
@@ -1534,9 +1528,6 @@ func Asmbpe(ctxt *Link) {
// some data symbols (e.g. masks) end up in the .rdata section, and they normally
// expect larger alignment requirement than the default text section alignment.
ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
- } else {
- // TODO(brainman): should not need IMAGE_SCN_MEM_EXECUTE, but I do not know why it carshes without it
- ro.characteristics |= IMAGE_SCN_MEM_EXECUTE
}
ro.checkSegment(&Segrodata)
pefile.rdataSect = ro
From 415e948eaea05930b2a16bab6af9e38b24e8414b Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Fri, 30 Jun 2017 12:10:01 -0400
Subject: [PATCH 022/240] runtime: improve mheap.alloc doc and let compiler
check system stack
The alloc_m documentation refers to concepts that don't exist (and
maybe never did?). alloc_m is also not the API entry point to span
allocation.
Hence, rewrite the documentation for alloc and alloc_m. While we're
here, document why alloc_m must run on the system stack and replace
alloc_m's hand-implemented system stack check with a go:systemstack
annotation.
Change-Id: I30e263d8e53c2774a6614e1b44df5464838cef09
Reviewed-on: https://go-review.googlesource.com/c/139459
Run-TryBot: Austin Clements
Reviewed-by: Michael Knyszek
Reviewed-by: Keith Randall
TryBot-Result: Gobot Gobot
---
src/runtime/mheap.go | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 7a11bdc058..b92e27e4e0 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -657,13 +657,14 @@ func (h *mheap) reclaim(npage uintptr) {
lock(&h.lock)
}
-// Allocate a new span of npage pages from the heap for GC'd memory
-// and record its size class in the HeapMap and HeapMapCache.
+// alloc_m is the internal implementation of mheap.alloc.
+//
+// alloc_m must run on the system stack because it locks the heap, so
+// any stack growth during alloc_m would self-deadlock.
+//
+//go:systemstack
func (h *mheap) alloc_m(npage uintptr, spanclass spanClass, large bool) *mspan {
_g_ := getg()
- if _g_ != _g_.m.g0 {
- throw("_mheap_alloc not on g0 stack")
- }
lock(&h.lock)
// To prevent excessive heap growth, before allocating n pages
@@ -752,6 +753,12 @@ func (h *mheap) alloc_m(npage uintptr, spanclass spanClass, large bool) *mspan {
return s
}
+// alloc allocates a new span of npage pages from the GC'd heap.
+//
+// Either large must be true or spanclass must indicates the span's
+// size class and scannability.
+//
+// If needzero is true, the memory for the returned span will be zeroed.
func (h *mheap) alloc(npage uintptr, spanclass spanClass, large bool, needzero bool) *mspan {
// Don't do any operations that lock the heap on the G stack.
// It might trigger stack growth, and the stack growth code needs
From 28fa1da9db8eedf079f1b83fd39383e17b3d7e68 Mon Sep 17 00:00:00 2001
From: Meng Zhuo
Date: Thu, 4 Oct 2018 16:46:22 +0800
Subject: [PATCH 023/240] cmd/api: explicit tagKey with GOOS and GOARCH
The origin tagKey is just dirname if no tags input which will cause
pkgCache missmatch if other imported pkg explicit on GOARCH or GOOS
This CL will add GOOS and GOARCH to tagKey
Fixes #8425
Fixes #21181
Change-Id: Ifc189cf6746d753ad7c7e5bb60621297fc0a4e35
Reviewed-on: https://go-review.googlesource.com/c/138315
Reviewed-by: Robert Griesemer
---
api/except.txt | 2 ++
src/cmd/api/goapi.go | 14 ++++++++++----
src/cmd/api/goapi_test.go | 15 +++++++++++++++
src/cmd/api/testdata/src/issue21181/dep/p.go | 5 +++++
.../api/testdata/src/issue21181/dep/p_amd64.go | 1 +
src/cmd/api/testdata/src/issue21181/indirect/p.go | 5 +++++
src/cmd/api/testdata/src/issue21181/p/p.go | 9 +++++++++
src/cmd/api/testdata/src/issue21181/p/p_amd64.go | 7 +++++++
.../api/testdata/src/issue21181/p/p_generic.go | 11 +++++++++++
9 files changed, 65 insertions(+), 4 deletions(-)
create mode 100644 src/cmd/api/testdata/src/issue21181/dep/p.go
create mode 100644 src/cmd/api/testdata/src/issue21181/dep/p_amd64.go
create mode 100644 src/cmd/api/testdata/src/issue21181/indirect/p.go
create mode 100644 src/cmd/api/testdata/src/issue21181/p/p.go
create mode 100644 src/cmd/api/testdata/src/issue21181/p/p_amd64.go
create mode 100644 src/cmd/api/testdata/src/issue21181/p/p_generic.go
diff --git a/api/except.txt b/api/except.txt
index 9f7f3fe934..90b79f1592 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -6,6 +6,8 @@ pkg os, const ModeType = 2399141888
pkg os, const ModeType = 2399666176
pkg os (linux-arm), const O_SYNC = 4096
pkg os (linux-arm-cgo), const O_SYNC = 4096
+pkg os (linux-arm), const O_SYNC = 1052672
+pkg os (linux-arm-cgo), const O_SYNC = 1052672
pkg syscall (darwin-386), const ImplementsGetwd = false
pkg syscall (darwin-386), func Fchflags(string, int) error
pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 8cc78c01ed..9698f25b51 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -385,9 +385,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
return f, nil
}
-// The package cache doesn't operate correctly in rare (so far artificial)
-// circumstances (issue 8425). Disable before debugging non-obvious errors
-// from the type-checker.
+// Disable before debugging non-obvious errors from the type-checker.
const usePkgCache = true
var (
@@ -398,7 +396,7 @@ var (
// tagKey returns the tag-based key to use in the pkgCache.
// It is a comma-separated string; the first part is dir, the rest tags.
// The satisfied tags are derived from context but only those that
-// matter (the ones listed in the tags argument) are used.
+// matter (the ones listed in the tags argument plus GOOS and GOARCH) are used.
// The tags list, which came from go/build's Package.AllTags,
// is known to be sorted.
func tagKey(dir string, context *build.Context, tags []string) string {
@@ -414,9 +412,17 @@ func tagKey(dir string, context *build.Context, tags []string) string {
}
// TODO: ReleaseTags (need to load default)
key := dir
+
+ // explicit on GOOS and GOARCH as global cache will use "all" cached packages for
+ // an indirect imported package. See https://github.com/golang/go/issues/21181
+ // for more detail.
+ tags = append(tags, context.GOOS, context.GOARCH)
+ sort.Strings(tags)
+
for _, tag := range tags {
if ctags[tag] {
key += "," + tag
+ ctags[tag] = false
}
}
return key
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index 3c4e50a21a..1c8e2a345b 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -188,3 +188,18 @@ func BenchmarkAll(b *testing.B) {
}
}
}
+
+func TestIssue21181(t *testing.T) {
+ for _, c := range contexts {
+ c.Compiler = build.Default.Compiler
+ }
+ for _, context := range contexts {
+ w := NewWalker(context, "testdata/src/issue21181")
+ pkg, err := w.Import("p")
+ if err != nil {
+ t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
+ pkg.Name(), w.imported)
+ }
+ w.export(pkg)
+ }
+}
diff --git a/src/cmd/api/testdata/src/issue21181/dep/p.go b/src/cmd/api/testdata/src/issue21181/dep/p.go
new file mode 100644
index 0000000000..2d8e0c4cce
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/dep/p.go
@@ -0,0 +1,5 @@
+package dep
+
+type Interface interface {
+ N([]byte)
+}
diff --git a/src/cmd/api/testdata/src/issue21181/dep/p_amd64.go b/src/cmd/api/testdata/src/issue21181/dep/p_amd64.go
new file mode 100644
index 0000000000..8a2343a0e2
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/dep/p_amd64.go
@@ -0,0 +1 @@
+package dep
diff --git a/src/cmd/api/testdata/src/issue21181/indirect/p.go b/src/cmd/api/testdata/src/issue21181/indirect/p.go
new file mode 100644
index 0000000000..e37cf3fc44
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/indirect/p.go
@@ -0,0 +1,5 @@
+package indirect
+
+import "dep"
+
+func F(dep.Interface) {}
diff --git a/src/cmd/api/testdata/src/issue21181/p/p.go b/src/cmd/api/testdata/src/issue21181/p/p.go
new file mode 100644
index 0000000000..a704160edc
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/p/p.go
@@ -0,0 +1,9 @@
+package p
+
+import (
+ "dep"
+)
+
+type algo struct {
+ indrt func(dep.Interface)
+}
diff --git a/src/cmd/api/testdata/src/issue21181/p/p_amd64.go b/src/cmd/api/testdata/src/issue21181/p/p_amd64.go
new file mode 100644
index 0000000000..02b4cbf036
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/p/p_amd64.go
@@ -0,0 +1,7 @@
+package p
+
+import "indirect"
+
+var in = []algo{
+ {indirect.F},
+}
diff --git a/src/cmd/api/testdata/src/issue21181/p/p_generic.go b/src/cmd/api/testdata/src/issue21181/p/p_generic.go
new file mode 100644
index 0000000000..4d75809676
--- /dev/null
+++ b/src/cmd/api/testdata/src/issue21181/p/p_generic.go
@@ -0,0 +1,11 @@
+// +build !amd64
+
+package p
+
+import (
+ "indirect"
+)
+
+var in = []algo{
+ {indirect.F},
+}
From f2c1c7acf84a6ea8092f3b098de177b3265fbace Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 4 Oct 2018 12:59:09 -0700
Subject: [PATCH 024/240] go/types: fix recvPtr helper (follow-up on
https://golang.org/cl/139422)
The prior CL prepared go/types for the situation where methods might
not have a type-checked signature when being looked up. The respective
adjustments to recvPtr were not correct (but because so far method
signatures are type-checked in time, the bug didn't manifest itself).
Updates #23203.
Updates #26854.
Change-Id: I796691d11e6aac84396bdef802ad30715755fcc6
Reviewed-on: https://go-review.googlesource.com/c/139721
Reviewed-by: Alan Donovan
---
src/go/types/methodset.go | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
index c25236656e..619c448492 100644
--- a/src/go/types/methodset.go
+++ b/src/go/types/methodset.go
@@ -256,9 +256,12 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
// ptrRecv reports whether the receiver is of the form *T.
func ptrRecv(f *Func) bool {
- // If a method's type is set, use that as the source of truth for the receiver.
- if f.typ != nil {
- _, isPtr := deref(f.typ.(*Signature).recv.typ)
+ // If a method's receiver type is set, use that as the source of truth for the receiver.
+ // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
+ // signature. We may reach here before the signature is fully set up: we must explicitly
+ // check if the receiver is set (we cannot just look for non-nil f.typ).
+ if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
+ _, isPtr := deref(sig.recv.typ)
return isPtr
}
From bf9240681dec2664f6acc1695e517e985d2b85d3 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 3 Oct 2018 17:50:02 -0700
Subject: [PATCH 025/240] go/types: prepare for delayed type-checking of
methods to when they are used
Remove assumption that methods associated to concrete (non-interface)
types have a fully set up signature. Such methods are found through
LookupFieldOrMethod or lookupMethod, or indexed method access from
a Named type. Make sure that the method's signature is type-checked
before use in those cases.
(MethodSets also hold methods but the type checker is not using
them but for internal verification. API clients will be using it
after all methods have been type-checked.)
Some functions such as MissingMethod may now have to type-check a
method and for that they need a *Checker. Add helper functions as
necessary to provide the additional (receiver) parameter but permit
it to be nil if the respective functions are invoked through the API
(at which point we know that all methods have a proper signature and
thus we don't need the delayed type-check).
Since all package-level objects eventually are type-checked through
the top-level loop in Checker.packageObjects we are guaranteed that
all methods will be type-checked as well.
Updates #23203.
Updates #26854.
Change-Id: I6e48f0016cefd498aa70b776e84a48215a9042c5
Reviewed-on: https://go-review.googlesource.com/c/139425
Reviewed-by: Alan Donovan
---
src/go/types/api.go | 6 +++---
src/go/types/assignments.go | 2 +-
src/go/types/builtins.go | 4 ++--
src/go/types/call.go | 5 +++++
src/go/types/conversions.go | 11 +++++++----
src/go/types/decl.go | 4 ++++
src/go/types/expr.go | 17 +++++++++++++----
src/go/types/lookup.go | 27 ++++++++++++++++++++++++---
src/go/types/operand.go | 8 +++++---
src/go/types/type.go | 2 +-
src/go/types/typexpr.go | 2 +-
11 files changed, 66 insertions(+), 22 deletions(-)
diff --git a/src/go/types/api.go b/src/go/types/api.go
index b1fcb2d10b..1252aade35 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -353,20 +353,20 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
- m, _ := assertableTo(V, T)
+ m, _ := (*Checker)(nil).assertableTo(V, T)
return m == nil
}
// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
x := operand{mode: value, typ: V}
- return x.assignableTo(nil, T, nil) // config not needed for non-constant x
+ return x.assignableTo(nil, T, nil) // check not needed for non-constant x
}
// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
x := operand{mode: value, typ: V}
- return x.convertibleTo(nil, T) // config not needed for non-constant x
+ return x.convertibleTo(nil, T) // check not needed for non-constant x
}
// Implements reports whether type V implements interface T.
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 27002f6699..efa0cbba50 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -57,7 +57,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
return
}
- if reason := ""; !x.assignableTo(check.conf, T, &reason) {
+ if reason := ""; !x.assignableTo(check, T, &reason) {
if reason != "" {
check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason)
} else {
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index d3f0c4d40d..882c773db4 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -95,7 +95,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// spec: "As a special case, append also accepts a first argument assignable
// to type []byte with a second argument of string type followed by ... .
// This form appends the bytes of the string.
- if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte), nil) {
+ if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check, NewSlice(universeByte), nil) {
arg(x, 1)
if x.mode == invalid {
return
@@ -345,7 +345,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
- if !x.assignableTo(check.conf, m.key, nil) {
+ if !x.assignableTo(check, m.key, nil) {
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
return
}
diff --git a/src/go/types/call.go b/src/go/types/call.go
index d5c196afe8..52f1ac31ce 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -383,6 +383,11 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
goto Error
}
+ // methods may not have a fully set up signature yet
+ if m, _ := obj.(*Func); m != nil {
+ check.objDecl(m, nil)
+ }
+
if x.mode == typexpr {
// method expression
m, _ := obj.(*Func)
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 81a65838fe..fecb7b617f 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -18,7 +18,7 @@ func (check *Checker) conversion(x *operand, T Type) {
case constArg && isConstType(T):
// constant conversion
switch t := T.Underlying().(*Basic); {
- case representableConst(x.val, check.conf, t, &x.val):
+ case representableConst(x.val, check, t, &x.val):
ok = true
case isInteger(x.typ) && isString(t):
codepoint := int64(-1)
@@ -31,7 +31,7 @@ func (check *Checker) conversion(x *operand, T Type) {
x.val = constant.MakeString(string(codepoint))
ok = true
}
- case x.convertibleTo(check.conf, T):
+ case x.convertibleTo(check, T):
// non-constant conversion
x.mode = value
ok = true
@@ -76,9 +76,12 @@ func (check *Checker) conversion(x *operand, T Type) {
// is tricky because we'd have to run updateExprType on the argument first.
// (Issue #21982.)
-func (x *operand) convertibleTo(conf *Config, T Type) bool {
+// convertibleTo reports whether T(x) is valid.
+// The check parameter may be nil if convertibleTo is invoked through an
+// exported API call, i.e., when all methods have been type-checked.
+func (x *operand) convertibleTo(check *Checker, T Type) bool {
// "x is assignable to T"
- if x.assignableTo(conf, T, nil) {
+ if x.assignableTo(check, T, nil) {
return true
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 0ff1fb058b..b4a1eec1ac 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -586,6 +586,10 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
}
// type-check
+ // TODO(gri): This call is not needed anymore because the code can handle
+ // method signatures that have not yet been type-checked.
+ // Remove in separate CL to make it easy to isolate issues
+ // that might be introduced by this change.
check.objDecl(m, nil)
if base != nil {
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index fc4de98eb7..87769d1db0 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -187,11 +187,20 @@ func roundFloat64(x constant.Value) constant.Value {
// representable floating-point and complex values, and to an Int
// value for integer values; it is left alone otherwise.
// It is ok to provide the addressof the first argument for rounded.
-func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool {
+//
+// The check parameter may be nil if representableConst is invoked
+// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
+// because we don't need the Checker's config for those calls.
+func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
if x.Kind() == constant.Unknown {
return true // avoid follow-up errors
}
+ var conf *Config
+ if check != nil {
+ conf = check.conf
+ }
+
switch {
case isInteger(typ):
x := constant.ToInt(x)
@@ -323,7 +332,7 @@ func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *con
// representable checks that a constant operand is representable in the given basic type.
func (check *Checker) representable(x *operand, typ *Basic) {
assert(x.mode == constant_)
- if !representableConst(x.val, check.conf, typ, &x.val) {
+ if !representableConst(x.val, check, typ, &x.val) {
var msg string
if isNumeric(x.typ) && isNumeric(typ) {
// numeric conversion : error msg
@@ -576,7 +585,7 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
// spec: "In any comparison, the first operand must be assignable
// to the type of the second operand, or vice versa."
err := ""
- if x.assignableTo(check.conf, y.typ, nil) || y.assignableTo(check.conf, x.typ, nil) {
+ if x.assignableTo(check, y.typ, nil) || y.assignableTo(check, x.typ, nil) {
defined := false
switch op {
case token.EQL, token.NEQ:
@@ -1547,7 +1556,7 @@ func keyVal(x constant.Value) interface{} {
// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) {
- method, wrongType := assertableTo(xtyp, T)
+ method, wrongType := check.assertableTo(xtyp, T)
if method == nil {
return
}
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
index f31ef9cfe9..e6764f45a0 100644
--- a/src/go/types/lookup.go
+++ b/src/go/types/lookup.go
@@ -6,6 +6,11 @@
package types
+// Internal use of LookupFieldOrMethod: If the obj result is a method
+// associated with a concrete (non-interface) type, the method's signature
+// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
+// the method's type.
+
// LookupFieldOrMethod looks up a field or method with given package and name
// in T and returns the corresponding *Var or *Func, an index sequence, and a
// bool indicating if there were any pointer indirections on the path to the
@@ -112,7 +117,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// look for a matching attached method
if i, m := lookupMethod(named.methods, pkg, name); m != nil {
// potential match
- assert(m.typ != nil)
+ // caution: method may not have a proper signature yet
index = concat(e.index, i)
if obj != nil || e.multiples {
return nil, index, false // collision
@@ -248,6 +253,14 @@ func lookupType(m map[Type]int, typ Type) (int, bool) {
// x is of interface type V).
//
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+ return (*Checker)(nil).missingMethod(V, T, static)
+}
+
+// missingMethod is like MissingMethod but accepts a receiver.
+// The receiver may be nil if missingMethod is invoked through
+// an exported API call (such as MissingMethod), i.e., when all
+// methods have been type-checked.
+func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
// fast path for common case
if T.Empty() {
return
@@ -275,11 +288,17 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
for _, m := range T.allMethods {
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
+ // we must have a method (not a field of matching function type)
f, _ := obj.(*Func)
if f == nil {
return m, false
}
+ // methods may not have a fully set up signature yet
+ if check != nil {
+ check.objDecl(f, nil)
+ }
+
if !Identical(f.typ, m.typ) {
return m, true
}
@@ -291,14 +310,16 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
// assertableTo reports whether a value of type V can be asserted to have type T.
// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
// method required by V and whether it is missing or just has the wrong type.
-func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
+// The receiver may be nil if assertableTo is invoked through an exported API call
+// (such as AssertableTo), i.e., when all methods have been type-checked.
+func (check *Checker) assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
// no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T."
if _, ok := T.Underlying().(*Interface); ok && !strict {
return
}
- return MissingMethod(T, V, false)
+ return check.missingMethod(T, V, false)
}
// deref dereferences typ if it is a *Pointer and returns its base and true.
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index 07247bd6f5..97ca6c622f 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -201,7 +201,9 @@ func (x *operand) isNil() bool {
// assignableTo reports whether x is assignable to a variable of type T.
// If the result is false and a non-nil reason is provided, it may be set
// to a more detailed explanation of the failure (result != "").
-func (x *operand) assignableTo(conf *Config, T Type, reason *string) bool {
+// The check parameter may be nil if assignableTo is invoked through
+// an exported API call, i.e., when all methods have been type-checked.
+func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
if x.mode == invalid || T == Typ[Invalid] {
return true // avoid spurious errors
}
@@ -226,7 +228,7 @@ func (x *operand) assignableTo(conf *Config, T Type, reason *string) bool {
return true
}
if x.mode == constant_ {
- return representableConst(x.val, conf, t, nil)
+ return representableConst(x.val, check, t, nil)
}
// The result of a comparison is an untyped boolean,
// but may not be a constant.
@@ -249,7 +251,7 @@ func (x *operand) assignableTo(conf *Config, T Type, reason *string) bool {
// T is an interface type and x implements T
if Ti, ok := Tu.(*Interface); ok {
- if m, wrongType := MissingMethod(x.typ, Ti, true); m != nil /* Implements(x.typ, Ti) */ {
+ if m, wrongType := check.missingMethod(x.typ, Ti, true); m != nil /* Implements(x.typ, Ti) */ {
if reason != nil {
if wrongType {
*reason = "wrong type for method " + m.Name()
diff --git a/src/go/types/type.go b/src/go/types/type.go
index d9399a6587..74b6bcfd67 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -424,7 +424,7 @@ func (c *Chan) Elem() Type { return c.elem }
type Named struct {
obj *TypeName // corresponding declared object
underlying Type // possibly a *Named during setup; never a *Named once set up completely
- methods []*Func // methods declared for this type (not the method set of this type)
+ methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
}
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index bcdbc5906d..eb0d8e8fb9 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -391,7 +391,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
}
if isUntyped(x.typ) || isInteger(x.typ) {
if val := constant.ToInt(x.val); val.Kind() == constant.Int {
- if representableConst(val, check.conf, Typ[Int], nil) {
+ if representableConst(val, check, Typ[Int], nil) {
if n, ok := constant.Int64Val(val); ok && n >= 0 {
return n
}
From 8ae8576abf483cf928eb0f63bc55c09c7bf73576 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 4 Oct 2018 16:20:48 -0700
Subject: [PATCH 026/240] go/types: don't type-check method signatures eagerly
anymore
As a side-effect we also get slightly clearer errors for some
pathological cyclic method declarations.
Fixes #23203.
Updates #26854.
Change-Id: I30bd6634ac6be26d3f4ef8c7b32e5c1bf76987dd
Reviewed-on: https://go-review.googlesource.com/c/139897
Reviewed-by: Alan Donovan
---
src/go/types/check_test.go | 2 ++
src/go/types/decl.go | 14 +-------------
src/go/types/testdata/decls0.src | 8 ++++----
src/go/types/testdata/issue23203a.src | 14 ++++++++++++++
src/go/types/testdata/issue23203b.src | 14 ++++++++++++++
5 files changed, 35 insertions(+), 17 deletions(-)
create mode 100644 src/go/types/testdata/issue23203a.src
create mode 100644 src/go/types/testdata/issue23203b.src
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index 2bdfc150f4..e8ba1a037c 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -92,6 +92,8 @@ var tests = [][]string{
{"testdata/blank.src"},
{"testdata/issue25008b.src", "testdata/issue25008a.src"}, // order (b before a) is crucial!
{"testdata/issue26390.src"}, // stand-alone test to ensure case is triggered
+ {"testdata/issue23203a.src"},
+ {"testdata/issue23203b.src"},
}
var fset = token.NewFileSet()
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index b4a1eec1ac..5a6eda8ee4 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -515,11 +515,6 @@ func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bo
}
- // check and add associated methods
- // TODO(gri) It's easy to create pathological cases where the
- // current approach is incorrect: In general we need to know
- // and add all methods _before_ type-checking the type.
- // See https://play.golang.org/p/WMpE0q2wK8
check.addMethodDecls(obj)
}
@@ -567,7 +562,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
check.push(cutCycle)
defer check.pop()
- // type-check methods
+ // add valid methods
for _, m := range methods {
// spec: "For a base type, the non-blank names of methods bound
// to it must be unique."
@@ -585,13 +580,6 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
continue
}
- // type-check
- // TODO(gri): This call is not needed anymore because the code can handle
- // method signatures that have not yet been type-checked.
- // Remove in separate CL to make it easy to isolate issues
- // that might be introduced by this change.
- check.objDecl(m, nil)
-
if base != nil {
base.methods = append(base.methods, m)
}
diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src
index e75216172b..56adbbfaae 100644
--- a/src/go/types/testdata/decls0.src
+++ b/src/go/types/testdata/decls0.src
@@ -189,10 +189,10 @@ func f2(x *f2 /* ERROR "not a type" */ ) {}
func f3() (x f3 /* ERROR "not a type" */ ) { return }
func f4() (x *f4 /* ERROR "not a type" */ ) { return }
-func (S0) m1(x S0.m1 /* ERROR "field or method" */ ) {}
-func (S0) m2(x *S0.m2 /* ERROR "field or method" */ ) {}
-func (S0) m3() (x S0.m3 /* ERROR "field or method" */ ) { return }
-func (S0) m4() (x *S0.m4 /* ERROR "field or method" */ ) { return }
+func (S0) m1 /* ERROR illegal cycle */ (x S0 /* ERROR value .* is not a type */ .m1) {}
+func (S0) m2 /* ERROR illegal cycle */ (x *S0 /* ERROR value .* is not a type */ .m2) {}
+func (S0) m3 /* ERROR illegal cycle */ () (x S0 /* ERROR value .* is not a type */ .m3) { return }
+func (S0) m4 /* ERROR illegal cycle */ () (x *S0 /* ERROR value .* is not a type */ .m4) { return }
// interfaces may not have any blank methods
type BlankI interface {
diff --git a/src/go/types/testdata/issue23203a.src b/src/go/types/testdata/issue23203a.src
new file mode 100644
index 0000000000..48cb5889cd
--- /dev/null
+++ b/src/go/types/testdata/issue23203a.src
@@ -0,0 +1,14 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m1() {}
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+
+func main() {}
diff --git a/src/go/types/testdata/issue23203b.src b/src/go/types/testdata/issue23203b.src
new file mode 100644
index 0000000000..638ec6c5ce
--- /dev/null
+++ b/src/go/types/testdata/issue23203b.src
@@ -0,0 +1,14 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+func (T) m1() {}
+
+func main() {}
From 6d51dd1e85bbed9f59023a468c4cbbeed598608f Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 4 Oct 2018 16:43:34 -0700
Subject: [PATCH 027/240] go/types: remove work-around for issue #26124
This work-around is not needed anymore now that method
signatures are type-checked separately from their receiver
base types: no artificial cycles are introduced anymore
and so there is no need to artificially cut them.
Updates #26124.
Change-Id: I9d50171f12dd8977116a5d3f63ac39a06b1cd492
Reviewed-on: https://go-review.googlesource.com/c/139899
Reviewed-by: Alan Donovan
---
src/go/types/decl.go | 26 ++------------------------
1 file changed, 2 insertions(+), 24 deletions(-)
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 5a6eda8ee4..3d8054de23 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -245,14 +245,6 @@ func (check *Checker) objDecl(obj Object, def *Named) {
// Indirections are used to break type cycles.
var indir = NewTypeName(token.NoPos, nil, "*", nil)
-// cutCycle is a sentinel type name that is pushed onto the object path
-// to indicate that a cycle doesn't actually exist. This is currently
-// needed to break cycles formed via method declarations because they
-// are type-checked together with their receiver base types. Once methods
-// are type-checked separately (see also TODO in Checker.typeDecl), we
-// can get rid of this.
-var cutCycle = NewTypeName(token.NoPos, nil, "!", nil)
-
// typeCycle checks if the cycle starting with obj is valid and
// reports an error if it is not.
// TODO(gri) rename s/typeCycle/cycle/ once we don't need the other
@@ -293,16 +285,10 @@ func (check *Checker) typeCycle(obj Object) (isCycle bool) {
case *Const, *Var:
nval++
case *TypeName:
- switch {
- case obj == indir:
+ if obj == indir {
ncycle-- // don't count (indirections are not objects)
hasIndir = true
- case obj == cutCycle:
- // The cycle is not real and only caused by the fact
- // that we type-check methods when we type-check their
- // receiver base types.
- return false
- default:
+ } else {
// Determine if the type name is an alias or not. For
// package-level objects, use the object map which
// provides syntactic information (which doesn't rely
@@ -554,14 +540,6 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
}
}
- // Suppress detection of type cycles occurring through method
- // declarations - they wouldn't exist if methods were type-
- // checked separately from their receiver base types. See also
- // comment at the end of Checker.typeDecl.
- // TODO(gri) Remove this once methods are type-checked separately.
- check.push(cutCycle)
- defer check.pop()
-
// add valid methods
for _, m := range methods {
// spec: "For a base type, the non-blank names of methods bound
From 71d40c492fa92e710f9a3b2f26881a86f877ae95 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 4 Oct 2018 17:16:33 -0700
Subject: [PATCH 028/240] go/types: remove work-around for issue #26390
This work-around is not needed anymore now that method
signatures are type-checked separately from their receiver
base types: no artificial cycles are introduced anymore
and so there is no need to artificially cut them.
Fixes #26854.
Change-Id: I2ef15ceeaa0b486f65f6cdc466d0cf06246c74d7
Reviewed-on: https://go-review.googlesource.com/c/139900
Reviewed-by: Alan Donovan
---
src/go/types/decl.go | 25 -------------------------
1 file changed, 25 deletions(-)
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 3d8054de23..1e2790a171 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -150,31 +150,6 @@ func (check *Checker) objDecl(obj Object, def *Named) {
}
case *TypeName:
- // fixFor26390 enables a temporary work-around to handle alias type names
- // that have not been given a type yet even though the underlying type
- // is already known. See testdata/issue26390.src for a simple example.
- // Set this flag to false to disable this code quickly (and comment
- // out the new test in decls4.src that will fail again).
- // TODO(gri) remove this for Go 1.12 in favor of a more comprehensive fix
- const fixFor26390 = true
- if fixFor26390 {
- // If we have a package-level alias type name that has not been
- // given a type yet but the underlying type is a type name that
- // has been given a type already, don't report a cycle but use
- // the underlying type name's type instead. The cycle shouldn't
- // exist in the first place in this case and is due to the way
- // methods are type-checked at the moment. See also the comment
- // at the end of Checker.typeDecl below.
- if d := check.objMap[obj]; d != nil && d.alias && obj.typ == Typ[Invalid] {
- // If we can find the underlying type name syntactically
- // and it has a type, use that type.
- if tname := check.resolveBaseTypeName(ast.NewIdent(obj.name)); tname != nil && tname.typ != nil {
- obj.typ = tname.typ
- break
- }
- }
- }
-
if check.typeCycle(obj) {
// break cycle
// (without this, calling underlying()
From 497fd2c09ca4ed1d9f9d397aed71fce741e3588a Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 4 Oct 2018 17:30:42 -0700
Subject: [PATCH 029/240] go/types: remove a TODO, enable a test
1) Scopes do have a comment field for documentation (debugging output).
No need to do anything extra.
2) The testcase in expr3.src has ok error messages. Enabled.
Change-Id: Ic1a03bfec0a6a70d876aa6cfb936973abe58fe6c
Reviewed-on: https://go-review.googlesource.com/c/139902
Reviewed-by: Alan Donovan
---
src/go/types/scope.go | 3 ---
src/go/types/testdata/expr3.src | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/go/types/scope.go b/src/go/types/scope.go
index 839a60db2e..6cf5cc66f9 100644
--- a/src/go/types/scope.go
+++ b/src/go/types/scope.go
@@ -15,9 +15,6 @@ import (
"strings"
)
-// TODO(gri) Provide scopes with a name or other mechanism so that
-// objects can use that information for better printing.
-
// A Scope maintains a set of objects and links to its containing
// (parent) and contained (children) scopes. Objects may be inserted
// and looked up by name. The zero value for Scope is a ready-to-use
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index b4c8163324..d562f0b16b 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -497,7 +497,7 @@ func _calls() {
f1(x ... /* ERROR "cannot use ..." */ )
f1(g0 /* ERROR "used as value" */ ())
f1(g1())
- // f1(g2()) // TODO(gri) missing position in error message
+ f1(g2 /* ERROR "cannot use g2" */ /* ERROR "too many arguments" */ ())
f2() /* ERROR "too few arguments" */
f2(3.14) /* ERROR "too few arguments" */
From 68d52969ddbfc8f90900f781d35201bea7b7869c Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 5 Oct 2018 16:47:33 +0200
Subject: [PATCH 030/240] runtime: remove unused armArch
runtime.armArch is unused on linux/arm since CL 93637. The new code in
runtime/internal/atomic (added by CL 111315) only checks runtime.goarm.
Change-Id: Ic097ee6750e39abb20f45770a1c7c2d925f02408
Reviewed-on: https://go-review.googlesource.com/c/140077
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/os_linux_arm.go | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
index 8f082ba6a0..207b0e4d4d 100644
--- a/src/runtime/os_linux_arm.go
+++ b/src/runtime/os_linux_arm.go
@@ -4,20 +4,14 @@
package runtime
-import (
- "internal/cpu"
- "unsafe"
-)
+import "internal/cpu"
const (
- _AT_PLATFORM = 15 // introduced in at least 2.6.11
-
_HWCAP_VFP = 1 << 6 // introduced in at least 2.6.11
_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
)
var randomNumber uint32
-var armArch uint8 = 6 // we default to ARMv6
func checkgoarm() {
// On Android, /proc/self/auxv might be unreadable and hwcap won't
@@ -47,12 +41,6 @@ func archauxv(tag, val uintptr) {
randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 |
uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24
- case _AT_PLATFORM: // v5l, v6l, v7l
- t := *(*uint8)(unsafe.Pointer(val + 1))
- if '5' <= t && t <= '7' {
- armArch = t - '0'
- }
-
case _AT_HWCAP:
cpu.HWCap = uint(val)
case _AT_HWCAP2:
From 3d19d95932e2d864c5b9a71f9c78ef5c8b2eafbe Mon Sep 17 00:00:00 2001
From: Jordan Rhee
Date: Fri, 5 Oct 2018 13:12:18 -0700
Subject: [PATCH 031/240] debug/pe: fix TestDWARF to work with relocations
Fixes #27904
Change-Id: Ie2aad20cd66785b6cc1018c0048824382cb39f8c
Reviewed-on: https://go-review.googlesource.com/c/140158
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/debug/pe/file_test.go | 77 ++++++++++++++++++++++++++++++++++++---
1 file changed, 71 insertions(+), 6 deletions(-)
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index c65c82d342..4f0510200f 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -298,6 +298,17 @@ const (
linkCgoExternal
)
+func getImageBase(f *File) uintptr {
+ switch oh := f.OptionalHeader.(type) {
+ case *OptionalHeader32:
+ return uintptr(oh.ImageBase)
+ case *OptionalHeader64:
+ return uintptr(oh.ImageBase)
+ default:
+ panic("unexpected optionalheader type")
+ }
+}
+
func testDWARF(t *testing.T, linktype int) {
if runtime.GOOS != "windows" {
t.Skip("skipping windows only test")
@@ -347,14 +358,15 @@ func testDWARF(t *testing.T, linktype int) {
if err != nil {
t.Fatalf("running test executable failed: %s %s", err, out)
}
+ t.Logf("Testprog output:\n%s", string(out))
- matches := regexp.MustCompile("main=(.*)\n").FindStringSubmatch(string(out))
+ matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out))
if len(matches) < 2 {
t.Fatalf("unexpected program output: %s", out)
}
- wantaddr, err := strconv.ParseUint(matches[1], 0, 64)
+ wantoffset, err := strconv.ParseUint(matches[1], 0, 64)
if err != nil {
- t.Fatalf("unexpected main address %q: %s", matches[1], err)
+ t.Fatalf("unexpected main offset %q: %s", matches[1], err)
}
f, err := Open(exe)
@@ -363,6 +375,8 @@ func testDWARF(t *testing.T, linktype int) {
}
defer f.Close()
+ imageBase := getImageBase(f)
+
var foundDebugGDBScriptsSection bool
for _, sect := range f.Sections {
if sect.Name == ".debug_gdb_scripts" {
@@ -389,10 +403,20 @@ func testDWARF(t *testing.T, linktype int) {
break
}
if e.Tag == dwarf.TagSubprogram {
- if name, ok := e.Val(dwarf.AttrName).(string); ok && name == "main.main" {
- if addr, ok := e.Val(dwarf.AttrLowpc).(uint64); ok && addr == wantaddr {
- return
+ name, ok := e.Val(dwarf.AttrName).(string)
+ if ok && name == "main.main" {
+ t.Logf("Found main.main")
+ addr, ok := e.Val(dwarf.AttrLowpc).(uint64)
+ if !ok {
+ t.Fatal("Failed to get AttrLowpc")
}
+ offset := uintptr(addr) - imageBase
+ if offset != uintptr(wantoffset) {
+ t.Fatal("Runtime offset (0x%x) did "+
+ "not match dwarf offset "+
+ "(0x%x)", wantoffset, offset)
+ }
+ return
}
}
}
@@ -479,11 +503,52 @@ const testprog = `
package main
import "fmt"
+import "syscall"
+import "unsafe"
{{if .}}import "C"
{{end}}
+// struct MODULEINFO from the Windows SDK
+type moduleinfo struct {
+ BaseOfDll uintptr
+ SizeOfImage uint32
+ EntryPoint uintptr
+}
+
+func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(p) + x)
+}
+
+func funcPC(f interface{}) uintptr {
+ var a uintptr
+ return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
+}
+
func main() {
+ kernel32 := syscall.MustLoadDLL("kernel32.dll")
+ psapi := syscall.MustLoadDLL("psapi.dll")
+ getModuleHandle := kernel32.MustFindProc("GetModuleHandleW")
+ getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
+ getModuleInformation := psapi.MustFindProc("GetModuleInformation")
+
+ procHandle, _, _ := getCurrentProcess.Call()
+ moduleHandle, _, err := getModuleHandle.Call(0)
+ if moduleHandle == 0 {
+ panic(fmt.Sprintf("GetModuleHandle() failed: %d", err))
+ }
+
+ var info moduleinfo
+ ret, _, err := getModuleInformation.Call(procHandle, moduleHandle,
+ uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info))
+
+ if ret == 0 {
+ panic(fmt.Sprintf("GetModuleInformation() failed: %d", err))
+ }
+
+ offset := funcPC(main) - info.BaseOfDll
+ fmt.Printf("base=0x%x\n", info.BaseOfDll)
fmt.Printf("main=%p\n", main)
+ fmt.Printf("offset=0x%x\n", offset)
}
`
From dc6eb200dd59dfedaa5259565b8ef1aa96a39271 Mon Sep 17 00:00:00 2001
From: Yuval Pavel Zholkover
Date: Sat, 29 Sep 2018 18:17:29 +0300
Subject: [PATCH 032/240] syscall: FreeBSD 12 ino64 support
This is similar to CL 136816 for x/sys/unix, changing the FreeBSD ABI to use 64-bit inodes in
Stat_t, Statfs_t, and Dirent types.
The changes are forward compatible, that is FreeBSD 10.x, 11.x continue to use their current sysnum numbers.
The affected types are converted to the new layout (with some overhead).
Thus the same statically linked binary should work using the native sysnums (without any conversion) on FreeBSD 12.
Breaking API changes in package syscall are:
Mknod takes a uint64 (C dev_t) instead of int.
Stat_t: Dev, Ino, Nlink, Rdev, Gen became uint64.
Atimespec, Mtimespec, Ctimespec, Birthtimespec renamed to Atim, Mtim, Ctim, Birthtim respectively.
Statfs_t: Mntonname and Mntfromname changed from [88]int8 to [1024]int8 arrays.
Dirent: Fileno became uint64, Namlen uint16 and an additional field Off int64 (currently unused) was added.
The following commands were run to generate ztypes_* and zsyscall_* on FreeBSD-12.0-ALPHA6 systems (GOARCH=386 were run on the same amd64 host):
GOOS=freebsd GOARCH=amd64 ./mksyscall.pl -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go |gofmt >zsyscall_freebsd_amd64.go
GOOS=freebsd GOARCH=amd64 go tool cgo -godefs types_freebsd.go | GOOS=freebsd GOARCH=amd64 go run mkpost.go >ztypes_freebsd_amd64.go
GOOS=freebsd GOARCH=386 ./mksyscall.pl -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go |gofmt >zsyscall_freebsd_386.go
GOOS=freebsd GOARCH=386 go tool cgo -godefs types_freebsd.go | GOOS=freebsd GOARCH=386 go run mkpost.go >ztypes_freebsd_386.go
GOOS=freebsd GOARCH=arm ./mksyscall.pl -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go |gofmt >zsyscall_freebsd_arm.go
GOOS=freebsd GOARCH=arm go tool cgo -godefs -- -fsigned-char types_freebsd.go | GOOS=freebsd GOARCH=arm go run mkpost.go >ztypes_freebsd_arm.go
The Kevent struct was changed to use the FREEBSD_COMPAT11 version always (requiring the COMPAT_FREEBSD11 kernel option FreeBSD-12, this is the default).
The definitions of ifData were not updated, their functionality in has have been replaced by vendored golang.org/x/net/route.
freebsdVersion initialization was dropped from init() in favor of a sync.Once based wrapper - supportsABI().
Updates #22448.
Change-Id: I359b756e2849c036d7ed7f75dbd6ec836e0b90b4
Reviewed-on: https://go-review.googlesource.com/c/138595
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
api/except.txt | 98 +++++++++
src/archive/tar/stat_actime1.go | 2 +-
src/archive/tar/stat_actime2.go | 2 +-
src/os/stat_freebsd.go | 4 +-
src/runtime/defs_freebsd.go | 3 +-
src/syscall/route_freebsd.go | 4 -
src/syscall/route_freebsd_32bit.go | 2 +-
src/syscall/syscall_freebsd.go | 281 ++++++++++++++++++++++++--
src/syscall/types_freebsd.go | 72 +++----
src/syscall/zsyscall_freebsd_386.go | 96 ++++++++-
src/syscall/zsyscall_freebsd_amd64.go | 96 ++++++++-
src/syscall/zsyscall_freebsd_arm.go | 96 ++++++++-
src/syscall/ztypes_freebsd_386.go | 111 ++++++++--
src/syscall/ztypes_freebsd_amd64.go | 105 ++++++++--
src/syscall/ztypes_freebsd_arm.go | 103 ++++++++--
15 files changed, 923 insertions(+), 152 deletions(-)
diff --git a/api/except.txt b/api/except.txt
index 90b79f1592..a911783c6b 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -383,3 +383,101 @@ pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
+pkg syscall (freebsd-386), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-386), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-386), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-386), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-386), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-386), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-386), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-386), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-386), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-386), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-386), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8
+pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8
+pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8
+pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8
+pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-amd64), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-amd64), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-amd64), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-amd64), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8
+pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8
+pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-arm), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-arm), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-arm), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-arm), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8
+pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error
+pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32
+pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Atimespec Timespec
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Birthtimespec Timespec
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ctimespec Timespec
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Mtimespec Timespec
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
+pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
+pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
diff --git a/src/archive/tar/stat_actime1.go b/src/archive/tar/stat_actime1.go
index cf9cc79c59..eb82edb6d9 100644
--- a/src/archive/tar/stat_actime1.go
+++ b/src/archive/tar/stat_actime1.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux dragonfly openbsd solaris
+// +build linux dragonfly freebsd openbsd solaris
package tar
diff --git a/src/archive/tar/stat_actime2.go b/src/archive/tar/stat_actime2.go
index 6f17dbe307..f707012714 100644
--- a/src/archive/tar/stat_actime2.go
+++ b/src/archive/tar/stat_actime2.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin freebsd netbsd
+// +build darwin netbsd
package tar
diff --git a/src/os/stat_freebsd.go b/src/os/stat_freebsd.go
index bab4ffa798..d36afa9ffd 100644
--- a/src/os/stat_freebsd.go
+++ b/src/os/stat_freebsd.go
@@ -12,7 +12,7 @@ import (
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
fs.size = fs.sys.Size
- fs.modTime = timespecToTime(fs.sys.Mtimespec)
+ fs.modTime = timespecToTime(fs.sys.Mtim)
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
case syscall.S_IFBLK:
@@ -47,5 +47,5 @@ func timespecToTime(ts syscall.Timespec) time.Time {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.Sys().(*syscall.Stat_t).Atimespec)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
diff --git a/src/runtime/defs_freebsd.go b/src/runtime/defs_freebsd.go
index 29a6ec20a5..53c1508eb7 100644
--- a/src/runtime/defs_freebsd.go
+++ b/src/runtime/defs_freebsd.go
@@ -19,6 +19,7 @@ package runtime
#include
#include
#include
+#define _WANT_FREEBSD11_KEVENT 1
#include
#include
#include
@@ -149,7 +150,7 @@ type Itimerval C.struct_itimerval
type Umtx_time C.struct__umtx_time
-type Kevent C.struct_kevent
+type Kevent C.struct_kevent_freebsd11
type bintime C.struct_bintime
type vdsoTimehands C.struct_vdso_timehands
diff --git a/src/syscall/route_freebsd.go b/src/syscall/route_freebsd.go
index 2c2de7474a..2b47faff42 100644
--- a/src/syscall/route_freebsd.go
+++ b/src/syscall/route_freebsd.go
@@ -6,11 +6,7 @@ package syscall
import "unsafe"
-// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
-var freebsdVersion uint32
-
func init() {
- freebsdVersion, _ = SysctlUint32("kern.osreldate")
conf, _ := Sysctl("kern.conftxt")
for i, j := 0, 0; j < len(conf); j++ {
if conf[j] != '\n' {
diff --git a/src/syscall/route_freebsd_32bit.go b/src/syscall/route_freebsd_32bit.go
index ec6f6b7f8b..aed8682237 100644
--- a/src/syscall/route_freebsd_32bit.go
+++ b/src/syscall/route_freebsd_32bit.go
@@ -22,7 +22,7 @@ func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
// FreeBSD 10 and beyond have a restructured mbuf
// packet header view.
// See https://svnweb.freebsd.org/base?view=revision&revision=254804.
- if freebsdVersion >= 1000000 {
+ if supportsABI(1000000) {
m := (*ifMsghdr)(unsafe.Pointer(any))
p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
p.Header.Data.Epoch = m.Data.Epoch
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index d5738ba1c1..e118120048 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -12,7 +12,34 @@
package syscall
-import "unsafe"
+import (
+ "sync"
+ "unsafe"
+)
+
+const (
+ _SYS_FSTAT_FREEBSD12 = 551 // { int fstat(int fd, _Out_ struct stat *sb); }
+ _SYS_FSTATAT_FREEBSD12 = 552 // { int fstatat(int fd, _In_z_ char *path, \
+ _SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, \
+ _SYS_STATFS_FREEBSD12 = 555 // { int statfs(_In_z_ char *path, \
+ _SYS_FSTATFS_FREEBSD12 = 556 // { int fstatfs(int fd, \
+ _SYS_GETFSSTAT_FREEBSD12 = 557 // { int getfsstat( \
+ _SYS_MKNODAT_FREEBSD12 = 559 // { int mknodat(int fd, _In_z_ char *path, \
+)
+
+// See https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html.
+var (
+ osreldateOnce sync.Once
+ osreldate uint32
+)
+
+// INO64_FIRST from /usr/src/lib/libc/sys/compat-ino64.h
+const _ino64First = 1200031
+
+func supportsABI(ver uint32) bool {
+ osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
+ return osreldate >= ver
+}
type SockaddrDatalink struct {
Len uint8
@@ -113,17 +140,39 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
}
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- var bufsize uintptr
+ var (
+ _p0 unsafe.Pointer
+ bufsize uintptr
+ oldBuf []statfs_freebsd11_t
+ needsConvert bool
+ )
+
if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ if supportsABI(_ino64First) {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ } else {
+ n := len(buf)
+ oldBuf = make([]statfs_freebsd11_t, n)
+ _p0 = unsafe.Pointer(&oldBuf[0])
+ bufsize = unsafe.Sizeof(statfs_freebsd11_t{}) * uintptr(n)
+ needsConvert = true
+ }
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ var sysno uintptr = SYS_GETFSSTAT
+ if supportsABI(_ino64First) {
+ sysno = _SYS_GETFSSTAT_FREEBSD12
+ }
+ r0, _, e1 := Syscall(sysno, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
+ if e1 == 0 && needsConvert {
+ for i := range oldBuf {
+ buf[i].convertFrom(&oldBuf[i])
+ }
+ }
return
}
@@ -132,6 +181,206 @@ func setattrlistTimes(path string, times []Timespec) error {
return ENOSYS
}
+func Stat(path string, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatat_freebsd12(_AT_FDCWD, path, st, 0)
+ }
+ err = stat(path, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
+}
+
+func Lstat(path string, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatat_freebsd12(_AT_FDCWD, path, st, _AT_SYMLINK_NOFOLLOW)
+ }
+ err = lstat(path, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
+}
+
+func Fstat(fd int, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstat_freebsd12(fd, st)
+ }
+ err = fstat(fd, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
+}
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+ var oldStatfs statfs_freebsd11_t
+ if supportsABI(_ino64First) {
+ return statfs_freebsd12(path, stat)
+ }
+ err = statfs(path, &oldStatfs)
+ if err != nil {
+ return err
+ }
+
+ stat.convertFrom(&oldStatfs)
+ return nil
+}
+
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
+ var oldStatfs statfs_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatfs_freebsd12(fd, stat)
+ }
+ err = fstatfs(fd, &oldStatfs)
+ if err != nil {
+ return err
+ }
+
+ stat.convertFrom(&oldStatfs)
+ return nil
+}
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ if supportsABI(_ino64First) {
+ return getdirentries_freebsd12(fd, buf, basep)
+ }
+
+ // The old syscall entries are smaller than the new. Use 1/4 of the original
+ // buffer size rounded up to DIRBLKSIZ (see /usr/src/lib/libc/sys/getdirentries.c).
+ oldBufLen := roundup(len(buf)/4, _dirblksiz)
+ oldBuf := make([]byte, oldBufLen)
+ n, err = getdirentries(fd, oldBuf, basep)
+ if err == nil && n > 0 {
+ n = convertFromDirents11(oldBuf[:n], buf)
+ }
+ return
+}
+
+func Mknod(path string, mode uint32, dev uint64) (err error) {
+ var oldDev int
+ if supportsABI(_ino64First) {
+ return mknodat_freebsd12(_AT_FDCWD, path, mode, dev)
+ }
+ oldDev = int(dev)
+ return mknod(path, mode, oldDev)
+}
+
+// round x to the nearest multiple of y, larger or equal to x.
+//
+// from /usr/include/sys/param.h Macros for counting and rounding.
+// #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+func roundup(x, y int) int {
+ return ((x + y - 1) / y) * y
+}
+
+func (s *Stat_t) convertFrom(old *stat_freebsd11_t) {
+ *s = Stat_t{
+ Dev: uint64(old.Dev),
+ Ino: uint64(old.Ino),
+ Nlink: uint64(old.Nlink),
+ Mode: old.Mode,
+ Uid: old.Uid,
+ Gid: old.Gid,
+ Rdev: uint64(old.Rdev),
+ Atim: old.Atim,
+ Mtim: old.Mtim,
+ Ctim: old.Ctim,
+ Birthtim: old.Birthtim,
+ Size: old.Size,
+ Blocks: old.Blocks,
+ Blksize: old.Blksize,
+ Flags: old.Flags,
+ Gen: uint64(old.Gen),
+ }
+}
+
+func (s *Statfs_t) convertFrom(old *statfs_freebsd11_t) {
+ *s = Statfs_t{
+ Version: _statfsVersion,
+ Type: old.Type,
+ Flags: old.Flags,
+ Bsize: old.Bsize,
+ Iosize: old.Iosize,
+ Blocks: old.Blocks,
+ Bfree: old.Bfree,
+ Bavail: old.Bavail,
+ Files: old.Files,
+ Ffree: old.Ffree,
+ Syncwrites: old.Syncwrites,
+ Asyncwrites: old.Asyncwrites,
+ Syncreads: old.Syncreads,
+ Asyncreads: old.Asyncreads,
+ // Spare
+ Namemax: old.Namemax,
+ Owner: old.Owner,
+ Fsid: old.Fsid,
+ // Charspare
+ // Fstypename
+ // Mntfromname
+ // Mntonname
+ }
+
+ sl := old.Fstypename[:]
+ n := clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Fstypename[:], old.Fstypename[:n])
+
+ sl = old.Mntfromname[:]
+ n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Mntfromname[:], old.Mntfromname[:n])
+
+ sl = old.Mntonname[:]
+ n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Mntonname[:], old.Mntonname[:n])
+}
+
+func convertFromDirents11(oldBuf []byte, buf []byte) int {
+ src := unsafe.Pointer(&oldBuf[0])
+ esrc := unsafe.Pointer(uintptr(src) + uintptr(len(oldBuf)))
+ dst := unsafe.Pointer(&buf[0])
+ edst := unsafe.Pointer(uintptr(dst) + uintptr(len(buf)))
+
+ for uintptr(src) < uintptr(esrc) && uintptr(dst) < uintptr(edst) {
+ srcDirent := (*dirent_freebsd11)(src)
+ dstDirent := (*Dirent)(dst)
+
+ reclen := roundup(int(unsafe.Offsetof(dstDirent.Name)+uintptr(srcDirent.Namlen)+1), 8)
+ if uintptr(dst)+uintptr(reclen) >= uintptr(edst) {
+ break
+ }
+
+ dstDirent.Fileno = uint64(srcDirent.Fileno)
+ dstDirent.Off = 0
+ dstDirent.Reclen = uint16(reclen)
+ dstDirent.Type = srcDirent.Type
+ dstDirent.Pad0 = 0
+ dstDirent.Namlen = uint16(srcDirent.Namlen)
+ dstDirent.Pad1 = 0
+
+ sl := srcDirent.Name[:]
+ n := clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(dstDirent.Name[:], srcDirent.Name[:n])
+ for i := n; i < int(dstDirent.Namlen); i++ {
+ dstDirent.Name[i] = 0
+ }
+
+ src = unsafe.Pointer(uintptr(src) + uintptr(srcDirent.Reclen))
+ dst = unsafe.Pointer(uintptr(dst) + uintptr(reclen))
+ }
+
+ return int(uintptr(dst) - uintptr(unsafe.Pointer((&buf[0]))))
+}
+
/*
* Exposed directly
*/
@@ -151,11 +400,15 @@ func setattrlistTimes(path string, times []Timespec) error {
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
-//sys Fstat(fd int, stat *Stat_t) (err error)
-//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys fstat(fd int, stat *stat_freebsd11_t) (err error)
+//sys fstat_freebsd12(fd int, stat *Stat_t) (err error) = _SYS_FSTAT_FREEBSD12
+//sys fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) = _SYS_FSTATAT_FREEBSD12
+//sys fstatfs(fd int, stat *statfs_freebsd11_t) (err error)
+//sys fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) = _SYS_FSTATFS_FREEBSD12
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sys getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) = _SYS_GETDIRENTRIES_FREEBSD12
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
@@ -176,10 +429,11 @@ func setattrlistTimes(path string, times []Timespec) error {
//sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error)
//sys Listen(s int, backlog int) (err error)
-//sys Lstat(path string, stat *Stat_t) (err error)
+//sys lstat(path string, stat *stat_freebsd11_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
-//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys mknod(path string, mode uint32, dev int) (err error)
+//sys mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) = _SYS_MKNODAT_FREEBSD12
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
@@ -204,8 +458,9 @@ func setattrlistTimes(path string, times []Timespec) error {
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
-//sys Stat(path string, stat *Stat_t) (err error)
-//sys Statfs(path string, stat *Statfs_t) (err error)
+//sys stat(path string, stat *stat_freebsd11_t) (err error)
+//sys statfs(path string, stat *statfs_freebsd11_t) (err error)
+//sys statfs_freebsd12(path string, stat *Statfs_t) (err error) = _SYS_STATFS_FREEBSD12
//sys Symlink(path string, link string) (err error)
//sys Sync() (err error)
//sys Truncate(path string, length int64) (err error)
diff --git a/src/syscall/types_freebsd.go b/src/syscall/types_freebsd.go
index 066a4acbd7..f686021121 100644
--- a/src/syscall/types_freebsd.go
+++ b/src/syscall/types_freebsd.go
@@ -14,7 +14,11 @@ Input to cgo -godefs. See also mkerrors.sh and mkall.sh
package syscall
/*
-#define KERNEL
+#define _WANT_FREEBSD11_STAT 1
+#define _WANT_FREEBSD11_STATFS 1
+#define _WANT_FREEBSD11_DIRENT 1
+#define _WANT_FREEBSD11_KEVENT 1
+
#include
#include
#include
@@ -60,50 +64,6 @@ struct sockaddr_any {
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
-// This structure is a duplicate of stat on FreeBSD 8-STABLE.
-// See /usr/include/sys/stat.h.
-struct stat8 {
-#undef st_atimespec st_atim
-#undef st_mtimespec st_mtim
-#undef st_ctimespec st_ctim
-#undef st_birthtimespec st_birthtim
- __dev_t st_dev;
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- __dev_t st_rdev;
-#if __BSD_VISIBLE
- struct timespec st_atimespec;
- struct timespec st_mtimespec;
- struct timespec st_ctimespec;
-#else
- time_t st_atime;
- long __st_atimensec;
- time_t st_mtime;
- long __st_mtimensec;
- time_t st_ctime;
- long __st_ctimensec;
-#endif
- off_t st_size;
- blkcnt_t st_blocks;
- blksize_t st_blksize;
- fflags_t st_flags;
- __uint32_t st_gen;
- __int32_t st_lspare;
-#if __BSD_VISIBLE
- struct timespec st_birthtimespec;
- unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
- unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
-#else
- time_t st_birthtime;
- long st_birthtimensec;
- unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
- unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
-#endif
-};
-
// This structure is a duplicate of if_data on FreeBSD 8-STABLE.
// See /usr/include/net/if.h.
struct if_data8 {
@@ -130,7 +90,10 @@ struct if_data8 {
u_long ifi_iqdrops;
u_long ifi_noproto;
u_long ifi_hwassist;
+// FIXME: these are now unions, so maybe need to change definitions?
+#undef ifi_epoch
time_t ifi_epoch;
+#undef ifi_lastchange
struct timeval ifi_lastchange;
};
@@ -202,14 +165,25 @@ const ( // Directory mode bits
S_IRWXO = C.S_IRWXO
)
-type Stat_t C.struct_stat8
+const (
+ _statfsVersion = C.STATFS_VERSION
+ _dirblksiz = C.DIRBLKSIZ
+)
+
+type Stat_t C.struct_stat
+
+type stat_freebsd11_t C.struct_freebsd11_stat
type Statfs_t C.struct_statfs
+type statfs_freebsd11_t C.struct_freebsd11_statfs
+
type Flock_t C.struct_flock
type Dirent C.struct_dirent
+type dirent_freebsd11 C.struct_freebsd11_dirent
+
type Fsid C.struct_fsid
// File system limits
@@ -281,7 +255,7 @@ const (
// Events (kqueue, kevent)
-type Kevent_t C.struct_kevent
+type Kevent_t C.struct_kevent_freebsd11
// Select
@@ -348,7 +322,9 @@ type BpfZbufHeader C.struct_bpf_zbuf_header
// Misc
const (
- _AT_FDCWD = C.AT_FDCWD
+ _AT_FDCWD = C.AT_FDCWD
+ _AT_SYMLINK_FOLLOW = C.AT_SYMLINK_FOLLOW
+ _AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
)
// Terminal handling
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 451da4d6fe..ba7ea27f8d 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -463,7 +463,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (err error) {
+func fstat(fd int, stat *stat_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -473,7 +473,32 @@ func Fstat(fd int, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (err error) {
+func fstat_freebsd12(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -483,6 +508,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
if e1 != 0 {
@@ -503,7 +538,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,6 +555,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
@@ -721,7 +773,7 @@ func Listen(s int, backlog int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (err error) {
+func lstat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -766,7 +818,7 @@ func Mkfifo(path string, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (err error) {
+func mknod(path string, mode uint32, dev int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -781,6 +833,21 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {
@@ -1093,7 +1160,7 @@ func Setuid(uid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (err error) {
+func stat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1108,7 +1175,7 @@ func Stat(path string, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (err error) {
+func statfs(path string, stat *statfs_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1123,6 +1190,21 @@ func Statfs(path string, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func statfs_freebsd12(path string, stat *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(_SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 0312ca347c..4b519a7f7f 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -463,7 +463,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (err error) {
+func fstat(fd int, stat *stat_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -473,7 +473,32 @@ func Fstat(fd int, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (err error) {
+func fstat_freebsd12(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -483,6 +508,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
if e1 != 0 {
@@ -503,7 +538,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,6 +555,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
@@ -721,7 +773,7 @@ func Listen(s int, backlog int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (err error) {
+func lstat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -766,7 +818,7 @@ func Mkfifo(path string, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (err error) {
+func mknod(path string, mode uint32, dev int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -781,6 +833,21 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {
@@ -1093,7 +1160,7 @@ func Setuid(uid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (err error) {
+func stat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1108,7 +1175,7 @@ func Stat(path string, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (err error) {
+func statfs(path string, stat *statfs_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1123,6 +1190,21 @@ func Statfs(path string, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func statfs_freebsd12(path string, stat *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(_SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index fcb0733774..e89707654b 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -463,7 +463,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (err error) {
+func fstat(fd int, stat *stat_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -473,7 +473,32 @@ func Fstat(fd int, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (err error) {
+func fstat_freebsd12(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_FSTATAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fstatfs(fd int, stat *statfs_freebsd11_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
@@ -483,6 +508,16 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func fstatfs_freebsd12(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(_SYS_FSTATFS_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
if e1 != 0 {
@@ -503,7 +538,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,6 +555,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES_FREEBSD12, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
@@ -721,7 +773,7 @@ func Listen(s int, backlog int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (err error) {
+func lstat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -766,7 +818,7 @@ func Mkfifo(path string, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (err error) {
+func mknod(path string, mode uint32, dev int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -781,6 +833,21 @@ func Mknod(path string, mode uint32, dev int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(_SYS_MKNODAT_FREEBSD12, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {
@@ -1093,7 +1160,7 @@ func Setuid(uid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (err error) {
+func stat(path string, stat *stat_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1108,7 +1175,7 @@ func Stat(path string, stat *Stat_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (err error) {
+func statfs(path string, stat *statfs_freebsd11_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -1123,6 +1190,21 @@ func Statfs(path string, stat *Statfs_t) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func statfs_freebsd12(path string, stat *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(_SYS_STATFS_FREEBSD12, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go
index 242a73d1de..3ca31f2872 100644
--- a/src/syscall/ztypes_freebsd_386.go
+++ b/src/syscall/ztypes_freebsd_386.go
@@ -1,5 +1,5 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_freebsd.go
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go | go run mkpost.go
// +build 386,freebsd
@@ -75,28 +75,84 @@ const (
S_IRWXO = 0x7
)
+const (
+ _statfsVersion = 0x20140518
+ _dirblksiz = 0x400
+)
+
type Stat_t struct {
- Dev uint32
- Ino uint32
- Mode uint16
- Nlink uint16
- Uid uint32
- Gid uint32
- Rdev uint32
- Atimespec Timespec
- Mtimespec Timespec
- Ctimespec Timespec
- Size int64
- Blocks int64
- Blksize uint32
- Flags uint32
- Gen uint32
- Lspare int32
- Birthtimespec Timespec
- Pad_cgo_0 [8]byte
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint16
+ Padding0 int16
+ Uid uint32
+ Gid uint32
+ Padding1 int32
+ Rdev uint64
+ Atim_ext int32
+ Atim Timespec
+ Mtim_ext int32
+ Mtim Timespec
+ Ctim_ext int32
+ Ctim Timespec
+ Btim_ext int32
+ Birthtim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint64
+ Spare [10]uint64
+}
+
+type stat_freebsd11_t struct {
+ Dev uint32
+ Ino uint32
+ Mode uint16
+ Nlink uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Birthtim Timespec
+ Pad_cgo_0 [8]byte
}
type Statfs_t struct {
+ Version uint32
+ Type uint32
+ Flags uint64
+ Bsize uint64
+ Iosize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail int64
+ Files uint64
+ Ffree int64
+ Syncwrites uint64
+ Asyncwrites uint64
+ Syncreads uint64
+ Asyncreads uint64
+ Spare [10]uint64
+ Namemax uint32
+ Owner uint32
+ Fsid Fsid
+ Charspare [80]int8
+ Fstypename [16]int8
+ Mntfromname [1024]int8
+ Mntonname [1024]int8
+}
+
+type statfs_freebsd11_t struct {
Version uint32
Type uint32
Flags uint64
@@ -131,6 +187,17 @@ type Flock_t struct {
}
type Dirent struct {
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Pad0 uint8
+ Namlen uint16
+ Pad1 uint16
+ Name [256]int8
+}
+
+type dirent_freebsd11 struct {
Fileno uint32
Reclen uint16
Type uint8
@@ -490,7 +557,9 @@ type BpfZbufHeader struct {
}
const (
- _AT_FDCWD = -0x64
+ _AT_FDCWD = -0x64
+ _AT_SYMLINK_FOLLOW = 0x400
+ _AT_SYMLINK_NOFOLLOW = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go
index 8b34cde2ee..797a3bab08 100644
--- a/src/syscall/ztypes_freebsd_amd64.go
+++ b/src/syscall/ztypes_freebsd_amd64.go
@@ -1,5 +1,5 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_freebsd.go
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go | go run mkpost.go
// +build amd64,freebsd
@@ -75,27 +75,79 @@ const (
S_IRWXO = 0x7
)
+const (
+ _statfsVersion = 0x20140518
+ _dirblksiz = 0x400
+)
+
type Stat_t struct {
- Dev uint32
- Ino uint32
- Mode uint16
- Nlink uint16
- Uid uint32
- Gid uint32
- Rdev uint32
- Atimespec Timespec
- Mtimespec Timespec
- Ctimespec Timespec
- Size int64
- Blocks int64
- Blksize uint32
- Flags uint32
- Gen uint32
- Lspare int32
- Birthtimespec Timespec
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint16
+ Padding0 int16
+ Uid uint32
+ Gid uint32
+ Padding1 int32
+ Rdev uint64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Birthtim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint64
+ Spare [10]uint64
+}
+
+type stat_freebsd11_t struct {
+ Dev uint32
+ Ino uint32
+ Mode uint16
+ Nlink uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Birthtim Timespec
}
type Statfs_t struct {
+ Version uint32
+ Type uint32
+ Flags uint64
+ Bsize uint64
+ Iosize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail int64
+ Files uint64
+ Ffree int64
+ Syncwrites uint64
+ Asyncwrites uint64
+ Syncreads uint64
+ Asyncreads uint64
+ Spare [10]uint64
+ Namemax uint32
+ Owner uint32
+ Fsid Fsid
+ Charspare [80]int8
+ Fstypename [16]int8
+ Mntfromname [1024]int8
+ Mntonname [1024]int8
+}
+
+type statfs_freebsd11_t struct {
Version uint32
Type uint32
Flags uint64
@@ -131,6 +183,17 @@ type Flock_t struct {
}
type Dirent struct {
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Pad0 uint8
+ Namlen uint16
+ Pad1 uint16
+ Name [256]int8
+}
+
+type dirent_freebsd11 struct {
Fileno uint32
Reclen uint16
Type uint8
@@ -493,7 +556,9 @@ type BpfZbufHeader struct {
}
const (
- _AT_FDCWD = -0x64
+ _AT_FDCWD = -0x64
+ _AT_SYMLINK_FOLLOW = 0x400
+ _AT_SYMLINK_NOFOLLOW = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go
index 4fd6bd509c..9be8752e18 100644
--- a/src/syscall/ztypes_freebsd_arm.go
+++ b/src/syscall/ztypes_freebsd_arm.go
@@ -1,4 +1,4 @@
-// Created by cgo -godefs - DO NOT EDIT
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs -- -fsigned-char types_freebsd.go
// +build arm,freebsd
@@ -77,27 +77,79 @@ const (
S_IRWXO = 0x7
)
+const (
+ _statfsVersion = 0x20140518
+ _dirblksiz = 0x400
+)
+
type Stat_t struct {
- Dev uint32
- Ino uint32
- Mode uint16
- Nlink uint16
- Uid uint32
- Gid uint32
- Rdev uint32
- Atimespec Timespec
- Mtimespec Timespec
- Ctimespec Timespec
- Size int64
- Blocks int64
- Blksize uint32
- Flags uint32
- Gen uint32
- Lspare int32
- Birthtimespec Timespec
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint16
+ Padding0 int16
+ Uid uint32
+ Gid uint32
+ Padding1 int32
+ Rdev uint64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Birthtim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint64
+ Spare [10]uint64
+}
+
+type stat_freebsd11_t struct {
+ Dev uint32
+ Ino uint32
+ Mode uint16
+ Nlink uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Birthtim Timespec
}
type Statfs_t struct {
+ Version uint32
+ Type uint32
+ Flags uint64
+ Bsize uint64
+ Iosize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail int64
+ Files uint64
+ Ffree int64
+ Syncwrites uint64
+ Asyncwrites uint64
+ Syncreads uint64
+ Asyncreads uint64
+ Spare [10]uint64
+ Namemax uint32
+ Owner uint32
+ Fsid Fsid
+ Charspare [80]int8
+ Fstypename [16]int8
+ Mntfromname [1024]int8
+ Mntonname [1024]int8
+}
+
+type statfs_freebsd11_t struct {
Version uint32
Type uint32
Flags uint64
@@ -133,6 +185,17 @@ type Flock_t struct {
}
type Dirent struct {
+ Fileno uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Pad0 uint8
+ Namlen uint16
+ Pad1 uint16
+ Name [256]int8
+}
+
+type dirent_freebsd11 struct {
Fileno uint32
Reclen uint16
Type uint8
@@ -493,7 +556,9 @@ type BpfZbufHeader struct {
}
const (
- _AT_FDCWD = -0x64
+ _AT_FDCWD = -0x64
+ _AT_SYMLINK_FOLLOW = 0x400
+ _AT_SYMLINK_NOFOLLOW = 0x200
)
type Termios struct {
From 9d907160d46ee56169b910673c0a934a0422cd73 Mon Sep 17 00:00:00 2001
From: Mikio Hara
Date: Fri, 5 Oct 2018 08:28:20 +0900
Subject: [PATCH 033/240] vendor: update golang_org/x/net/route from upstream
Updates the route package to git rev 146acd2 for:
- 146acd2 don't run NET_RT_IFLIST vs. NET_RT_IFLISTL test in 386 emulation (again)
Change-Id: I24de1eb31b2ca0e24cb9ab1648f7a71b5067cf97
Reviewed-on: https://go-review.googlesource.com/c/139937
Reviewed-by: Ian Lance Taylor
---
.../x/net/route/message_freebsd_test.go | 8 ++------
.../golang_org/x/net/route/sys_freebsd.go | 17 +++++++++++------
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/src/vendor/golang_org/x/net/route/message_freebsd_test.go b/src/vendor/golang_org/x/net/route/message_freebsd_test.go
index db4b56752c..c6d8a5f54c 100644
--- a/src/vendor/golang_org/x/net/route/message_freebsd_test.go
+++ b/src/vendor/golang_org/x/net/route/message_freebsd_test.go
@@ -4,10 +4,7 @@
package route
-import (
- "testing"
- "unsafe"
-)
+import "testing"
func TestFetchAndParseRIBOnFreeBSD(t *testing.T) {
for _, typ := range []RIBType{sysNET_RT_IFMALIST} {
@@ -40,8 +37,7 @@ func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) {
if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil {
t.Skip("NET_RT_IFLISTL not supported")
}
- var p uintptr
- if kernelAlign != int(unsafe.Sizeof(p)) {
+ if compatFreeBSD32 {
t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL doesn't work for 386 emulation on amd64")
}
diff --git a/src/vendor/golang_org/x/net/route/sys_freebsd.go b/src/vendor/golang_org/x/net/route/sys_freebsd.go
index a1a0d79b61..fe91be1249 100644
--- a/src/vendor/golang_org/x/net/route/sys_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/sys_freebsd.go
@@ -54,6 +54,8 @@ func (m *InterfaceMessage) Sys() []Sys {
}
}
+var compatFreeBSD32 bool // 386 emulation on amd64
+
func probeRoutingStack() (int, map[int]*wireFormat) {
var p uintptr
wordSize := int(unsafe.Sizeof(p))
@@ -83,8 +85,11 @@ func probeRoutingStack() (int, map[int]*wireFormat) {
break
}
}
+ if align != wordSize {
+ compatFreeBSD32 = true // 386 emulation on amd64
+ }
var rtm, ifm, ifam, ifmam, ifanm *wireFormat
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
ifm = &wireFormat{extOff: 16}
ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
@@ -100,31 +105,31 @@ func probeRoutingStack() (int, map[int]*wireFormat) {
rel, _ := syscall.SysctlUint32("kern.osreldate")
switch {
case rel < 800000:
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD7
}
case 800000 <= rel && rel < 900000:
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD8
}
case 900000 <= rel && rel < 1000000:
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD9
}
case 1000000 <= rel && rel < 1100000:
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD10
}
default:
- if align != wordSize { // 386 emulation on amd64
+ if compatFreeBSD32 {
ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
} else {
ifm.bodyOff = sizeofIfMsghdrFreeBSD11
From 430b9cb92f1291f2bef3c99d21925b3204cead90 Mon Sep 17 00:00:00 2001
From: Alberto Donizetti
Date: Fri, 5 Oct 2018 18:22:06 +0000
Subject: [PATCH 034/240] runtime: revert "skip TestLldbPython when lldb is too
old"
This reverts commit d2170040617231a26ab0722d093ecb19e2ba8302.
Reason for revert: It broke all the darwin builders; it's also not
obvious how the weird darwin versions (900, 1000) relate to the > 3.9
requisite, so I'm not sure how to decide about skipping in a robust
way. It's better to revert the check for now.
Fixes #28028
Change-Id: Ibbcb7bf7cd2136e0851ebd097a2bc4dec9f0ee18
Reviewed-on: https://go-review.googlesource.com/c/140217
Reviewed-by: Keith Randall
---
src/runtime/runtime-lldb_test.go | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index c74e6ef029..fe3a0eb90d 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -10,9 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"runtime"
- "strconv"
"strings"
"testing"
)
@@ -27,27 +25,6 @@ func checkLldbPython(t *testing.T) {
}
lldbPath = strings.TrimSpace(string(out))
- // Check lldb version. The test is known to fail with 3.8 or older
- // (see Issue #22299).
- cmd = exec.Command("lldb", "--version")
- out, err = cmd.CombinedOutput()
-
- // lldb --version should print "lldb version a.b.c"
- re := regexp.MustCompile(` ([[:digit:]]+)\.([[:digit:]]+)`)
- lldbVersion := re.FindStringSubmatch(string(out))
- if len(lldbVersion) != 3 {
- t.Errorf("bad lldb --version output: %s", out)
- }
- major, err1 := strconv.Atoi(lldbVersion[1])
- minor, err2 := strconv.Atoi(lldbVersion[2])
- if err1 != nil || err2 != nil {
- t.Errorf("bad lldb --version output: %s", out)
- }
-
- if (major < 3) || (major == 3 && minor < 9) {
- t.Skipf("skipping because lldb version %v.%v is too old (need >= 3.9)", major, minor)
- }
-
cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
out, err = cmd.CombinedOutput()
From 7b8b3f30edde4ec93b91e62d2d6442dff7360056 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Fri, 5 Oct 2018 12:09:43 +0000
Subject: [PATCH 035/240] cmd/compile: combine similar code in 386's assembly
generator
The indexed MOVload and MOVstore have similar logic, and this CL
combine them together. The total size of pkg/linux_386/cmd/compile/
decreases about 4KB.
Change-Id: I06236a3542aaa3dfc113c49fe4c69d209e018dfe
Reviewed-on: https://go-review.googlesource.com/c/139958
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/x86/ssa.go | 94 +++++++++--------------------
1 file changed, 30 insertions(+), 64 deletions(-)
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index e0bb4418ec..8f8ee75eec 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -484,43 +484,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
- case ssa.Op386MOVSDloadidx8:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 8
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 4
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.Op386MOVWloadidx2:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 2
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
+ case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1,
+ ssa.Op386MOVSDloadidx8, ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4, ssa.Op386MOVWloadidx2:
r := v.Args[0].Reg()
i := v.Args[1].Reg()
- if i == x86.REG_SP {
- r, i = i, r
- }
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
+ switch v.Op {
+ case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p.From.Scale = 1
+ case ssa.Op386MOVSDloadidx8:
+ p.From.Scale = 8
+ case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
+ p.From.Scale = 4
+ case ssa.Op386MOVWloadidx2:
+ p.From.Scale = 2
+ }
p.From.Reg = r
- p.From.Scale = 1
p.From.Index = i
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
@@ -573,45 +556,28 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux2(&p.To, v, off)
- case ssa.Op386MOVSDstoreidx8:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 8
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 4
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.Op386MOVWstoreidx2:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 2
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
+ case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1,
+ ssa.Op386MOVSDstoreidx8, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4, ssa.Op386MOVWstoreidx2:
r := v.Args[0].Reg()
i := v.Args[1].Reg()
- if i == x86.REG_SP {
- r, i = i, r
- }
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
+ switch v.Op {
+ case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p.To.Scale = 1
+ case ssa.Op386MOVSDstoreidx8:
+ p.To.Scale = 8
+ case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
+ p.To.Scale = 4
+ case ssa.Op386MOVWstoreidx2:
+ p.To.Scale = 2
+ }
p.To.Reg = r
- p.To.Scale = 1
p.To.Index = i
gc.AddAux(&p.To, v)
case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
From 30c1ed7d0bd4a7bdb544bf8c190668d647b4faac Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Fri, 5 Oct 2018 03:19:03 +0000
Subject: [PATCH 036/240] cmd/compile: simplify 386's rules
This CL combines several rules together via regular expression,
but won't impact generated 386 code.
Change-Id: I354006fe801fc952e3a9431cae63229922c9ba48
Reviewed-on: https://go-review.googlesource.com/c/139957
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/gen/386.rules | 118 +++++----------------
1 file changed, 28 insertions(+), 90 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index f6aa37e884..83c469024c 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -721,41 +721,21 @@
(MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
// generating indexed loads and stores
-(MOVBload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVWload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOV(B|W|L|SS|SD)load [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOV(B|W|L|SS|SD)loadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
(MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
(MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVLload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVLload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVSSload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVSSload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOV(L|SS)load [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOV(L|SS)loadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
(MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
(MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVBstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVWstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOV(B|W|L|SS|SD)store [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOV(B|W|L|SS|SD)storeidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
(MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
(MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVLstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVLstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVSSstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
-(MOVSDstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
- (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOV(L|SS)store [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOV(L|SS)storeidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
(MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
(MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
@@ -775,31 +755,17 @@
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem)
-(MOVBload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVBloadidx1 [off] {sym} ptr idx mem)
-(MOVWload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVWloadidx1 [off] {sym} ptr idx mem)
-(MOVLload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVLloadidx1 [off] {sym} ptr idx mem)
-(MOVSSload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVSSloadidx1 [off] {sym} ptr idx mem)
-(MOVSDload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVSDloadidx1 [off] {sym} ptr idx mem)
-(MOVBstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx1 [off] {sym} ptr idx val mem)
-(MOVWstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx1 [off] {sym} ptr idx val mem)
-(MOVLstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVLstoreidx1 [off] {sym} ptr idx val mem)
-(MOVSSstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
-(MOVSDstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+(MOV(B|W|L|SS|SD)load [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)loadidx1 [off] {sym} ptr idx mem)
+(MOV(B|W|L|SS|SD)store [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)storeidx1 [off] {sym} ptr idx val mem)
-(MOVBstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
- (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVWstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
- (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOV(B|W|L)storeconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
(MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
(MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVLstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
- (MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
(MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
(MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
-(MOVBstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
-(MOVWstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
-(MOVLstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+(MOV(B|W|L)storeconst [x] {sym} (ADDL ptr idx) mem) -> (MOV(B|W|L)storeconstidx1 [x] {sym} ptr idx mem)
// combine SHLL into indexed loads and stores
(MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
@@ -810,44 +776,24 @@
(MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
// combine ADDL into indexed loads and stores
-(MOVBloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVBloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVWloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
+(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
(MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx2 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVLloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVLloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVLloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVLloadidx4 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSSloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVSSloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSSloadidx4 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
+(MOV(L|SS)loadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+d))] {sym} ptr idx mem)
(MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx8 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVBstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVBstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVLstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVLstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVLstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVLstoreidx4 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSSstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSSstoreidx4 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVSDstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOV(L|SS)storeidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVBloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVBloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx2 [int64(int32(c+2*d))] {sym} ptr idx mem)
-(MOVLloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVLloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVLloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVLloadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem)
-(MOVSSloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSSloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
-(MOVSSloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSSloadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem)
-(MOVSDloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
+(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
+(MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx2 [int64(int32(c+2*d))] {sym} ptr idx mem)
+(MOV(L|SS)loadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem)
(MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx8 [int64(int32(c+8*d))] {sym} ptr idx mem)
-(MOVBstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVBstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVWstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
(MOVWstoreidx2 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx2 [int64(int32(c+2*d))] {sym} ptr idx val mem)
-(MOVLstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVLstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVLstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVLstoreidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem)
-(MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSSstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
-(MOVSSstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSSstoreidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem)
-(MOVSDstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
+(MOV(L|SS)storeidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem)
(MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem)
// Merge load/store to op
@@ -861,25 +807,17 @@
&& y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) ->
((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem)
-(MOVBstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
- (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
-(MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
- (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOV(B|W|L)storeconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
(MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
(MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
-(MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
- (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
(MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
(MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
-(MOVBstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
- (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
-(MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
- (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOV(B|W|L)storeconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
(MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
(MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
-(MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
- (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
(MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
(MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
From dc492682b6b0fba963b7f44fde1526723518c708 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Sat, 6 Oct 2018 03:00:31 +0000
Subject: [PATCH 037/240] cmd/compile: combine 386 rules via regular expression
This CL combines similar rules together via regular expression,
while does not impact generated 386 code.
Change-Id: I2b26e7fc6adffa0fa10eeb04a4f3a76ddabc760b
Reviewed-on: https://go-review.googlesource.com/c/140297
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/gen/386.rules | 76 ++++------------------
1 file changed, 12 insertions(+), 64 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index 83c469024c..c817994add 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -614,27 +614,16 @@
(MOVWLSX (ANDLconst [c] x)) && c & 0x8000 == 0 -> (ANDLconst [c & 0x7fff] x)
// Don't extend before storing
-(MOVWstore [off] {sym} ptr (MOVWLSX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
-(MOVBstore [off] {sym} ptr (MOVBLSX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
-(MOVWstore [off] {sym} ptr (MOVWLZX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
-(MOVBstore [off] {sym} ptr (MOVBLZX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWL(S|Z)X x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBL(S|Z)X x) mem) -> (MOVBstore [off] {sym} ptr x mem)
// fold constants into memory operations
// Note that this is not always a good idea because if not all the uses of
// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
// Nevertheless, let's do it!
-(MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVLload [off1+off2] {sym} ptr mem)
-(MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem)
-(MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem)
-(MOVSSload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSSload [off1+off2] {sym} ptr mem)
-(MOVSDload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSDload [off1+off2] {sym} ptr mem)
-
-(MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVLstore [off1+off2] {sym} ptr val mem)
-(MOVWstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
-(MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
-(MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSSstore [off1+off2] {sym} ptr val mem)
-(MOVSDstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSDstore [off1+off2] {sym} ptr val mem)
+(MOV(L|W|B|SS|SD)load [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)load [off1+off2] {sym} ptr mem)
+(MOV(L|W|B|SS|SD)store [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)store [off1+off2] {sym} ptr val mem)
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem)
@@ -656,12 +645,8 @@
(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
// Fold address offsets into constant stores.
-(MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
- (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
- (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
-(MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
- (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {s} ptr mem)
// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
// what variables are being read/written by the ops.
@@ -671,54 +656,17 @@
// a separate instruction gives us that register. Having the LEAL be
// a separate instruction also allows it to be CSEd (which is good because
// it compiles to a thunk call).
-(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
&& (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVSSload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVSDload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ (MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+(MOV(L|W|B|SS|SD)store [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
&& (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ (MOV(L|W|B|SS|SD)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVSSstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVSDstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-
-(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+(MOV(L|W|B)storeconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
- && (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
- && (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
- (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+ (MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
// generating indexed loads and stores
(MOV(B|W|L|SS|SD)load [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
From 2294e3ebd374e18b191d0e8d8d32c46b0a1ef961 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Sat, 6 Oct 2018 03:35:17 +0000
Subject: [PATCH 038/240] cmd/compile: combine similar code in amd64's assembly
generator
This CL combines similar code in amd64's assembly generator. The
total size of pkg/linux_amd64/cmd/compile/ decreases about 4.5KB,
while the generated amd64 code is not affected.
Change-Id: I4cdbdd22bde8857aafdc29b47fa100a906fa1598
Reviewed-on: https://go-review.googlesource.com/c/140298
Run-TryBot: Ben Shi
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/amd64/ssa.go | 94 +++++++++------------------
1 file changed, 30 insertions(+), 64 deletions(-)
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index b4c4b1f4cd..b5e31e1601 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -653,43 +653,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
- case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8, ssa.OpAMD64MOVLloadidx8:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 8
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 4
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.OpAMD64MOVWloadidx2:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- p.From.Scale = 2
- p.From.Index = v.Args[1].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.OpAMD64MOVBloadidx1, ssa.OpAMD64MOVWloadidx1, ssa.OpAMD64MOVLloadidx1, ssa.OpAMD64MOVQloadidx1, ssa.OpAMD64MOVSSloadidx1, ssa.OpAMD64MOVSDloadidx1:
+ case ssa.OpAMD64MOVBloadidx1, ssa.OpAMD64MOVWloadidx1, ssa.OpAMD64MOVLloadidx1, ssa.OpAMD64MOVQloadidx1, ssa.OpAMD64MOVSSloadidx1, ssa.OpAMD64MOVSDloadidx1,
+ ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8, ssa.OpAMD64MOVLloadidx8, ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4, ssa.OpAMD64MOVWloadidx2:
r := v.Args[0].Reg()
i := v.Args[1].Reg()
- if i == x86.REG_SP {
- r, i = i, r
- }
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
+ switch v.Op {
+ case ssa.OpAMD64MOVBloadidx1, ssa.OpAMD64MOVWloadidx1, ssa.OpAMD64MOVLloadidx1, ssa.OpAMD64MOVQloadidx1, ssa.OpAMD64MOVSSloadidx1, ssa.OpAMD64MOVSDloadidx1:
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p.From.Scale = 1
+ case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8, ssa.OpAMD64MOVLloadidx8:
+ p.From.Scale = 8
+ case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
+ p.From.Scale = 4
+ case ssa.OpAMD64MOVWloadidx2:
+ p.From.Scale = 2
+ }
p.From.Reg = r
- p.From.Scale = 1
p.From.Index = i
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
@@ -704,45 +687,28 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v)
- case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8, ssa.OpAMD64MOVLstoreidx8:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 8
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 4
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.OpAMD64MOVWstoreidx2:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[2].Reg()
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- p.To.Scale = 2
- p.To.Index = v.Args[1].Reg()
- gc.AddAux(&p.To, v)
- case ssa.OpAMD64MOVBstoreidx1, ssa.OpAMD64MOVWstoreidx1, ssa.OpAMD64MOVLstoreidx1, ssa.OpAMD64MOVQstoreidx1, ssa.OpAMD64MOVSSstoreidx1, ssa.OpAMD64MOVSDstoreidx1:
+ case ssa.OpAMD64MOVBstoreidx1, ssa.OpAMD64MOVWstoreidx1, ssa.OpAMD64MOVLstoreidx1, ssa.OpAMD64MOVQstoreidx1, ssa.OpAMD64MOVSSstoreidx1, ssa.OpAMD64MOVSDstoreidx1,
+ ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8, ssa.OpAMD64MOVLstoreidx8, ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4, ssa.OpAMD64MOVWstoreidx2:
r := v.Args[0].Reg()
i := v.Args[1].Reg()
- if i == x86.REG_SP {
- r, i = i, r
- }
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
+ switch v.Op {
+ case ssa.OpAMD64MOVBstoreidx1, ssa.OpAMD64MOVWstoreidx1, ssa.OpAMD64MOVLstoreidx1, ssa.OpAMD64MOVQstoreidx1, ssa.OpAMD64MOVSSstoreidx1, ssa.OpAMD64MOVSDstoreidx1:
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p.To.Scale = 1
+ case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8, ssa.OpAMD64MOVLstoreidx8:
+ p.To.Scale = 8
+ case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
+ p.To.Scale = 4
+ case ssa.OpAMD64MOVWstoreidx2:
+ p.To.Scale = 2
+ }
p.To.Reg = r
- p.To.Scale = 1
p.To.Index = i
gc.AddAux(&p.To, v)
case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify:
From 963776e689c4c015c89464ab4fef90ae50373f66 Mon Sep 17 00:00:00 2001
From: Roberto
Date: Sat, 6 Oct 2018 06:53:32 +0000
Subject: [PATCH 039/240] sync: fix typo in doc
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Change-Id: Ie1f35c7598bd2549a048d64e1b1279bf4acaa103
GitHub-Last-Rev: c8cc7dfef987cbd04f48daabf23efa64c0c67322
GitHub-Pull-Request: golang/go#28051
Reviewed-on: https://go-review.googlesource.com/c/140302
Reviewed-by: Daniel Martí
---
src/sync/runtime.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index be16bcc8f7..a13d9f6cf1 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -54,7 +54,7 @@ func init() {
}
// Active spinning runtime support.
-// runtime_canSpin returns true is spinning makes sense at the moment.
+// runtime_canSpin returns true if spinning makes sense at the moment.
func runtime_canSpin(i int) bool
// runtime_doSpin does active spinning.
From 8aee193fb8b61d474a7e3e6d43625f4e746c5b65 Mon Sep 17 00:00:00 2001
From: Tim Cooper
Date: Thu, 27 Sep 2018 16:55:24 -0500
Subject: [PATCH 040/240] all: remove unneeded parentheses from package consts
and vars
Change-Id: Ic7fce53c6264107c15b127d9c9ca0bec11a888ff
Reviewed-on: https://go-review.googlesource.com/c/138183
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/cmd/internal/obj/x86/asm6.go | 2 +-
src/crypto/rand/rand_freebsd.go | 2 +-
src/strconv/atoi.go | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index d3389e4f15..23ff7f32af 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2288,7 +2288,7 @@ func instinit(ctxt *obj.Link) {
}
}
-var isAndroid = (objabi.GOOS == "android")
+var isAndroid = objabi.GOOS == "android"
func prefixof(ctxt *obj.Link, a *obj.Addr) int {
if a.Reg < REG_CS && a.Index < REG_CS { // fast path
diff --git a/src/crypto/rand/rand_freebsd.go b/src/crypto/rand/rand_freebsd.go
index b4d6653343..75f683c386 100644
--- a/src/crypto/rand/rand_freebsd.go
+++ b/src/crypto/rand/rand_freebsd.go
@@ -6,4 +6,4 @@ package rand
// maxGetRandomRead is the maximum number of bytes to ask for in one call to the
// getrandom() syscall. In FreeBSD at most 256 bytes will be returned per call.
-const maxGetRandomRead = (1 << 8)
+const maxGetRandomRead = 1 << 8
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index bebed04820..bbfdb7dc39 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -44,7 +44,7 @@ const intSize = 32 << (^uint(0) >> 63)
// IntSize is the size in bits of an int or uint value.
const IntSize = intSize
-const maxUint64 = (1<<64 - 1)
+const maxUint64 = 1<<64 - 1
// ParseUint is like ParseInt but for unsigned numbers.
func ParseUint(s string, base int, bitSize int) (uint64, error) {
From 9f193fbe31d7ffa5f6e71a6387cbcf4636306660 Mon Sep 17 00:00:00 2001
From: Gabriel Aszalos
Date: Sat, 30 Jun 2018 18:12:24 +0200
Subject: [PATCH 041/240] encoding/json: use isSpace in stateEndTop
This change makes stateEndTop use isSpace instead of specifically
recreating the same functionality.
Change-Id: I81f8f51682e46e7f8e2b9fed423a968457200625
Reviewed-on: https://go-review.googlesource.com/c/121797
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/encoding/json/scanner.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index 9e6d482e16..88572245fc 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -289,7 +289,7 @@ func stateEndValue(s *scanner, c byte) int {
// such as after reading `{}` or `[1,2,3]`.
// Only space characters should be seen now.
func stateEndTop(s *scanner, c byte) int {
- if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+ if !isSpace(c) {
// Complain about non-space byte on next call.
s.error(c, "after top-level value")
}
From f90e89e675443731e36c2de4bcd3cdd7316d3dfc Mon Sep 17 00:00:00 2001
From: Igor Zhilianin
Date: Sat, 6 Oct 2018 06:10:25 +0000
Subject: [PATCH 042/240] all: fix a bunch of misspellings
Change-Id: If2954bdfc551515403706b2cd0dde94e45936e08
GitHub-Last-Rev: d4cfc41a5504cf10befefdb881d4c45986a1d1f8
GitHub-Pull-Request: golang/go#28049
Reviewed-on: https://go-review.googlesource.com/c/140299
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
misc/cgo/test/callback.go | 2 +-
misc/cgo/testplugin/unnamed1/main.go | 2 +-
misc/cgo/testsanitizers/cc_test.go | 2 +-
misc/cgo/testshared/shared_test.go | 2 +-
src/cmd/compile/doc.go | 2 +-
src/cmd/compile/internal/gc/syntax.go | 2 +-
src/cmd/compile/internal/gc/walk.go | 2 +-
src/cmd/compile/internal/ssa/gen/PPC64.rules | 2 +-
src/cmd/compile/internal/ssa/layout.go | 2 +-
src/cmd/compile/internal/ssa/poset.go | 2 +-
src/cmd/compile/internal/ssa/stackalloc.go | 2 +-
src/cmd/compile/internal/types/pkg.go | 2 +-
src/cmd/go/internal/modget/get.go | 2 +-
src/cmd/go/testdata/testterminal18153/terminal_test.go | 2 +-
src/cmd/internal/obj/arm64/asm7.go | 2 +-
src/cmd/internal/obj/util.go | 2 +-
src/cmd/internal/obj/x86/asm6.go | 2 +-
src/cmd/internal/obj/x86/ytab.go | 2 +-
src/cmd/link/internal/ld/dwarf_test.go | 2 +-
src/cmd/link/internal/ld/elf.go | 4 ++--
src/cmd/link/internal/ld/lib.go | 2 +-
src/cmd/vet/testdata/structtag.go | 4 ++--
src/compress/flate/inflate.go | 2 +-
src/compress/zlib/reader.go | 2 +-
src/database/sql/sql_test.go | 2 +-
src/go/constant/value.go | 2 +-
src/go/parser/parser.go | 2 +-
src/go/printer/testdata/parser.go | 2 +-
src/math/big/float.go | 2 +-
src/net/http/transport_test.go | 2 +-
src/net/smtp/smtp_test.go | 4 ++--
src/os/file_windows.go | 2 +-
src/os/os_test.go | 2 +-
src/runtime/mgc.go | 2 +-
src/runtime/proc.go | 2 +-
src/runtime/stack.go | 2 +-
src/syscall/mksyscall_windows.go | 2 +-
src/syscall/syscall_windows.go | 4 ++--
test/closure3.dir/main.go | 2 +-
test/closure3.go | 2 +-
40 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index b88bf134bc..58e126b41b 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -295,7 +295,7 @@ func goWithString(s string) {
}
func testCallbackStack(t *testing.T) {
- // Make cgo call and callback with different amount of stack stack available.
+ // Make cgo call and callback with different amount of stack available.
// We do not do any explicit checks, just ensure that it does not crash.
for _, f := range splitTests {
f()
diff --git a/misc/cgo/testplugin/unnamed1/main.go b/misc/cgo/testplugin/unnamed1/main.go
index 5c1df086d7..caf09c9e89 100644
--- a/misc/cgo/testplugin/unnamed1/main.go
+++ b/misc/cgo/testplugin/unnamed1/main.go
@@ -9,7 +9,7 @@ import "C"
func FuncInt() int { return 1 }
-// Add a recursive type to to check that type equality across plugins doesn't
+// Add a recursive type to check that type equality across plugins doesn't
// crash. See https://golang.org/issues/19258
func FuncRecursive() X { return X{} }
diff --git a/misc/cgo/testsanitizers/cc_test.go b/misc/cgo/testsanitizers/cc_test.go
index f09ad52cee..218e225429 100644
--- a/misc/cgo/testsanitizers/cc_test.go
+++ b/misc/cgo/testsanitizers/cc_test.go
@@ -374,7 +374,7 @@ func (c *config) checkRuntime() (skip bool, err error) {
}
// libcgo.h sets CGO_TSAN if it detects TSAN support in the C compiler.
- // Dump the preprocessor defines to check that that works.
+ // Dump the preprocessor defines to check that works.
// (Sometimes it doesn't: see https://golang.org/issue/15983.)
cmd, err := cc(c.cFlags...)
if err != nil {
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index 529a2c692f..c3c7a6aab6 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -578,7 +578,7 @@ func TestNotes(t *testing.T) {
}
// Build a GOPATH package (depBase) into a shared library that links against the goroot
-// runtime, another package (dep2) that links against the first, and and an
+// runtime, another package (dep2) that links against the first, and an
// executable that links against dep2.
func TestTwoGopathShlibs(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go
index 0dfaacb584..b68314cf73 100644
--- a/src/cmd/compile/doc.go
+++ b/src/cmd/compile/doc.go
@@ -125,7 +125,7 @@ directive can skip over a directive like any other comment.
// For a //line comment, this is the first character of the next line, and
// for a /*line comment this is the character position immediately following the closing */.
// If no filename is given, the recorded filename is empty if there is also no column number;
-// otherwise is is the most recently recorded filename (actual filename or filename specified
+// otherwise it is the most recently recorded filename (actual filename or filename specified
// by previous line directive).
// If a line directive doesn't specify a column number, the column is "unknown" until
// the next directive and the compiler does not report column numbers for that range.
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index eb2ab6b916..ab65ddebb4 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -45,7 +45,7 @@ type Node struct {
// - ONAME nodes that refer to local variables use it to identify their stack frame position.
// - ODOT, ODOTPTR, and OINDREGSP use it to indicate offset relative to their base address.
// - OSTRUCTKEY uses it to store the named field's offset.
- // - Named OLITERALs use it to to store their ambient iota value.
+ // - Named OLITERALs use it to store their ambient iota value.
// Possibly still more uses. If you find any, document them.
Xoffset int64
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 5aa2146a8c..1c398ef43c 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -34,7 +34,7 @@ func walk(fn *Node) {
}
}
- // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
+ // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
for _, ln := range fn.Func.Dcl {
if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Name.Used() {
ln.Name.Defn.Left.Name.SetUsed(true)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index 7d79c9ad50..21c12591c5 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -956,7 +956,7 @@
(MOVWZreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))])
-// Lose widening ops fed to to stores
+// Lose widening ops fed to stores
(MOVBstore [off] {sym} ptr (MOV(B|BZ|H|HZ|W|WZ)reg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
(MOVHstore [off] {sym} ptr (MOV(H|HZ|W|WZ)reg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
(MOVWstore [off] {sym} ptr (MOV(W|WZ)reg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
index 15e111ae7c..78d5dc77fe 100644
--- a/src/cmd/compile/internal/ssa/layout.go
+++ b/src/cmd/compile/internal/ssa/layout.go
@@ -12,7 +12,7 @@ func layout(f *Func) {
}
// Register allocation may use a different order which has constraints
-// imposed by the linear-scan algorithm. Note that that f.pass here is
+// imposed by the linear-scan algorithm. Note that f.pass here is
// regalloc, so the switch is conditional on -d=ssa/regalloc/test=N
func layoutRegallocOrder(f *Func) []*Block {
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index 37b607977c..0e0e2789b1 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -114,7 +114,7 @@ type posetNode struct {
// given that non-equality is not transitive, the only effect is that a later call
// to SetEqual for the same values will fail. NonEqual checks whether it is known that
// the nodes are different, either because SetNonEqual was called before, or because
-// we know that that they are strictly ordered.
+// we know that they are strictly ordered.
//
// It is implemented as a forest of DAGs; in each DAG, if node A dominates B,
// it means that A
Date: Sat, 6 Oct 2018 08:56:03 -0700
Subject: [PATCH 043/240] cmd/compile: allow VARDEF at top level
This was missed as part of adding a top-level VARDEF
for stack tracing (CL 134156).
Fixes #28055
Change-Id: Id14748dfccb119197d788867d2ec6a3b3c9835cf
Reviewed-on: https://go-review.googlesource.com/c/140304
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Alberto Donizetti
---
src/cmd/compile/internal/gc/walk.go | 1 +
test/fixedbugs/issue28055.go | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
create mode 100644 test/fixedbugs/issue28055.go
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 1c398ef43c..80fdc55b5d 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -211,6 +211,7 @@ func walkstmt(n *Node) *Node {
ODCLCONST,
ODCLTYPE,
OCHECKNIL,
+ OVARDEF,
OVARKILL,
OVARLIVE:
break
diff --git a/test/fixedbugs/issue28055.go b/test/fixedbugs/issue28055.go
new file mode 100644
index 0000000000..d4889d54d4
--- /dev/null
+++ b/test/fixedbugs/issue28055.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure VARDEF can be a top-level statement.
+
+package p
+
+func f() {
+ var s string
+ var as []string
+ switch false && (s+"a"+as[0]+s+as[0]+s == "") {
+ }
+}
From 46cf91a75fc0a516eb76b66b1a61202f3546bd7e Mon Sep 17 00:00:00 2001
From: Yasuhiro Matsumoto
Date: Sun, 7 Oct 2018 00:58:08 +0900
Subject: [PATCH 044/240] all: fix typos
Change-Id: I775eb4b33422a95f4255799d551c9962d7e181d3
Reviewed-on: https://go-review.googlesource.com/c/140318
Reviewed-by: Robert Griesemer
---
src/go/types/typexpr.go | 2 +-
src/os/user/cgo_lookup_unix.go | 10 ++++------
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index eb0d8e8fb9..0f23345792 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -562,7 +562,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
// its position, and because interface method
// signatures don't get a receiver via regular
// type-checking (there isn't a receiver in the
- // the method's AST). Setting the correct receiver
+ // method's AST). Setting the correct receiver
// type is also important for ptrRecv() (see methodset.go).
//
// TODO(gri) Consider marking methods signatures
diff --git a/src/os/user/cgo_lookup_unix.go b/src/os/user/cgo_lookup_unix.go
index 210bd6e0b3..ccb2278246 100644
--- a/src/os/user/cgo_lookup_unix.go
+++ b/src/os/user/cgo_lookup_unix.go
@@ -94,9 +94,8 @@ func lookupUnixUid(uid int) (*User, error) {
defer buf.free()
err := retryWithBuffer(buf, func() syscall.Errno {
- // mygetpwuid_r is a wrapper around getpwuid_r to
- // to avoid using uid_t because C.uid_t(uid) for
- // unknown reasons doesn't work on linux.
+ // mygetpwuid_r is a wrapper around getpwuid_r to avoid using uid_t
+ // because C.uid_t(uid) for unknown reasons doesn't work on linux.
return syscall.Errno(C.mygetpwuid_r(C.int(uid),
&pwd,
(*C.char)(buf.ptr),
@@ -175,9 +174,8 @@ func lookupUnixGid(gid int) (*Group, error) {
defer buf.free()
err := retryWithBuffer(buf, func() syscall.Errno {
- // mygetgrgid_r is a wrapper around getgrgid_r to
- // to avoid using gid_t because C.gid_t(gid) for
- // unknown reasons doesn't work on linux.
+ // mygetgrgid_r is a wrapper around getgrgid_r to avoid using gid_t
+ // because C.gid_t(gid) for unknown reasons doesn't work on linux.
return syscall.Errno(C.mygetgrgid_r(C.int(gid),
&grp,
(*C.char)(buf.ptr),
From 2bb91e093cb57c5ba5ca71f0d0a63913a07f21f4 Mon Sep 17 00:00:00 2001
From: Lehner Florian
Date: Tue, 2 Oct 2018 16:43:56 +0000
Subject: [PATCH 045/240] fmt: add example Sscanf
Updates golang/go#27554.
Change-Id: I2bf3d57ebeeb5dd50beffbc643a4ad10287b2c1e
GitHub-Last-Rev: 4ffae55b4b2ca9d9b2a5b2b6dcef14ce43d83544
GitHub-Pull-Request: golang/go#27954
Reviewed-on: https://go-review.googlesource.com/c/138837
Reviewed-by: Rob Pike
Run-TryBot: Rob Pike
TryBot-Result: Gobot Gobot
---
src/fmt/example_test.go | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/fmt/example_test.go b/src/fmt/example_test.go
index ecf3391ce7..c285175976 100644
--- a/src/fmt/example_test.go
+++ b/src/fmt/example_test.go
@@ -63,6 +63,19 @@ func ExampleFscanln() {
// 3: ken, 271828, 3.141590
}
+func ExampleSscanf() {
+ var name string
+ var age int
+ n, err := fmt.Sscanf("Kim is 22 years old", "%s is %d years old", &name, &age)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("%d: %s, %d\n", n, name, age)
+
+ // Output:
+ // 2: Kim, 22
+}
+
func ExamplePrint() {
const name, age = "Kim", 22
fmt.Print(name, " is ", age, " years old.\n")
From 165ebaf97bc4c4863a756775d75ddc750c55b8f2 Mon Sep 17 00:00:00 2001
From: ludweeg
Date: Sat, 6 Oct 2018 18:38:37 +0300
Subject: [PATCH 046/240] net: simplify bool expression
Simplify `!(x <= y)` to `x > y` and `!(x >= y)` to `x < y` where x,y are not defined as float.
Change-Id: Id1e5b518395d97e75f96aa4ac5d6c0ee990c0e7d
Reviewed-on: https://go-review.googlesource.com/c/140337
Run-TryBot: Mikio Hara
TryBot-Result: Gobot Gobot
Reviewed-by: Mikio Hara
---
src/net/dial_test.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 00a84d17d6..3a45c0d2ec 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -318,9 +318,9 @@ func TestDialParallel(t *testing.T) {
expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
- if !(elapsed >= expectElapsedMin) {
+ if elapsed < expectElapsedMin {
t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
- } else if !(elapsed <= expectElapsedMax) {
+ } else if elapsed > expectElapsedMax {
t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
}
@@ -418,10 +418,10 @@ func TestDialerFallbackDelay(t *testing.T) {
}
expectMin := tt.expectElapsed - 1*time.Millisecond
expectMax := tt.expectElapsed + 95*time.Millisecond
- if !(elapsed >= expectMin) {
+ if elapsed < expectMin {
t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
}
- if !(elapsed <= expectMax) {
+ if elapsed > expectMax {
t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
}
}
From 04dc1b2443f3cec9d3babff1046eb36f41236224 Mon Sep 17 00:00:00 2001
From: Igor Zhilianin
Date: Mon, 8 Oct 2018 01:19:51 +0000
Subject: [PATCH 047/240] all: fix a bunch of misspellings
Change-Id: I94cebca86706e072fbe3be782d3edbe0e22b9432
GitHub-Last-Rev: 8e15a40545704fb21b41a8768079f2da19341ef3
GitHub-Pull-Request: golang/go#28067
Reviewed-on: https://go-review.googlesource.com/c/140437
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/archive/zip/writer.go | 2 +-
src/cmd/asm/internal/asm/testdata/386enc.s | 2 +-
src/cmd/asm/internal/asm/testdata/amd64enc_extra.s | 2 +-
src/cmd/compile/internal/gc/esc.go | 3 ++-
src/cmd/compile/internal/ppc64/ssa.go | 2 +-
src/cmd/internal/obj/x86/evex.go | 2 +-
src/cmd/link/internal/ld/lib.go | 2 +-
src/cmd/vet/vet_test.go | 4 ++--
src/database/sql/sql_test.go | 2 +-
src/net/http/transfer.go | 2 +-
src/runtime/mheap.go | 2 +-
src/runtime/sys_linux_ppc64x.s | 2 +-
test/run.go | 4 ++--
13 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 5f0c0a1a55..cdc534eaf0 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -178,7 +178,7 @@ func (w *Writer) Close() error {
return err
}
- // store max values in the regular end record to signal that
+ // store max values in the regular end record to signal
// that the zip64 values should be used instead
records = uint16max
size = uint32max
diff --git a/src/cmd/asm/internal/asm/testdata/386enc.s b/src/cmd/asm/internal/asm/testdata/386enc.s
index 15d1705c97..4af6de36d1 100644
--- a/src/cmd/asm/internal/asm/testdata/386enc.s
+++ b/src/cmd/asm/internal/asm/testdata/386enc.s
@@ -18,7 +18,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
MOVL -2147483648(AX), AX // 8b8000000080
ADDL 2147483648(AX), AX // 038000000080
ADDL -2147483648(AX), AX // 038000000080
- // Make sure MOV CR/DR continues to work after changing it's movtabs.
+ // Make sure MOV CR/DR continues to work after changing its movtabs.
MOVL CR0, AX // 0f20c0
MOVL CR0, DX // 0f20c2
MOVL CR4, DI // 0f20e7
diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s
index 2f0d9ecf86..d7afecc230 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s
@@ -302,7 +302,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
// Check that LEAL is permitted to use overflowing offset.
LEAL 2400959708(BP)(R10*1), BP // 428dac15dcbc1b8f
LEAL 3395469782(AX)(R10*1), AX // 428d8410d6c162ca
- // Make sure MOV CR/DR continues to work after changing it's movtabs.
+ // Make sure MOV CR/DR continues to work after changing its movtabs.
MOVQ CR0, AX // 0f20c0
MOVQ CR0, DX // 0f20c2
MOVQ CR4, DI // 0f20e7
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 94190f0020..eba66d9c67 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -946,7 +946,8 @@ opSwitch:
case OCALLMETH, OCALLFUNC, OCALLINTER:
e.esccall(n, parent)
- // esccall already done on n.Rlist.First(). tie it's Retval to n.List
+ // esccall already done on n.Rlist.First()
+ // tie its Retval to n.List
case OAS2FUNC: // x,y = f()
rs := e.nodeEscState(n.Rlist.First()).Retval.Slice()
where := n
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index 0a7238850c..bd6ffbce53 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -967,7 +967,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpPPC64LoweredMove:
// This will be used when moving more
- // than 8 bytes. Moves start with as
+ // than 8 bytes. Moves start with
// as many 8 byte moves as possible, then
// 4, 2, or 1 byte(s) as remaining. This will
// work and be efficient for power8 or later.
diff --git a/src/cmd/internal/obj/x86/evex.go b/src/cmd/internal/obj/x86/evex.go
index 30c0e62e0f..d8867283fa 100644
--- a/src/cmd/internal/obj/x86/evex.go
+++ b/src/cmd/internal/obj/x86/evex.go
@@ -194,7 +194,7 @@ func newEVEXSuffix() evexSuffix {
return evexSuffix{rounding: rcUnset}
}
-// evexSuffixMap maps obj.X86suffix to it's decoded version.
+// evexSuffixMap maps obj.X86suffix to its decoded version.
// Filled during init().
var evexSuffixMap [255]evexSuffix
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 8f3326d8cd..2284c347dc 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -646,7 +646,7 @@ func (ctxt *Link) loadlib() {
//
// These are the symbols that begin with the prefix 'type.' and
// contain run-time type information used by the runtime and reflect
-// packages. All Go binaries contain these symbols, but only only
+// packages. All Go binaries contain these symbols, but only
// those programs loaded dynamically in multiple parts need these
// symbols to have entries in the symbol table.
func (ctxt *Link) mangleTypeSym() {
diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go
index df84d6cc98..6b2125924d 100644
--- a/src/cmd/vet/vet_test.go
+++ b/src/cmd/vet/vet_test.go
@@ -232,10 +232,10 @@ func TestVetVerbose(t *testing.T) {
// this function will report an error.
// Likewise if outStr does not have an error for a line which has a comment,
// or if the error message does not match the .
-// The syntax is Perl but its best to stick to egrep.
+// The syntax is Perl but it's best to stick to egrep.
//
// Sources files are supplied as fullshort slice.
-// It consists of pairs: full path to source file and it's base name.
+// It consists of pairs: full path to source file and its base name.
func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
var errs []error
out := splitOutput(outStr, wantAuto)
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 1be9f770f1..82f3f316c6 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -597,7 +597,7 @@ func TestPoolExhaustOnCancel(t *testing.T) {
state := 0
// waiter will be called for all queries, including
- // initial setup queries. The state is only assigned when no
+ // initial setup queries. The state is only assigned when
// no queries are made.
//
// Only allow the first batch of queries to finish once the
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 2c6ba3231b..a41d034204 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -942,7 +942,7 @@ func (b *body) Close() error {
// no trailer and closing the connection next.
// no point in reading to EOF.
case b.doEarlyClose:
- // Read up to maxPostHandlerReadBytes bytes of the body, looking for
+ // Read up to maxPostHandlerReadBytes bytes of the body, looking
// for EOF (and trailers), so we can re-use this connection.
if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes {
// There was a declared Content-Length, and we have more bytes remaining
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index b92e27e4e0..1d672cdf21 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -673,7 +673,7 @@ func (h *mheap) alloc_m(npage uintptr, spanclass spanClass, large bool) *mspan {
// TODO(austin): This tends to sweep a large number of
// spans in order to find a few completely free spans
// (for example, in the garbage benchmark, this sweeps
- // ~30x the number of pages its trying to allocate).
+ // ~30x the number of pages it's trying to allocate).
// If GC kept a bit for whether there were any marks
// in a span, we could release these free spans
// at the end of GC and eliminate this entirely.
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index ed79b69257..5b5df50d41 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -320,7 +320,7 @@ TEXT runtime·_sigtramp(SB),NOSPLIT,$64
TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
// The stack unwinder, presumably written in C, may not be able to
// handle Go frame correctly. So, this function is NOFRAME, and we
- // we save/restore LR manually.
+ // save/restore LR manually.
MOVD LR, R10
// We're coming from C code, initialize essential registers.
diff --git a/test/run.go b/test/run.go
index 3af6d1466b..0974e9fdb8 100644
--- a/test/run.go
+++ b/test/run.go
@@ -1071,10 +1071,10 @@ func splitOutput(out string, wantAuto bool) []string {
// this function will report an error.
// Likewise if outStr does not have an error for a line which has a comment,
// or if the error message does not match the .
-// The syntax is Perl but its best to stick to egrep.
+// The syntax is Perl but it's best to stick to egrep.
//
// Sources files are supplied as fullshort slice.
-// It consists of pairs: full path to source file and it's base name.
+// It consists of pairs: full path to source file and its base name.
func (t *test) errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
defer func() {
if *verbose && err != nil {
From 7c3b324d265905eec137d92e3a0a9041cad3679d Mon Sep 17 00:00:00 2001
From: Alex Brainman
Date: Sun, 7 Oct 2018 11:22:57 +1100
Subject: [PATCH 048/240] net: skip TestUnixConnLocalWindows on windows/arm
Similarly to CL 138676, skip TestUnixConnLocalWindows on windows/arm.
Fixes #28061
Change-Id: I2270d2f9d268e85ea567be0c0c37c48e4d482282
Reviewed-on: https://go-review.googlesource.com/c/140397
Run-TryBot: Alex Brainman
Reviewed-by: Ian Lance Taylor
---
src/net/unixsock_windows_test.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/net/unixsock_windows_test.go b/src/net/unixsock_windows_test.go
index d856e3fd81..5dccc14653 100644
--- a/src/net/unixsock_windows_test.go
+++ b/src/net/unixsock_windows_test.go
@@ -34,8 +34,11 @@ func isBuild17063() bool {
}
func TestUnixConnLocalWindows(t *testing.T) {
- if runtime.GOARCH == "386" {
+ switch runtime.GOARCH {
+ case "386":
t.Skip("not supported on windows/386, see golang.org/issue/27943")
+ case "arm":
+ t.Skip("not supported on windows/arm, see golang.org/issue/28061")
}
if !isBuild17063() {
t.Skip("unix test")
From 26d22609c389cd9b5a21939183b6411e5861e16b Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Tue, 2 Oct 2018 15:55:38 -0700
Subject: [PATCH 049/240] spec: distinguish between explicit and implicit
conversions (clarification)
The spec used the term "conversion" somewhat indiscriminately for
explicit conversions that appear literally in the source, and implicit
conversions that are implied by the context of an expression.
Be clearer about it by defining the terms.
Also, state that integer to string conversions of the form string(x)
are never implicit. This clarifies situations where implicit conversions
might require an integer to change to a string (but don't and never have
done so). See line 3948.
Fixes #26313.
Change-Id: I8939466df6b5950933ae7c987662ef9f88827fda
Reviewed-on: https://go-review.googlesource.com/c/139099
Reviewed-by: Rob Pike
Reviewed-by: Ian Lance Taylor
---
doc/go_spec.html | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 32336e86f8..6c7f2aa902 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
@@ -811,7 +811,7 @@ To avoid portability issues all numeric types are de
types and thus distinct except
byte, which is an alias for uint8, and
rune, which is an alias for int32.
-Conversions
+Explicit conversions
are required when different numeric types are mixed in an expression
or assignment. For instance, int32 and int
are not the same type even though they may have the same size on a
@@ -1348,7 +1348,7 @@ ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
The optional <- operator specifies the channel direction,
send or receive. If no direction is given, the channel is
bidirectional.
-A channel may be constrained only to send or only to receive by
+A channel may be constrained only to send or only to receive by explicit
conversion or assignment.
@@ -2069,9 +2069,9 @@ Otherwise, each variable is initialized to its zero va
If a type is present, each variable is given that type.
Otherwise, each variable is given the type of the corresponding
initialization value in the assignment.
-If that value is an untyped constant, it is first
+If that value is an untyped constant, it is first implicitly
converted to its default type;
-if it is an untyped boolean value, it is first converted to type bool.
+if it is an untyped boolean value, it is first implicitly converted to type bool.
The predeclared value nil cannot be used to initialize a variable
with no explicit type.
@@ -3433,7 +3433,7 @@ For operations involving constants only, see the section on
Except for shift operations, if one operand is an untyped constant
-and the other operand is not, the constant is converted
+and the other operand is not, the constant is implicitly converted
to the type of the other operand.
@@ -3442,7 +3442,7 @@ The right operand in a shift expression must have unsigned integer type
or be an untyped constant representable by a
value of type uint.
If the left operand of a non-constant shift expression is an untyped constant,
-it is first converted to the type it would assume if the shift expression were
+it is first implicitly converted to the type it would assume if the shift expression were
replaced by its left operand alone.
@@ -3645,7 +3645,7 @@ occurs is implementation-specific.
An implementation may combine multiple floating-point operations into a single
fused operation, possibly across statements, and produce a result that differs
from the value obtained by executing and rounding the instructions individually.
-A floating-point type conversion explicitly rounds to
+An explicit floating-point type conversion rounds to
the precision of the target type, preventing fusion that would discard that rounding.
@@ -3907,7 +3907,14 @@ channel is closed and empty.
Conversions
-Conversions are expressions of the form T(x)
+A conversion changes the type of an expression
+to the type specified by the conversion.
+A conversion may appear literally in the source, or it may be implied
+by the context in which an expression appears.
+
+
+
+An explicit conversion is an expression of the form T(x)
where T is a type and x is an expression
that can be converted to type T.
@@ -3938,7 +3945,7 @@ func() int(x) // x is converted to func() int (unambiguous)
A constant value x can be converted to
type T if x is representable
by a value of T.
-As a special case, an integer constant x can be converted to a
+As a special case, an integer constant x can be explicitly converted to a
string type using the
same rule
as for non-constant x.
@@ -4672,13 +4679,13 @@ to the type of the operand to which it is assigned, with the following special c
If an untyped constant
is assigned to a variable of interface type or the blank identifier,
- the constant is first converted to its
+ the constant is first implicitly converted to its
default type.
If an untyped boolean value is assigned to a variable of interface type or
- the blank identifier, it is first converted to type bool.
+ the blank identifier, it is first implicitly converted to type bool.
@@ -4764,14 +4771,14 @@ ExprSwitchCase = "case" ExpressionList | "default" .
-If the switch expression evaluates to an untyped constant, it is first
+If the switch expression evaluates to an untyped constant, it is first implicitly
converted to its default type;
-if it is an untyped boolean value, it is first converted to type bool.
+if it is an untyped boolean value, it is first implicitly converted to type bool.
The predeclared untyped value nil cannot be used as a switch expression.
-If a case expression is untyped, it is first converted
+If a case expression is untyped, it is first implicitly converted
to the type of the switch expression.
For each (possibly converted) case expression x and the value t
of the switch expression, x == t must be a valid comparison.
@@ -5881,7 +5888,7 @@ floating-point type and the return type is the complex type
with the corresponding floating-point constituents:
complex64 for float32 arguments, and
complex128 for float64 arguments.
-If one of the arguments evaluates to an untyped constant, it is first
+If one of the arguments evaluates to an untyped constant, it is first implicitly
converted to the type of the other argument.
If both arguments evaluate to untyped constants, they must be non-complex
numbers or their imaginary parts must be zero, and the return value of
From e99082fc409234ebfe4683f488c9b1f41278cf0a Mon Sep 17 00:00:00 2001
From: Richard Musiol
Date: Mon, 8 Oct 2018 17:52:52 +0200
Subject: [PATCH 050/240] misc/wasm: fix fs operations in browser
The commit 0e4c013 changed the syscall package so it uses the
asynchronous functions of Node.js's fs module.
This commit adapts the stubs of the fs module which are used when using
a browser instead of Node.js.
Fixes #28068.
Change-Id: Ic3a6a8aebb0db06402383bc2fea7642a4501e02c
Reviewed-on: https://go-review.googlesource.com/c/140537
Reviewed-by: Agniva De Sarker
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
misc/wasm/wasm_exec.js | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index 94b9552c59..815b3fbeff 100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -47,10 +47,17 @@
}
return buf.length;
},
- openSync(path, flags, mode) {
+ write(fd, buf, offset, length, position, callback) {
+ if (offset !== 0 || length !== buf.length || position !== null) {
+ throw new Error("not implemented");
+ }
+ const n = this.writeSync(fd, buf);
+ callback(null, n);
+ },
+ open(path, flags, mode, callback) {
const err = new Error("not implemented");
err.code = "ENOSYS";
- throw err;
+ callback(err);
},
};
}
From 2afdd17e3f0a453ba330352a7221f4fa9bef19b2 Mon Sep 17 00:00:00 2001
From: Urvil Patel
Date: Tue, 25 Sep 2018 13:44:45 +0530
Subject: [PATCH 051/240] strconv: add example for QuoteRuneToGraphic and
QuoteToGraphic functions
Change-Id: Ie5b2ef0087dbc7b8191de8c8b4190396631e3c7f
Reviewed-on: https://go-review.googlesource.com/c/137215
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/strconv/example_test.go | 40 +++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/src/strconv/example_test.go b/src/strconv/example_test.go
index 15725456e2..2d1a2a9dbf 100644
--- a/src/strconv/example_test.go
+++ b/src/strconv/example_test.go
@@ -265,7 +265,7 @@ func ExampleParseUint() {
}
func ExampleQuote() {
- s := strconv.Quote(`"Fran & Freddie's Diner ☺"`)
+ s := strconv.Quote(`"Fran & Freddie's Diner ☺"`) // there is a tab character inside the string literal
fmt.Println(s)
// Output:
@@ -288,14 +288,50 @@ func ExampleQuoteRuneToASCII() {
// '\u263a'
}
+func ExampleQuoteRuneToGraphic() {
+ s := strconv.QuoteRuneToGraphic('☺')
+ fmt.Println(s)
+
+ s = strconv.QuoteRuneToGraphic('\u263a')
+ fmt.Println(s)
+
+ s = strconv.QuoteRuneToGraphic('\u000a')
+ fmt.Println(s)
+
+ s = strconv.QuoteRuneToGraphic(' ') // tab character
+ fmt.Println(s)
+
+ // Output:
+ // '☺'
+ // '☺'
+ // '\n'
+ // '\t'
+}
+
func ExampleQuoteToASCII() {
- s := strconv.QuoteToASCII(`"Fran & Freddie's Diner ☺"`)
+ s := strconv.QuoteToASCII(`"Fran & Freddie's Diner ☺"`) // there is a tab character inside the string literal
fmt.Println(s)
// Output:
// "\"Fran & Freddie's Diner\t\u263a\""
}
+func ExampleQuoteToGraphic() {
+ s := strconv.QuoteToGraphic("☺")
+ fmt.Println(s)
+
+ s = strconv.QuoteToGraphic("This is a \u263a \u000a") // there is a tab character inside the string literal
+ fmt.Println(s)
+
+ s = strconv.QuoteToGraphic(`" This is a ☺ \n "`)
+ fmt.Println(s)
+
+ // Output:
+ // "☺"
+ // "This is a ☺\t\n"
+ // "\" This is a ☺ \\n \""
+}
+
func ExampleUnquote() {
s, err := strconv.Unquote("You can't unquote a string without quotes")
fmt.Printf("%q, %v\n", s, err)
From 393330255024d77c963910b2e2de918b5027a17f Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Sat, 6 Oct 2018 13:13:48 +0000
Subject: [PATCH 052/240] cmd/compile: add indexed form for several 386
instructions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This CL implements indexed memory operands for the following instructions.
(ADD|SUB|MUL|AND|OR|XOR)Lload -> (ADD|SUB|MUL|AND|OR|XOR)Lloadidx4
(ADD|SUB|AND|OR|XOR)Lmodify -> (ADD|SUB|AND|OR|XOR)Lmodifyidx4
(ADD|AND|OR|XOR)Lconstmodify -> (ADD|AND|OR|XOR)Lconstmodifyidx4
1. The total size of pkg/linux_386/ decreases about 2.5KB, excluding
cmd/compile/ .
2. There is little regression in the go1 benchmark test, excluding noise.
name old time/op new time/op delta
BinaryTree17-4 3.25s ± 3% 3.25s ± 3% ~ (p=0.218 n=40+40)
Fannkuch11-4 3.53s ± 1% 3.53s ± 1% ~ (p=0.303 n=40+40)
FmtFprintfEmpty-4 44.9ns ± 3% 45.6ns ± 3% +1.48% (p=0.030 n=40+36)
FmtFprintfString-4 78.7ns ± 5% 80.1ns ± 7% ~ (p=0.217 n=36+40)
FmtFprintfInt-4 90.2ns ± 6% 89.8ns ± 5% ~ (p=0.659 n=40+38)
FmtFprintfIntInt-4 140ns ± 5% 141ns ± 5% +1.00% (p=0.027 n=40+40)
FmtFprintfPrefixedInt-4 185ns ± 3% 183ns ± 3% ~ (p=0.104 n=40+40)
FmtFprintfFloat-4 411ns ± 4% 406ns ± 3% -1.37% (p=0.005 n=40+40)
FmtManyArgs-4 590ns ± 4% 598ns ± 4% +1.35% (p=0.008 n=40+40)
GobDecode-4 7.16ms ± 5% 7.10ms ± 5% ~ (p=0.335 n=40+40)
GobEncode-4 6.85ms ± 7% 6.74ms ± 9% ~ (p=0.058 n=38+40)
Gzip-4 400ms ± 4% 399ms ± 2% -0.34% (p=0.003 n=40+33)
Gunzip-4 41.4ms ± 3% 41.4ms ± 4% -0.12% (p=0.020 n=40+40)
HTTPClientServer-4 64.1µs ± 4% 63.5µs ± 2% -1.07% (p=0.000 n=39+37)
JSONEncode-4 15.9ms ± 2% 15.9ms ± 3% ~ (p=0.103 n=40+40)
JSONDecode-4 62.2ms ± 4% 61.6ms ± 3% -0.98% (p=0.006 n=39+40)
Mandelbrot200-4 5.18ms ± 3% 5.14ms ± 4% ~ (p=0.125 n=40+40)
GoParse-4 3.29ms ± 2% 3.27ms ± 2% -0.66% (p=0.006 n=40+40)
RegexpMatchEasy0_32-4 103ns ± 4% 103ns ± 4% ~ (p=0.632 n=40+40)
RegexpMatchEasy0_1K-4 830ns ± 3% 828ns ± 3% ~ (p=0.563 n=40+40)
RegexpMatchEasy1_32-4 113ns ± 4% 113ns ± 4% ~ (p=0.494 n=40+40)
RegexpMatchEasy1_1K-4 1.03µs ± 4% 1.03µs ± 4% ~ (p=0.665 n=40+40)
RegexpMatchMedium_32-4 130ns ± 4% 129ns ± 3% ~ (p=0.458 n=40+40)
RegexpMatchMedium_1K-4 39.4µs ± 3% 39.7µs ± 3% ~ (p=0.825 n=40+40)
RegexpMatchHard_32-4 2.16µs ± 4% 2.15µs ± 4% ~ (p=0.137 n=40+40)
RegexpMatchHard_1K-4 65.2µs ± 3% 65.4µs ± 4% ~ (p=0.160 n=40+40)
Revcomp-4 1.87s ± 2% 1.87s ± 1% +0.17% (p=0.019 n=33+33)
Template-4 69.4ms ± 3% 69.8ms ± 3% +0.60% (p=0.009 n=40+40)
TimeParse-4 437ns ± 4% 438ns ± 4% ~ (p=0.234 n=40+40)
TimeFormat-4 408ns ± 3% 408ns ± 3% ~ (p=0.904 n=40+40)
[Geo mean] 65.7µs 65.6µs -0.08%
name old speed new speed delta
GobDecode-4 107MB/s ± 5% 108MB/s ± 5% ~ (p=0.336 n=40+40)
GobEncode-4 112MB/s ± 6% 114MB/s ± 9% +1.95% (p=0.036 n=37+40)
Gzip-4 48.5MB/s ± 4% 48.6MB/s ± 2% +0.28% (p=0.003 n=40+33)
Gunzip-4 469MB/s ± 4% 469MB/s ± 4% +0.11% (p=0.021 n=40+40)
JSONEncode-4 122MB/s ± 2% 122MB/s ± 3% ~ (p=0.105 n=40+40)
JSONDecode-4 31.2MB/s ± 4% 31.5MB/s ± 4% +0.99% (p=0.007 n=39+40)
GoParse-4 17.6MB/s ± 2% 17.7MB/s ± 2% +0.66% (p=0.007 n=40+40)
RegexpMatchEasy0_32-4 310MB/s ± 4% 310MB/s ± 4% ~ (p=0.384 n=40+40)
RegexpMatchEasy0_1K-4 1.23GB/s ± 3% 1.24GB/s ± 3% ~ (p=0.186 n=40+40)
RegexpMatchEasy1_32-4 283MB/s ± 3% 281MB/s ± 4% ~ (p=0.855 n=40+40)
RegexpMatchEasy1_1K-4 1.00GB/s ± 4% 1.00GB/s ± 4% ~ (p=0.665 n=40+40)
RegexpMatchMedium_32-4 7.68MB/s ± 4% 7.73MB/s ± 3% ~ (p=0.359 n=40+40)
RegexpMatchMedium_1K-4 26.0MB/s ± 3% 25.8MB/s ± 3% ~ (p=0.825 n=40+40)
RegexpMatchHard_32-4 14.8MB/s ± 3% 14.9MB/s ± 4% ~ (p=0.136 n=40+40)
RegexpMatchHard_1K-4 15.7MB/s ± 3% 15.7MB/s ± 4% ~ (p=0.150 n=40+40)
Revcomp-4 136MB/s ± 1% 136MB/s ± 1% -0.09% (p=0.028 n=32+33)
Template-4 28.0MB/s ± 3% 27.8MB/s ± 3% -0.59% (p=0.010 n=40+40)
[Geo mean] 82.1MB/s 82.3MB/s +0.25%
Change-Id: Ifa387a251056678326d3508aa02753b70bf7e5d0
Reviewed-on: https://go-review.googlesource.com/c/140303
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/gen/386.rules | 37 +
src/cmd/compile/internal/ssa/gen/386Ops.go | 29 +-
src/cmd/compile/internal/ssa/opGen.go | 275 ++
src/cmd/compile/internal/ssa/rewrite386.go | 2837 +++++++++++++++++++-
src/cmd/compile/internal/x86/ssa.go | 25 +-
test/codegen/arithmetic.go | 9 +-
6 files changed, 3183 insertions(+), 29 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index c817994add..0df8911f39 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -627,14 +627,26 @@
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem)
+((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) && is32Bit(off1+off2) ->
+ ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {sym} val base idx mem)
+((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) && is32Bit(off1+off2*4) ->
+ ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2*4] {sym} val base idx mem)
((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem)
((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem)
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) ->
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem)
+((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) && is32Bit(off1+off2) ->
+ ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {sym} base idx val mem)
+((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) && is32Bit(off1+off2*4) ->
+ ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2*4] {sym} base idx val mem)
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) ->
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem)
+((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) && ValAndOff(valoff1).canAdd(off2) ->
+ ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
+((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) && ValAndOff(valoff1).canAdd(off2*4) ->
+ ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
// Fold constants into stores.
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
@@ -690,6 +702,9 @@
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
+((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
@@ -699,9 +714,15 @@
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem)
+((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
+ && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ ((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
(MOV(B|W|L|SS|SD)load [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)loadidx1 [off] {sym} ptr idx mem)
(MOV(B|W|L|SS|SD)store [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)storeidx1 [off] {sym} ptr idx val mem)
@@ -746,14 +767,30 @@
// Merge load/store to op
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
+((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) && canMergeLoad(v, l, x) && clobber(l) ->
+ ((ADD|AND|OR|XOR|SUB|MUL)Lloadidx4 x [off] {sym} ptr idx mem)
+((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ ((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) ->
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
+(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lloadidx4 x [off] {sym} ptr idx mem) mem) && y.Uses==1 && clobber(y) ->
+ ((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem)
+(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|SUB|AND|OR|XOR)L l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) ->
+ ((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr mem)) mem)
&& y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) ->
((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem)
+(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) ->
+ ((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(c,off) ->
+ ((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+(SUBLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(-c,off) ->
+ (ADDLconstmodifyidx4 [makeValAndOff(-c,off)] {sym} ptr idx mem)
(MOV(B|W|L)storeconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
(MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
index 1786eea7cf..f7e5f939ab 100644
--- a/src/cmd/compile/internal/ssa/gen/386Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -126,9 +126,10 @@ func init() {
readflags = regInfo{inputs: nil, outputs: gponly}
flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
- gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
- gp21load = regInfo{inputs: []regMask{gp, gpspsb, 0}, outputs: gponly}
- gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
+ gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
+ gp21load = regInfo{inputs: []regMask{gp, gpspsb, 0}, outputs: gponly}
+ gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
+ gp21loadidx = regInfo{inputs: []regMask{gp, gpspsb, gpsp, 0}, outputs: gponly}
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
gpstoreconst = regInfo{inputs: []regMask{gpspsb, 0}}
@@ -281,6 +282,7 @@ func init() {
{name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-15
{name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-7
+ // binary-op with a memory source operand
{name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{name: "MULLload", argLength: 3, reg: gp21load, asm: "IMULL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
@@ -288,6 +290,14 @@ func init() {
{name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
+ // binary-op with an indexed memory source operand
+ {name: "ADDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+ {name: "SUBLloadidx4", argLength: 4, reg: gp21loadidx, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+ {name: "MULLloadidx4", argLength: 4, reg: gp21loadidx, asm: "IMULL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+ {name: "ANDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+ {name: "ORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+ {name: "XORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+arg2*4+auxint+aux, arg3 = mem
+
// unary ops
{name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0
@@ -367,12 +377,25 @@ func init() {
{name: "ORLmodify", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) |= arg1, arg2=mem
{name: "XORLmodify", argLength: 3, reg: gpstore, asm: "XORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) ^= arg1, arg2=mem
+ // direct binary-op on indexed memory (read-modify-write)
+ {name: "ADDLmodifyidx4", argLength: 4, reg: gpstoreidx, asm: "ADDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+arg1*4+auxint+aux) += arg2, arg3=mem
+ {name: "SUBLmodifyidx4", argLength: 4, reg: gpstoreidx, asm: "SUBL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+arg1*4+auxint+aux) -= arg2, arg3=mem
+ {name: "ANDLmodifyidx4", argLength: 4, reg: gpstoreidx, asm: "ANDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+arg1*4+auxint+aux) &= arg2, arg3=mem
+ {name: "ORLmodifyidx4", argLength: 4, reg: gpstoreidx, asm: "ORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+arg1*4+auxint+aux) |= arg2, arg3=mem
+ {name: "XORLmodifyidx4", argLength: 4, reg: gpstoreidx, asm: "XORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+arg1*4+auxint+aux) ^= arg2, arg3=mem
+
// direct binary-op on memory with a constant (read-modify-write)
{name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // add ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
+ // direct binary-op on indexed memory with a constant (read-modify-write)
+ {name: "ADDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // add ValAndOff(AuxInt).Val() to arg0+arg1*4+ValAndOff(AuxInt).Off()+aux, arg2=mem
+ {name: "ANDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // and ValAndOff(AuxInt).Val() to arg0+arg1*4+ValAndOff(AuxInt).Off()+aux, arg2=mem
+ {name: "ORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // or ValAndOff(AuxInt).Val() to arg0+arg1*4+ValAndOff(AuxInt).Off()+aux, arg2=mem
+ {name: "XORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "XORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // xor ValAndOff(AuxInt).Val() to arg0+arg1*4+ValAndOff(AuxInt).Off()+aux, arg2=mem
+
// indexed loads/stores
{name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", aux: "SymOff", symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
{name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", aux: "SymOff", symEffect: "Read"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 2145c6e723..ae04e25798 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -339,6 +339,12 @@ const (
Op386ANDLload
Op386ORLload
Op386XORLload
+ Op386ADDLloadidx4
+ Op386SUBLloadidx4
+ Op386MULLloadidx4
+ Op386ANDLloadidx4
+ Op386ORLloadidx4
+ Op386XORLloadidx4
Op386NEGL
Op386NOTL
Op386BSFL
@@ -394,10 +400,19 @@ const (
Op386ANDLmodify
Op386ORLmodify
Op386XORLmodify
+ Op386ADDLmodifyidx4
+ Op386SUBLmodifyidx4
+ Op386ANDLmodifyidx4
+ Op386ORLmodifyidx4
+ Op386XORLmodifyidx4
Op386ADDLconstmodify
Op386ANDLconstmodify
Op386ORLconstmodify
Op386XORLconstmodify
+ Op386ADDLconstmodifyidx4
+ Op386ANDLconstmodifyidx4
+ Op386ORLconstmodifyidx4
+ Op386XORLconstmodifyidx4
Op386MOVBloadidx1
Op386MOVWloadidx1
Op386MOVWloadidx2
@@ -4019,6 +4034,126 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ADDLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.AADDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SUBLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.ASUBL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MULLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.AIMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "ANDLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "ORLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "XORLloadidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ symEffect: SymRead,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {1, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
{
name: "NEGL",
argLen: 1,
@@ -4743,6 +4878,86 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ADDLmodifyidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AADDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "SUBLmodifyidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.ASUBL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "ANDLmodifyidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "ORLmodifyidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "XORLmodifyidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
{
name: "ADDLconstmodify",
auxType: auxSymValAndOff,
@@ -4799,6 +5014,66 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ADDLconstmodifyidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AADDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "ANDLconstmodifyidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "ORLconstmodifyidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "XORLconstmodifyidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ symEffect: SymRead | SymWrite,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
{
name: "MOVBloadidx1",
auxType: auxSymOff,
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 5481b4e773..3fb820933c 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -25,10 +25,16 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386ADDLconst_0(v)
case Op386ADDLconstmodify:
return rewriteValue386_Op386ADDLconstmodify_0(v)
+ case Op386ADDLconstmodifyidx4:
+ return rewriteValue386_Op386ADDLconstmodifyidx4_0(v)
case Op386ADDLload:
return rewriteValue386_Op386ADDLload_0(v)
+ case Op386ADDLloadidx4:
+ return rewriteValue386_Op386ADDLloadidx4_0(v)
case Op386ADDLmodify:
return rewriteValue386_Op386ADDLmodify_0(v)
+ case Op386ADDLmodifyidx4:
+ return rewriteValue386_Op386ADDLmodifyidx4_0(v)
case Op386ADDSD:
return rewriteValue386_Op386ADDSD_0(v)
case Op386ADDSDload:
@@ -43,10 +49,16 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386ANDLconst_0(v)
case Op386ANDLconstmodify:
return rewriteValue386_Op386ANDLconstmodify_0(v)
+ case Op386ANDLconstmodifyidx4:
+ return rewriteValue386_Op386ANDLconstmodifyidx4_0(v)
case Op386ANDLload:
return rewriteValue386_Op386ANDLload_0(v)
+ case Op386ANDLloadidx4:
+ return rewriteValue386_Op386ANDLloadidx4_0(v)
case Op386ANDLmodify:
return rewriteValue386_Op386ANDLmodify_0(v)
+ case Op386ANDLmodifyidx4:
+ return rewriteValue386_Op386ANDLmodifyidx4_0(v)
case Op386CMPB:
return rewriteValue386_Op386CMPB_0(v)
case Op386CMPBconst:
@@ -118,7 +130,7 @@ func rewriteValue386(v *Value) bool {
case Op386MOVLstoreidx1:
return rewriteValue386_Op386MOVLstoreidx1_0(v)
case Op386MOVLstoreidx4:
- return rewriteValue386_Op386MOVLstoreidx4_0(v)
+ return rewriteValue386_Op386MOVLstoreidx4_0(v) || rewriteValue386_Op386MOVLstoreidx4_10(v)
case Op386MOVSDconst:
return rewriteValue386_Op386MOVSDconst_0(v)
case Op386MOVSDload:
@@ -177,6 +189,8 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386MULLconst_0(v) || rewriteValue386_Op386MULLconst_10(v) || rewriteValue386_Op386MULLconst_20(v) || rewriteValue386_Op386MULLconst_30(v)
case Op386MULLload:
return rewriteValue386_Op386MULLload_0(v)
+ case Op386MULLloadidx4:
+ return rewriteValue386_Op386MULLloadidx4_0(v)
case Op386MULSD:
return rewriteValue386_Op386MULSD_0(v)
case Op386MULSDload:
@@ -195,10 +209,16 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386ORLconst_0(v)
case Op386ORLconstmodify:
return rewriteValue386_Op386ORLconstmodify_0(v)
+ case Op386ORLconstmodifyidx4:
+ return rewriteValue386_Op386ORLconstmodifyidx4_0(v)
case Op386ORLload:
return rewriteValue386_Op386ORLload_0(v)
+ case Op386ORLloadidx4:
+ return rewriteValue386_Op386ORLloadidx4_0(v)
case Op386ORLmodify:
return rewriteValue386_Op386ORLmodify_0(v)
+ case Op386ORLmodifyidx4:
+ return rewriteValue386_Op386ORLmodifyidx4_0(v)
case Op386ROLBconst:
return rewriteValue386_Op386ROLBconst_0(v)
case Op386ROLLconst:
@@ -265,8 +285,12 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386SUBLconst_0(v)
case Op386SUBLload:
return rewriteValue386_Op386SUBLload_0(v)
+ case Op386SUBLloadidx4:
+ return rewriteValue386_Op386SUBLloadidx4_0(v)
case Op386SUBLmodify:
return rewriteValue386_Op386SUBLmodify_0(v)
+ case Op386SUBLmodifyidx4:
+ return rewriteValue386_Op386SUBLmodifyidx4_0(v)
case Op386SUBSD:
return rewriteValue386_Op386SUBSD_0(v)
case Op386SUBSDload:
@@ -281,10 +305,16 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_Op386XORLconst_0(v)
case Op386XORLconstmodify:
return rewriteValue386_Op386XORLconstmodify_0(v)
+ case Op386XORLconstmodifyidx4:
+ return rewriteValue386_Op386XORLconstmodifyidx4_0(v)
case Op386XORLload:
return rewriteValue386_Op386XORLload_0(v)
+ case Op386XORLloadidx4:
+ return rewriteValue386_Op386XORLloadidx4_0(v)
case Op386XORLmodify:
return rewriteValue386_Op386XORLmodify_0(v)
+ case Op386XORLmodifyidx4:
+ return rewriteValue386_Op386XORLmodifyidx4_0(v)
case OpAdd16:
return rewriteValue386_OpAdd16_0(v)
case OpAdd32:
@@ -1314,6 +1344,62 @@ func rewriteValue386_Op386ADDL_20(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (ADDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ADDLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ADDLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ l := v.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ x := v.Args[1]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
// match: (ADDL x (NEGL y))
// cond:
// result: (SUBL x y)
@@ -1621,6 +1707,92 @@ func rewriteValue386_Op386ADDLconstmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ADDLconstmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ADDLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2)
+ // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem)
+ // cond: ValAndOff(valoff1).canAdd(off2*4)
+ // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2 * 4)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2 * 4)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ADDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386ADDLload_0(v *Value) bool {
b := v.Block
_ = b
@@ -1679,6 +1851,128 @@ func rewriteValue386_Op386ADDLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (ADDLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (ADDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ADDLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ADDLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ADDLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ADDLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ADDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ADDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386ADDLmodify_0(v *Value) bool {
@@ -1741,6 +2035,124 @@ func rewriteValue386_Op386ADDLmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ADDLmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ADDLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ADDLmodifyidx4 [off1+off2] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ADDLmodifyidx4 [off1+off2*4] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ADDLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ADDLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem)
+ // cond: validValAndOff(c,off)
+ // result: (ADDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386MOVLconst {
+ break
+ }
+ c := v_2.AuxInt
+ mem := v.Args[3]
+ if !(validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386ADDSD_0(v *Value) bool {
b := v.Block
_ = b
@@ -2064,6 +2476,62 @@ func rewriteValue386_Op386ANDL_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (ANDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ANDLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ANDLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ l := v.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ x := v.Args[1]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
// match: (ANDL x x)
// cond:
// result: x
@@ -2195,6 +2663,92 @@ func rewriteValue386_Op386ANDLconstmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ANDLconstmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ANDLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2)
+ // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2)) {
+ break
+ }
+ v.reset(Op386ANDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem)
+ // cond: ValAndOff(valoff1).canAdd(off2*4)
+ // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2 * 4)) {
+ break
+ }
+ v.reset(Op386ANDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2 * 4)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ANDLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ANDLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386ANDLload_0(v *Value) bool {
b := v.Block
_ = b
@@ -2253,6 +2807,128 @@ func rewriteValue386_Op386ANDLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (ANDLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (ANDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ANDLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ANDLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ANDLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ANDLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ANDLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ANDLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386ANDLmodify_0(v *Value) bool {
@@ -2315,6 +2991,124 @@ func rewriteValue386_Op386ANDLmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ANDLmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ANDLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ANDLmodifyidx4 [off1+off2] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ANDLmodifyidx4 [off1+off2*4] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ANDLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ANDLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem)
+ // cond: validValAndOff(c,off)
+ // result: (ANDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386MOVLconst {
+ break
+ }
+ c := v_2.AuxInt
+ mem := v.Args[3]
+ if !(validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ANDLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386CMPB_0(v *Value) bool {
b := v.Block
_ = b
@@ -7279,6 +8073,797 @@ func rewriteValue386_Op386MOVLstoreidx4_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDLloadidx4 x [off] {sym} ptr idx mem) mem)
+ // cond: y.Uses==1 && clobber(y)
+ // result: (ADDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ADDLloadidx4 {
+ break
+ }
+ if y.AuxInt != off {
+ break
+ }
+ if y.Aux != sym {
+ break
+ }
+ _ = y.Args[3]
+ x := y.Args[0]
+ if ptr != y.Args[1] {
+ break
+ }
+ if idx != y.Args[2] {
+ break
+ }
+ mem := y.Args[3]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && clobber(y)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDLloadidx4 x [off] {sym} ptr idx mem) mem)
+ // cond: y.Uses==1 && clobber(y)
+ // result: (ANDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ANDLloadidx4 {
+ break
+ }
+ if y.AuxInt != off {
+ break
+ }
+ if y.Aux != sym {
+ break
+ }
+ _ = y.Args[3]
+ x := y.Args[0]
+ if ptr != y.Args[1] {
+ break
+ }
+ if idx != y.Args[2] {
+ break
+ }
+ mem := y.Args[3]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && clobber(y)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORLloadidx4 x [off] {sym} ptr idx mem) mem)
+ // cond: y.Uses==1 && clobber(y)
+ // result: (ORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ORLloadidx4 {
+ break
+ }
+ if y.AuxInt != off {
+ break
+ }
+ if y.Aux != sym {
+ break
+ }
+ _ = y.Args[3]
+ x := y.Args[0]
+ if ptr != y.Args[1] {
+ break
+ }
+ if idx != y.Args[2] {
+ break
+ }
+ mem := y.Args[3]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && clobber(y)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORLloadidx4 x [off] {sym} ptr idx mem) mem)
+ // cond: y.Uses==1 && clobber(y)
+ // result: (XORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386XORLloadidx4 {
+ break
+ }
+ if y.AuxInt != off {
+ break
+ }
+ if y.Aux != sym {
+ break
+ }
+ _ = y.Args[3]
+ x := y.Args[0]
+ if ptr != y.Args[1] {
+ break
+ }
+ if idx != y.Args[2] {
+ break
+ }
+ mem := y.Args[3]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && clobber(y)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ADDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ADDL {
+ break
+ }
+ _ = y.Args[1]
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ x := y.Args[1]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ADDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ADDL {
+ break
+ }
+ _ = y.Args[1]
+ x := y.Args[0]
+ l := y.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ADDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(SUBL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (SUBLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386SUBL {
+ break
+ }
+ _ = y.Args[1]
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ x := y.Args[1]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386SUBLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ANDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ANDL {
+ break
+ }
+ _ = y.Args[1]
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ x := y.Args[1]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVLstoreidx4_10(v *Value) bool {
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ANDLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ANDL {
+ break
+ }
+ _ = y.Args[1]
+ x := y.Args[0]
+ l := y.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ANDLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ORL {
+ break
+ }
+ _ = y.Args[1]
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ x := y.Args[1]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (ORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ORL {
+ break
+ }
+ _ = y.Args[1]
+ x := y.Args[0]
+ l := y.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (XORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386XORL {
+ break
+ }
+ _ = y.Args[1]
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ x := y.Args[1]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
+ // result: (XORLmodifyidx4 [off] {sym} ptr idx x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386XORL {
+ break
+ }
+ _ = y.Args[1]
+ x := y.Args[0]
+ l := y.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ADDLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off)
+ // result: (ADDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ADDLconst {
+ break
+ }
+ c := y.AuxInt
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ANDLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off)
+ // result: (ANDLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ANDLconst {
+ break
+ }
+ c := y.AuxInt
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ANDLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(ORLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off)
+ // result: (ORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386ORLconst {
+ break
+ }
+ c := y.AuxInt
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ORLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreidx4 {sym} [off] ptr idx y:(XORLconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
+ // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off)
+ // result: (XORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ y := v.Args[2]
+ if y.Op != Op386XORLconst {
+ break
+ }
+ c := y.AuxInt
+ l := y.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ if l.AuxInt != off {
+ break
+ }
+ if l.Aux != sym {
+ break
+ }
+ _ = l.Args[2]
+ if ptr != l.Args[0] {
+ break
+ }
+ if idx != l.Args[1] {
+ break
+ }
+ mem := l.Args[2]
+ if mem != v.Args[3] {
+ break
+ }
+ if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386XORLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386MOVSDconst_0(v *Value) bool {
@@ -10378,6 +11963,62 @@ func rewriteValue386_Op386MULL_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MULL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (MULLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MULL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (MULLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ l := v.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ x := v.Args[1]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386MULLconst_0(v *Value) bool {
@@ -10943,6 +12584,128 @@ func rewriteValue386_Op386MULLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MULLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MULLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MULLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (MULLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MULLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MULLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (MULLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MULLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (MULLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386MULLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386MULSD_0(v *Value) bool {
@@ -11473,6 +13236,62 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
_ = b
typ := &b.Func.Config.Types
_ = typ
+ // match: (ORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ORLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (ORLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ l := v.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ x := v.Args[1]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
// match: (ORL x x)
// cond:
// result: x
@@ -11943,6 +13762,11 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
v0.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValue386_Op386ORL_20(v *Value) bool {
+ b := v.Block
+ _ = b
// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
// cond: i1==i0+1 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
// result: @mergePoint(b,x0,x1) (MOVWloadidx1 [i0] {s} p idx mem)
@@ -12051,11 +13875,6 @@ func rewriteValue386_Op386ORL_10(v *Value) bool {
v0.AddArg(mem)
return true
}
- return false
-}
-func rewriteValue386_Op386ORL_20(v *Value) bool {
- b := v.Block
- _ = b
// match: (ORL x0:(MOVBloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} idx p mem)))
// cond: i1==i0+1 && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
// result: @mergePoint(b,x0,x1) (MOVWloadidx1 [i0] {s} p idx mem)
@@ -12578,6 +14397,11 @@ func rewriteValue386_Op386ORL_20(v *Value) bool {
v0.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValue386_Op386ORL_30(v *Value) bool {
+ b := v.Block
+ _ = b
// match: (ORL o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -12746,11 +14570,6 @@ func rewriteValue386_Op386ORL_20(v *Value) bool {
v0.AddArg(mem)
return true
}
- return false
-}
-func rewriteValue386_Op386ORL_30(v *Value) bool {
- b := v.Block
- _ = b
// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -13423,6 +15242,11 @@ func rewriteValue386_Op386ORL_30(v *Value) bool {
v0.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValue386_Op386ORL_40(v *Value) bool {
+ b := v.Block
+ _ = b
// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -13591,11 +15415,6 @@ func rewriteValue386_Op386ORL_30(v *Value) bool {
v0.AddArg(mem)
return true
}
- return false
-}
-func rewriteValue386_Op386ORL_40(v *Value) bool {
- b := v.Block
- _ = b
// match: (ORL o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem)) x0:(MOVWloadidx1 [i0] {s} idx p mem)) s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -14268,6 +16087,11 @@ func rewriteValue386_Op386ORL_40(v *Value) bool {
v0.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValue386_Op386ORL_50(v *Value) bool {
+ b := v.Block
+ _ = b
// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL x0:(MOVWloadidx1 [i0] {s} idx p mem) s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} idx p mem))))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -14436,11 +16260,6 @@ func rewriteValue386_Op386ORL_40(v *Value) bool {
v0.AddArg(mem)
return true
}
- return false
-}
-func rewriteValue386_Op386ORL_50(v *Value) bool {
- b := v.Block
- _ = b
// match: (ORL s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} idx p mem)) o0:(ORL s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)) x0:(MOVWloadidx1 [i0] {s} p idx mem)))
// cond: i2 == i0+2 && i3 == i0+3 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && o0.Uses == 1 && mergePoint(b,x0,x1,x2) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(s0) && clobber(s1) && clobber(o0)
// result: @mergePoint(b,x0,x1,x2) (MOVLloadidx1 [i0] {s} p idx mem)
@@ -15130,6 +16949,92 @@ func rewriteValue386_Op386ORLconstmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ORLconstmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ORLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2)
+ // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2)) {
+ break
+ }
+ v.reset(Op386ORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem)
+ // cond: ValAndOff(valoff1).canAdd(off2*4)
+ // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2 * 4)) {
+ break
+ }
+ v.reset(Op386ORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2 * 4)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386ORLload_0(v *Value) bool {
b := v.Block
_ = b
@@ -15188,6 +17093,128 @@ func rewriteValue386_Op386ORLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (ORLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (ORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ORLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ORLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ORLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ORLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386ORLmodify_0(v *Value) bool {
@@ -15250,6 +17277,124 @@ func rewriteValue386_Op386ORLmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386ORLmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (ORLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (ORLmodifyidx4 [off1+off2] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (ORLmodifyidx4 [off1+off2*4] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (ORLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386ORLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (ORLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem)
+ // cond: validValAndOff(c,off)
+ // result: (ORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386MOVLconst {
+ break
+ }
+ c := v_2.AuxInt
+ mem := v.Args[3]
+ if !(validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386ORLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386ROLBconst_0(v *Value) bool {
// match: (ROLBconst [c] (ROLBconst [d] x))
// cond:
@@ -16637,6 +18782,34 @@ func rewriteValue386_Op386SUBL_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (SUBL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (SUBLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386SUBLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
// match: (SUBL x x)
// cond:
// result: (MOVLconst [0])
@@ -16756,6 +18929,128 @@ func rewriteValue386_Op386SUBLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (SUBLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (SUBLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386SUBLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SUBLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (SUBLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (SUBLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386SUBLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (SUBLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (SUBLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386SUBLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (SUBLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (SUBLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386SUBLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386SUBLmodify_0(v *Value) bool {
@@ -16818,6 +19113,124 @@ func rewriteValue386_Op386SUBLmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386SUBLmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (SUBLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (SUBLmodifyidx4 [off1+off2] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386SUBLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (SUBLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (SUBLmodifyidx4 [off1+off2*4] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386SUBLmodifyidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (SUBLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (SUBLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386SUBLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (SUBLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem)
+ // cond: validValAndOff(-c,off)
+ // result: (ADDLconstmodifyidx4 [makeValAndOff(-c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386MOVLconst {
+ break
+ }
+ c := v_2.AuxInt
+ mem := v.Args[3]
+ if !(validValAndOff(-c, off)) {
+ break
+ }
+ v.reset(Op386ADDLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(-c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386SUBSD_0(v *Value) bool {
b := v.Block
_ = b
@@ -17258,6 +19671,62 @@ func rewriteValue386_Op386XORL_0(v *Value) bool {
return false
}
func rewriteValue386_Op386XORL_10(v *Value) bool {
+ // match: (XORL x l:(MOVLloadidx4 [off] {sym} ptr idx mem))
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (XORLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ x := v.Args[0]
+ l := v.Args[1]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORL l:(MOVLloadidx4 [off] {sym} ptr idx mem) x)
+ // cond: canMergeLoad(v, l, x) && clobber(l)
+ // result: (XORLloadidx4 x [off] {sym} ptr idx mem)
+ for {
+ _ = v.Args[1]
+ l := v.Args[0]
+ if l.Op != Op386MOVLloadidx4 {
+ break
+ }
+ off := l.AuxInt
+ sym := l.Aux
+ _ = l.Args[2]
+ ptr := l.Args[0]
+ idx := l.Args[1]
+ mem := l.Args[2]
+ x := v.Args[1]
+ if !(canMergeLoad(v, l, x) && clobber(l)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
// match: (XORL x x)
// cond:
// result: (MOVLconst [0])
@@ -17376,6 +19845,92 @@ func rewriteValue386_Op386XORLconstmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386XORLconstmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (XORLconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2)
+ // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2)) {
+ break
+ }
+ v.reset(Op386XORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem)
+ // cond: ValAndOff(valoff1).canAdd(off2*4)
+ // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2 * 4)) {
+ break
+ }
+ v.reset(Op386XORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2 * 4)
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
+ // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (XORLconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
+ for {
+ valoff1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386XORLconstmodifyidx4)
+ v.AuxInt = ValAndOff(valoff1).add(off2)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_Op386XORLload_0(v *Value) bool {
b := v.Block
_ = b
@@ -17434,6 +19989,128 @@ func rewriteValue386_Op386XORLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (XORLload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (XORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[2]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ _ = v_1.Args[1]
+ ptr := v_1.Args[0]
+ idx := v_1.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386XORLloadidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (XORLloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem)
+ // cond: is32Bit(off1+off2)
+ // result: (XORLloadidx4 [off1+off2] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (XORLloadidx4 [off1+off2*4] {sym} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ base := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_2.AuxInt
+ idx := v_2.Args[0]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (XORLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ val := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ base := v_1.Args[0]
+ idx := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386XORLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(val)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
return false
}
func rewriteValue386_Op386XORLmodify_0(v *Value) bool {
@@ -17496,6 +20173,124 @@ func rewriteValue386_Op386XORLmodify_0(v *Value) bool {
}
return false
}
+func rewriteValue386_Op386XORLmodifyidx4_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (XORLmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (XORLmodifyidx4 [off1+off2] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem)
+ // cond: is32Bit(off1+off2*4)
+ // result: (XORLmodifyidx4 [off1+off2*4] {sym} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ base := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2*4)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off1 + off2*4
+ v.Aux = sym
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (XORLmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ _ = v.Args[3]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386XORLmodifyidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (XORLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem)
+ // cond: validValAndOff(c,off)
+ // result: (XORLconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[3]
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386MOVLconst {
+ break
+ }
+ c := v_2.AuxInt
+ mem := v.Args[3]
+ if !(validValAndOff(c, off)) {
+ break
+ }
+ v.reset(Op386XORLconstmodifyidx4)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
func rewriteValue386_OpAdd16_0(v *Value) bool {
// match: (Add16 x y)
// cond:
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index 8f8ee75eec..4ed46b9c8c 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -508,6 +508,19 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.Op386ADDLloadidx4, ssa.Op386SUBLloadidx4, ssa.Op386MULLloadidx4,
+ ssa.Op386ANDLloadidx4, ssa.Op386ORLloadidx4, ssa.Op386XORLloadidx4:
+ p := s.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = v.Args[1].Reg()
+ p.From.Index = v.Args[2].Reg()
+ p.From.Scale = 4
+ gc.AddAux(&p.From, v)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
case ssa.Op386ADDLload, ssa.Op386SUBLload, ssa.Op386MULLload,
ssa.Op386ANDLload, ssa.Op386ORLload, ssa.Op386XORLload,
ssa.Op386ADDSDload, ssa.Op386ADDSSload, ssa.Op386SUBSDload, ssa.Op386SUBSSload,
@@ -557,7 +570,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = v.Args[0].Reg()
gc.AddAux2(&p.To, v, off)
case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1,
- ssa.Op386MOVSDstoreidx8, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4, ssa.Op386MOVWstoreidx2:
+ ssa.Op386MOVSDstoreidx8, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4, ssa.Op386MOVWstoreidx2,
+ ssa.Op386ADDLmodifyidx4, ssa.Op386SUBLmodifyidx4, ssa.Op386ANDLmodifyidx4, ssa.Op386ORLmodifyidx4, ssa.Op386XORLmodifyidx4:
r := v.Args[0].Reg()
i := v.Args[1].Reg()
p := s.Prog(v.Op.Asm())
@@ -572,7 +586,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Scale = 1
case ssa.Op386MOVSDstoreidx8:
p.To.Scale = 8
- case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
+ case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4,
+ ssa.Op386ADDLmodifyidx4, ssa.Op386SUBLmodifyidx4, ssa.Op386ANDLmodifyidx4, ssa.Op386ORLmodifyidx4, ssa.Op386XORLmodifyidx4:
p.To.Scale = 4
case ssa.Op386MOVWstoreidx2:
p.To.Scale = 2
@@ -588,7 +603,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux2(&p.To, v, sc.Off())
- case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1:
+ case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1,
+ ssa.Op386ADDLconstmodifyidx4, ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
sc := v.AuxValAndOff()
@@ -603,7 +619,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
}
case ssa.Op386MOVWstoreconstidx2:
p.To.Scale = 2
- case ssa.Op386MOVLstoreconstidx4:
+ case ssa.Op386MOVLstoreconstidx4,
+ ssa.Op386ADDLconstmodifyidx4, ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
p.To.Scale = 4
}
p.To.Type = obj.TYPE_MEM
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index 8e2a210948..0b209f5130 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -14,7 +14,8 @@ package codegen
// Subtraction //
// ----------------- //
-func SubMem(arr []int, b int) int {
+var ef int
+func SubMem(arr []int, b, c, d int) int {
// 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)`
// amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)`
arr[2] -= b
@@ -25,6 +26,12 @@ func SubMem(arr []int, b int) int {
arr[4]--
// 386:`ADDL\s[$]-20,\s20\([A-Z]+\)`
arr[5] -= 20
+ // 386:`SUBL\s\([A-Z]+\)\([A-Z]+\*4\),\s[A-Z]+`
+ ef -= arr[b]
+ // 386:`SUBL\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+\*4\)`
+ arr[c] -= b
+ // 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
+ arr[d] -= 15
// 386:"SUBL\t4"
// amd64:"SUBQ\t8"
return arr[0] - arr[1]
From ccc337d8eeedbf94f56adb7ab22ce009056d0973 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Mon, 8 Oct 2018 02:20:03 +0000
Subject: [PATCH 053/240] cmd/compile: combine similar code in amd64's assembly
generator
BSFQ/BSRQ/BSFL/BSRL/SQRTSD have similar logic in amd64's assembly
generator. This CL combines them together while does not impact
generated amd64 code. The total size of
pkg/linux_amd64/cmd/compile/internal decreases about 1.8KB.
Change-Id: I5f3210c5178c20ac9108877c69f17234baf5b6b7
Reviewed-on: https://go-review.googlesource.com/c/140438
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/amd64/ssa.go | 37 +++++++++++----------------
1 file changed, 15 insertions(+), 22 deletions(-)
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index b5e31e1601..f12e4cb5ec 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -782,14 +782,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// Break false dependency on destination register.
opregreg(s, x86.AXORPS, r, r)
opregreg(s, v.Op.Asm(), r, v.Args[0].Reg())
- case ssa.OpAMD64MOVQi2f, ssa.OpAMD64MOVQf2i:
- p := s.Prog(x86.AMOVQ)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[0].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.OpAMD64MOVLi2f, ssa.OpAMD64MOVLf2i:
- p := s.Prog(x86.AMOVL)
+ case ssa.OpAMD64MOVQi2f, ssa.OpAMD64MOVQf2i, ssa.OpAMD64MOVLi2f, ssa.OpAMD64MOVLf2i:
+ var p *obj.Prog
+ switch v.Op {
+ case ssa.OpAMD64MOVQi2f, ssa.OpAMD64MOVQf2i:
+ p = s.Prog(x86.AMOVQ)
+ case ssa.OpAMD64MOVLi2f, ssa.OpAMD64MOVLf2i:
+ p = s.Prog(x86.AMOVL)
+ }
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
@@ -934,24 +934,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ:
+ case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg0()
- case ssa.OpAMD64BSFL, ssa.OpAMD64BSRL:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[0].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
- case ssa.OpAMD64SQRTSD:
- p := s.Prog(v.Op.Asm())
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[0].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
+ switch v.Op {
+ case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ:
+ p.To.Reg = v.Reg0()
+ case ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD:
+ p.To.Reg = v.Reg()
+ }
case ssa.OpAMD64ROUNDSD:
p := s.Prog(v.Op.Asm())
val := v.AuxInt
From 465d1c61685db9e249d77db7d4ceca578f400b27 Mon Sep 17 00:00:00 2001
From: Marten Seemann
Date: Fri, 17 Aug 2018 18:03:55 +0700
Subject: [PATCH 054/240] crypto/tls: fix ServerHello SCT test
According to https://tools.ietf.org/html/rfc6962#section-3.3, the SCT
must be at least one byte long. The parsing code correctly checks for
this condition, but rarely the test does generate an empty SCT.
Change-Id: If36a34985b4470a5a9f96affc159195c04f6bfad
Reviewed-on: https://go-review.googlesource.com/c/129755
Reviewed-by: Filippo Valsorda
Reviewed-by: Brad Fitzpatrick
---
src/crypto/tls/handshake_messages_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index 37eb748eea..4a4a466768 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -188,7 +188,7 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
numSCTs := rand.Intn(4)
m.scts = make([][]byte, numSCTs)
for i := range m.scts {
- m.scts[i] = randomBytes(rand.Intn(500), rand)
+ m.scts[i] = randomBytes(rand.Intn(500)+1, rand)
}
}
From ffc7bc55f351976c9bb1e04aeba75397d40cbb53 Mon Sep 17 00:00:00 2001
From: Qais Patankar
Date: Tue, 9 Oct 2018 10:14:59 +0100
Subject: [PATCH 055/240] cmd/compile: fix Compiler Directives typo
Change-Id: I098b3c627c2142affd4e800a2c1f37e00f3775c5
Reviewed-on: https://go-review.googlesource.com/c/140777
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/doc.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go
index b68314cf73..3dc73a8fde 100644
--- a/src/cmd/compile/doc.go
+++ b/src/cmd/compile/doc.go
@@ -146,7 +146,7 @@ directive can skip over a directive like any other comment.
// will report positions in the original input to the generator.
/*
The line directive is an historical special case; all other directives are of the form
-//go:name and must start at the begnning of a line, indicating that the directive is defined
+//go:name and must start at the beginning of a line, indicating that the directive is defined
by the Go toolchain.
//go:noescape
From 5440bfc2ea8c0a4c78d5161605659c07ea10e37a Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick
Date: Tue, 25 Sep 2018 16:13:17 +0000
Subject: [PATCH 056/240] net/http/httputil: rewrite flushing code, disable on
Server-Sent Events
* Rewrite the flushing code to not use a persistent goroutine, which
also simplifies testing.
* Define the meaning of a negative flush interval. Its meaning doesn't
change, but now it's locked in, and then we can use it to optimize
the performance of the non-buffered case to avoid use of an AfterFunc.
* Support (internal-only) special casing of FlushInterval values per
request/response.
* For now, treat Server-Sent Event responses as unbuffered. (or rather,
immediately flushed from the buffer per-write)
Fixes #27816
Change-Id: Ie0f975c997daa3db539504137c741a96d7022665
Reviewed-on: https://go-review.googlesource.com/c/137335
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
Reviewed-by: Dmitri Shuralyov
---
src/net/http/httputil/reverseproxy.go | 89 ++++++++++++++--------
src/net/http/httputil/reverseproxy_test.go | 56 +++++++++++---
2 files changed, 102 insertions(+), 43 deletions(-)
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 1dddaa95a7..1efcbd3bbc 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -18,10 +18,6 @@ import (
"time"
)
-// onExitFlushLoop is a callback set by tests to detect the state of the
-// flushLoop() goroutine.
-var onExitFlushLoop func()
-
// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
@@ -42,6 +38,12 @@ type ReverseProxy struct {
// to flush to the client while copying the
// response body.
// If zero, no periodic flushing is done.
+ // A negative value means to flush immediately
+ // after each write to the client.
+ // The FlushInterval is ignored when ReverseProxy
+ // recognizes a response as a streaming response;
+ // for such reponses, writes are flushed to the client
+ // immediately.
FlushInterval time.Duration
// ErrorLog specifies an optional logger for errors
@@ -271,7 +273,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
fl.Flush()
}
}
- err = p.copyResponse(rw, res.Body)
+ err = p.copyResponse(rw, res.Body, p.flushInterval(req, res))
if err != nil {
defer res.Body.Close()
// Since we're streaming the response, if we run into an error all we can do
@@ -332,15 +334,28 @@ func removeConnectionHeaders(h http.Header) {
}
}
-func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) error {
- if p.FlushInterval != 0 {
+// flushInterval returns the p.FlushInterval value, conditionally
+// overriding its value for a specific request/response.
+func (p *ReverseProxy) flushInterval(req *http.Request, res *http.Response) time.Duration {
+ resCT := res.Header.Get("Content-Type")
+
+ // For Server-Sent Events responses, flush immediately.
+ // The MIME type is defined in https://www.w3.org/TR/eventsource/#text-event-stream
+ if resCT == "text/event-stream" {
+ return -1 // negative means immediately
+ }
+
+ // TODO: more specific cases? e.g. res.ContentLength == -1?
+ return p.FlushInterval
+}
+
+func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval time.Duration) error {
+ if flushInterval != 0 {
if wf, ok := dst.(writeFlusher); ok {
mlw := &maxLatencyWriter{
dst: wf,
- latency: p.FlushInterval,
- done: make(chan bool),
+ latency: flushInterval,
}
- go mlw.flushLoop()
defer mlw.stop()
dst = mlw
}
@@ -403,34 +418,44 @@ type writeFlusher interface {
type maxLatencyWriter struct {
dst writeFlusher
- latency time.Duration
+ latency time.Duration // non-zero; negative means to flush immediately
- mu sync.Mutex // protects Write + Flush
- done chan bool
+ mu sync.Mutex // protects t, flushPending, and dst.Flush
+ t *time.Timer
+ flushPending bool
}
-func (m *maxLatencyWriter) Write(p []byte) (int, error) {
+func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
m.mu.Lock()
defer m.mu.Unlock()
- return m.dst.Write(p)
+ n, err = m.dst.Write(p)
+ if m.latency < 0 {
+ m.dst.Flush()
+ return
+ }
+ if m.flushPending {
+ return
+ }
+ if m.t == nil {
+ m.t = time.AfterFunc(m.latency, m.delayedFlush)
+ } else {
+ m.t.Reset(m.latency)
+ }
+ m.flushPending = true
+ return
}
-func (m *maxLatencyWriter) flushLoop() {
- t := time.NewTicker(m.latency)
- defer t.Stop()
- for {
- select {
- case <-m.done:
- if onExitFlushLoop != nil {
- onExitFlushLoop()
- }
- return
- case <-t.C:
- m.mu.Lock()
- m.dst.Flush()
- m.mu.Unlock()
- }
+func (m *maxLatencyWriter) delayedFlush() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.dst.Flush()
+ m.flushPending = false
+}
+
+func (m *maxLatencyWriter) stop() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.t != nil {
+ m.t.Stop()
}
}
-
-func (m *maxLatencyWriter) stop() { m.done <- true }
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 2f75b4e34e..ddae11b168 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -297,10 +297,6 @@ func TestReverseProxyFlushInterval(t *testing.T) {
proxyHandler := NewSingleHostReverseProxy(backendURL)
proxyHandler.FlushInterval = time.Microsecond
- done := make(chan bool)
- onExitFlushLoop = func() { done <- true }
- defer func() { onExitFlushLoop = nil }()
-
frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
@@ -314,13 +310,6 @@ func TestReverseProxyFlushInterval(t *testing.T) {
if bodyBytes, _ := ioutil.ReadAll(res.Body); string(bodyBytes) != expected {
t.Errorf("got body %q; expected %q", bodyBytes, expected)
}
-
- select {
- case <-done:
- // OK
- case <-time.After(5 * time.Second):
- t.Error("maxLatencyWriter flushLoop() never exited")
- }
}
func TestReverseProxyCancelation(t *testing.T) {
@@ -946,3 +935,48 @@ func TestReverseProxy_PanicBodyError(t *testing.T) {
req, _ := http.NewRequest("GET", "http://foo.tld/", nil)
rproxy.ServeHTTP(httptest.NewRecorder(), req)
}
+
+func TestSelectFlushInterval(t *testing.T) {
+ tests := []struct {
+ name string
+ p *ReverseProxy
+ req *http.Request
+ res *http.Response
+ want time.Duration
+ }{
+ {
+ name: "default",
+ res: &http.Response{},
+ p: &ReverseProxy{FlushInterval: 123},
+ want: 123,
+ },
+ {
+ name: "server-sent events overrides non-zero",
+ res: &http.Response{
+ Header: http.Header{
+ "Content-Type": {"text/event-stream"},
+ },
+ },
+ p: &ReverseProxy{FlushInterval: 123},
+ want: -1,
+ },
+ {
+ name: "server-sent events overrides zero",
+ res: &http.Response{
+ Header: http.Header{
+ "Content-Type": {"text/event-stream"},
+ },
+ },
+ p: &ReverseProxy{FlushInterval: 0},
+ want: -1,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := tt.p.flushInterval(tt.req, tt.res)
+ if got != tt.want {
+ t.Errorf("flushLatency = %v; want %v", got, tt.want)
+ }
+ })
+ }
+}
From 3f86d7cc6762a5f6745cdcda4bd50031bfafc92f Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Tue, 25 Sep 2018 15:44:27 -0400
Subject: [PATCH 057/240] runtime: tidy mheap.freeSpan
freeSpan currently takes a mysterious "acct int32" argument. This is
really just a boolean and actually just needs to match the "large"
argument to alloc in order to balance out accounting.
To make this clearer, replace acct with a "large bool" argument that
must match the call to mheap.alloc.
Change-Id: Ibc81faefdf9f0583114e1953fcfb362e9c3c76de
Reviewed-on: https://go-review.googlesource.com/c/138655
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mcentral.go | 2 +-
src/runtime/mgcsweep.go | 2 +-
src/runtime/mheap.go | 8 ++++++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index 9ca8e5d222..baede31405 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -244,7 +244,7 @@ func (c *mcentral) freeSpan(s *mspan, preserve bool, wasempty bool) bool {
c.nonempty.remove(s)
unlock(&c.lock)
- mheap_.freeSpan(s, 0)
+ mheap_.freeSpan(s, false)
return true
}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 00950aede2..104bd868fa 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -366,7 +366,7 @@ func (s *mspan) sweep(preserve bool) bool {
s.limit = 0 // prevent mlookup from finding this span
sysFault(unsafe.Pointer(s.base()), size)
} else {
- mheap_.freeSpan(s, 1)
+ mheap_.freeSpan(s, true)
}
c.local_nlargefree++
c.local_largefree += size
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 1d672cdf21..48b3f5364a 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -945,7 +945,10 @@ func (h *mheap) grow(npage uintptr) bool {
}
// Free the span back into the heap.
-func (h *mheap) freeSpan(s *mspan, acct int32) {
+//
+// large must match the value of large passed to mheap.alloc. This is
+// used for accounting.
+func (h *mheap) freeSpan(s *mspan, large bool) {
systemstack(func() {
mp := getg().m
lock(&h.lock)
@@ -959,7 +962,8 @@ func (h *mheap) freeSpan(s *mspan, acct int32) {
bytes := s.npages << _PageShift
msanfree(base, bytes)
}
- if acct != 0 {
+ if large {
+ // Match accounting done in mheap.alloc.
memstats.heap_objects--
}
if gcBlackenEnabled != 0 {
From 1d09433ec072c2acff27335c2d05ce44bb501ecc Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Wed, 26 Sep 2018 15:36:28 -0400
Subject: [PATCH 058/240] runtime: undo manual inlining of mbits.setMarked
Since atomic.Or8 is now an intrinsic (and has been for some time),
markBits.setMarked is inlinable. Undo the manual inlining of it.
Change-Id: I8e37ccf0851ad1d3088d9c8ae0f6f0c439d7eb2d
Reviewed-on: https://go-review.googlesource.com/c/138659
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mbitmap.go | 4 +---
src/runtime/mgcmark.go | 3 +--
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 87fa027b4e..4854c0e632 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -283,9 +283,7 @@ func (m markBits) isMarked() bool {
return *m.bytep&m.mask != 0
}
-// setMarked sets the marked bit in the markbits, atomically. Some compilers
-// are not able to inline atomic.Or8 function so if it appears as a hot spot consider
-// inlining it manually.
+// setMarked sets the marked bit in the markbits, atomically.
func (m markBits) setMarked() {
// Might be racing with other updates, so use atomic update always.
// We used to be clever here and use a non-atomic update in certain
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index d4dcfb6cb9..14f09700ee 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -1228,8 +1228,7 @@ func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintp
if mbits.isMarked() {
return
}
- // mbits.setMarked() // Avoid extra call overhead with manual inlining.
- atomic.Or8(mbits.bytep, mbits.mask)
+ mbits.setMarked()
// If this is a noscan object, fast-track it to black
// instead of greying it.
if span.spanclass.noscan() {
From 7d2f46dacddba279c5b6b7520c7f6a475e6fffbc Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 8 Oct 2018 19:24:46 -0400
Subject: [PATCH 059/240] runtime: fix non-in-use span check
Lazy mcache flushing (golang.org/cl/134783) introduced a second value
for sweepgen that indicates a span has been swept. I missed adding
this case to a sanity check in sweepone, so it can now panic if it
finds a non-in-use spans that's been swept *and* put in an mcache.
Fix this by adding the second sweepgen case to this check.
Fixes #27997.
Change-Id: I568d9f2cc8923396ca897a37d154cd2c859c7bef
Reviewed-on: https://go-review.googlesource.com/c/140697
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mgcsweep.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 104bd868fa..b7528ab68f 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -101,7 +101,7 @@ func sweepone() uintptr {
// This can happen if direct sweeping already
// swept this span, but in that case the sweep
// generation should always be up-to-date.
- if s.sweepgen != sg {
+ if !(s.sweepgen == sg || s.sweepgen == sg+3) {
print("runtime: bad span s.state=", s.state, " s.sweepgen=", s.sweepgen, " sweepgen=", sg, "\n")
throw("non in-use span in unswept list")
}
From 70d7e96c7850d141ae48e99f02a397aed1bc474b Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Mon, 8 Oct 2018 13:51:10 -0400
Subject: [PATCH 060/240] runtime: avoid tracking spans with no objects with
mcentral
Lazy mcache flushing (golang.org/cl/134783) made it so that moving a
span from an mcache to an mcentral was sometimes responsible for
sweeping the span. However, it did a "preserving" sweep, which meant
it retained ownership, even if the sweeper swept all objects in the
span. As a result, we could put a completely unused span back in the
mcentral.
Fix this by first taking back ownership of the span into the mcentral
and moving it to the right mcentral list, and then doing a
non-preserving sweep. The non-preserving sweep will move the span to
the heap if it sweeps all objects.
Change-Id: I244b1893b44b8c00264f0928ac9239449775f617
Reviewed-on: https://go-review.googlesource.com/c/140597
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Michael Knyszek
---
src/runtime/mcentral.go | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index baede31405..d94b95792c 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -153,16 +153,6 @@ func (c *mcentral) uncacheSpan(s *mspan) {
throw("uncaching span but s.allocCount == 0")
}
- cap := int32((s.npages << _PageShift) / s.elemsize)
- n := cap - int32(s.allocCount)
-
- // cacheSpan updated alloc assuming all objects on s were
- // going to be allocated. Adjust for any that weren't. We must
- // do this before potentially sweeping the span.
- if n > 0 {
- atomic.Xadd64(&c.nmalloc, -int64(n))
- }
-
sg := mheap_.sweepgen
stale := s.sweepgen == sg+1
if stale {
@@ -170,18 +160,23 @@ func (c *mcentral) uncacheSpan(s *mspan) {
// responsibility to sweep it.
//
// Set sweepgen to indicate it's not cached but needs
- // sweeping. sweep will set s.sweepgen to indicate s
- // is swept.
- s.sweepgen = sg - 1
- s.sweep(true)
- // sweep may have freed objects, so recompute n.
- n = cap - int32(s.allocCount)
+ // sweeping and can't be allocated from. sweep will
+ // set s.sweepgen to indicate s is swept.
+ atomic.Store(&s.sweepgen, sg-1)
} else {
// Indicate that s is no longer cached.
- s.sweepgen = sg
+ atomic.Store(&s.sweepgen, sg)
}
+ cap := int32((s.npages << _PageShift) / s.elemsize)
+ n := cap - int32(s.allocCount)
if n > 0 {
+ // cacheSpan updated alloc assuming all objects on s
+ // were going to be allocated. Adjust for any that
+ // weren't. We must do this before potentially
+ // sweeping the span.
+ atomic.Xadd64(&c.nmalloc, -int64(n))
+
lock(&c.lock)
c.empty.remove(s)
c.nonempty.insert(s)
@@ -197,6 +192,12 @@ func (c *mcentral) uncacheSpan(s *mspan) {
}
unlock(&c.lock)
}
+
+ if stale {
+ // Now that s is in the right mcentral list, we can
+ // sweep it.
+ s.sweep(false)
+ }
}
// freeSpan updates c and s after sweeping s.
From 416804f3e24b25cf3e291fbbe5857cc28644a852 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Tue, 25 Sep 2018 17:24:30 -0400
Subject: [PATCH 061/240] runtime: simplify free count calculation in
(un)cacheSpan
For unclear reasons, cacheSpan and uncacheSpan compute the number of
elements in a span by dividing its size by the element size. This
number is simply available in the mspan structure, so just use it.
Change-Id: If2e5de6ecec39befd3324bf1da4a275ad000932f
Reviewed-on: https://go-review.googlesource.com/c/138656
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mcentral.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index d94b95792c..d9bc8b4719 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -117,8 +117,7 @@ havespan:
if trace.enabled && !traceDone {
traceGCSweepDone()
}
- cap := int32((s.npages << _PageShift) / s.elemsize)
- n := cap - int32(s.allocCount)
+ n := int(s.nelems) - int(s.allocCount)
if n == 0 || s.freeindex == s.nelems || uintptr(s.allocCount) == s.nelems {
throw("span has no free objects")
}
@@ -168,8 +167,7 @@ func (c *mcentral) uncacheSpan(s *mspan) {
atomic.Store(&s.sweepgen, sg)
}
- cap := int32((s.npages << _PageShift) / s.elemsize)
- n := cap - int32(s.allocCount)
+ n := int(s.nelems) - int(s.allocCount)
if n > 0 {
// cacheSpan updated alloc assuming all objects on s
// were going to be allocated. Adjust for any that
From f3bb4cbfd5a02b14a8660aa7e6a08801bcb9fbaf Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Tue, 25 Sep 2018 17:32:03 -0400
Subject: [PATCH 062/240] runtime: eliminate gosweepone
gosweepone just switches to the system stack and calls sweepone.
sweepone doesn't need to run on the system stack, so this is pretty
pointless.
Historically, this was necessary because the sweeper was written in C
and hence needed to run on the system stack. gosweepone was the
function that Go code (specifically, bgsweep) used to call into the C
sweeper implementation. This probably became unnecessary in 2014 with
CL golang.org/cl/167540043, which ported the sweeper to Go.
This CL changes all callers of gosweepone to call sweepone and
eliminates gosweepone.
Change-Id: I26b8ef0c7d060b4c0c5dedbb25ecfc936acc7269
Reviewed-on: https://go-review.googlesource.com/c/138657
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mgc.go | 4 ++--
src/runtime/mgcsweep.go | 18 ++++--------------
2 files changed, 6 insertions(+), 16 deletions(-)
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 2c6af43da5..9a35c7671f 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -1061,7 +1061,7 @@ func GC() {
// complete the cycle and because runtime.GC() is often used
// as part of tests and benchmarks to get the system into a
// relatively stable and isolated state.
- for atomic.Load(&work.cycles) == n+1 && gosweepone() != ^uintptr(0) {
+ for atomic.Load(&work.cycles) == n+1 && sweepone() != ^uintptr(0) {
sweep.nbgsweep++
Gosched()
}
@@ -1219,7 +1219,7 @@ func gcStart(trigger gcTrigger) {
//
// We check the transition condition continuously here in case
// this G gets delayed in to the next GC cycle.
- for trigger.test() && gosweepone() != ^uintptr(0) {
+ for trigger.test() && sweepone() != ^uintptr(0) {
sweep.nbgsweep++
}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index b7528ab68f..35b717ca9b 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -52,7 +52,7 @@ func bgsweep(c chan int) {
goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
for {
- for gosweepone() != ^uintptr(0) {
+ for sweepone() != ^uintptr(0) {
sweep.nbgsweep++
Gosched()
}
@@ -72,9 +72,8 @@ func bgsweep(c chan int) {
}
}
-// sweeps one span
-// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep
-//go:nowritebarrier
+// sweepone sweeps one span and returns the number of pages returned
+// to the heap, or ^uintptr(0) if there was nothing to sweep.
func sweepone() uintptr {
_g_ := getg()
sweepRatio := mheap_.sweepPagesPerByte // For debugging
@@ -135,15 +134,6 @@ func sweepone() uintptr {
return npages
}
-//go:nowritebarrier
-func gosweepone() uintptr {
- var ret uintptr
- systemstack(func() {
- ret = sweepone()
- })
- return ret
-}
-
//go:nowritebarrier
func gosweepdone() bool {
return mheap_.sweepdone != 0
@@ -414,7 +404,7 @@ retry:
newHeapLive := uintptr(atomic.Load64(&memstats.heap_live)-mheap_.sweepHeapLiveBasis) + spanBytes
pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages)
for pagesTarget > int64(atomic.Load64(&mheap_.pagesSwept)-sweptBasis) {
- if gosweepone() == ^uintptr(0) {
+ if sweepone() == ^uintptr(0) {
mheap_.sweepPagesPerByte = 0
break
}
From 007e8a2fbda83e8863f7dda5632a100928318019 Mon Sep 17 00:00:00 2001
From: Austin Clements
Date: Tue, 25 Sep 2018 17:41:11 -0400
Subject: [PATCH 063/240] runtime: rename gosweepdone to isSweepDone and
document better
gosweepdone is another anachronism from the time when the sweeper was
implemented in C. Rename it to "isSweepDone" for the modern era.
Change-Id: I8472aa6f52478459c3f2edc8a4b2761e73c4c2dd
Reviewed-on: https://go-review.googlesource.com/c/138658
Run-TryBot: Austin Clements
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/runtime/mgc.go | 4 ++--
src/runtime/mgcsweep.go | 11 ++++++++---
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 9a35c7671f..e12df7f7d2 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -789,7 +789,7 @@ func gcSetTriggerRatio(triggerRatio float64) {
trigger = uint64(float64(memstats.heap_marked) * (1 + triggerRatio))
// Don't trigger below the minimum heap size.
minTrigger := heapminimum
- if !gosweepdone() {
+ if !isSweepDone() {
// Concurrent sweep happens in the heap growth
// from heap_live to gc_trigger, so ensure
// that concurrent sweep has some heap growth
@@ -834,7 +834,7 @@ func gcSetTriggerRatio(triggerRatio float64) {
}
// Update sweep pacing.
- if gosweepdone() {
+ if isSweepDone() {
mheap_.sweepPagesPerByte = 0
} else {
// Concurrent sweep needs to sweep all of the in-use
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 35b717ca9b..627a6a023f 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -60,7 +60,7 @@ func bgsweep(c chan int) {
Gosched()
}
lock(&sweep.lock)
- if !gosweepdone() {
+ if !isSweepDone() {
// This can happen if a GC runs between
// gosweepone returning ^0 above
// and the lock being acquired.
@@ -134,8 +134,13 @@ func sweepone() uintptr {
return npages
}
-//go:nowritebarrier
-func gosweepdone() bool {
+// isSweepDone reports whether all spans are swept or currently being swept.
+//
+// Note that this condition may transition from false to true at any
+// time as the sweeper runs. It may transition from true to false if a
+// GC runs; to prevent that the caller must be non-preemptible or must
+// somehow block GC progress.
+func isSweepDone() bool {
return mheap_.sweepdone != 0
}
From d30d5a6b1e86e1bb62e159ffe8b8c698c04e945b Mon Sep 17 00:00:00 2001
From: Muhammad Falak R Wani
Date: Sat, 6 Oct 2018 19:16:28 +0530
Subject: [PATCH 064/240] go/doc: skip examples with no body
Fixes #28044
Change-Id: I0052e078dd34dc3546204416bcc5a99e3146c535
Reviewed-on: https://go-review.googlesource.com/c/140317
Run-TryBot: Dmitri Shuralyov
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/go/doc/example.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/go/doc/example.go b/src/go/doc/example.go
index 5b40bb0fb2..d6d4ece3a8 100644
--- a/src/go/doc/example.go
+++ b/src/go/doc/example.go
@@ -68,6 +68,9 @@ func Examples(files ...*ast.File) []*Example {
if !isTest(name, "Example") {
continue
}
+ if f.Body == nil { // ast.File.Body nil dereference (see issue 28044)
+ continue
+ }
var doc string
if f.Doc != nil {
doc = f.Doc.Text()
From 48dc42b6afe7ad13102c55b8200c9f4577a88c84 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Thu, 4 Oct 2018 16:49:53 -0700
Subject: [PATCH 065/240] cmd/compile/internal/gc: major evconst cleanup
Major cleanup to structure the code more similarly to go/constant.
Passes "toolstash -cmp" on std cmd.
Change-Id: I3ec7a7a24e313f119b0da4095001aad02e317894
Reviewed-on: https://go-review.googlesource.com/c/139901
Run-TryBot: Matthew Dempsky
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/const.go | 867 ++++++++++-----------------
1 file changed, 310 insertions(+), 557 deletions(-)
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index effed1f4ac..e60e05df04 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -40,7 +40,7 @@ func (v Val) Ctype() Ctype {
switch x := v.U.(type) {
default:
Fatalf("unexpected Ctype for %T", v.U)
- panic("not reached")
+ panic("unreachable")
case nil:
return 0
case *NilVal:
@@ -68,7 +68,7 @@ func eqval(a, b Val) bool {
switch x := a.U.(type) {
default:
Fatalf("unexpected Ctype for %T", a.U)
- panic("not reached")
+ panic("unreachable")
case *NilVal:
return true
case bool:
@@ -96,7 +96,7 @@ func (v Val) Interface() interface{} {
switch x := v.U.(type) {
default:
Fatalf("unexpected Interface for %T", v.U)
- panic("not reached")
+ panic("unreachable")
case *NilVal:
return nil
case bool, string:
@@ -424,29 +424,6 @@ bad:
return n
}
-func copyval(v Val) Val {
- switch u := v.U.(type) {
- case *Mpint:
- i := new(Mpint)
- i.Set(u)
- i.Rune = u.Rune
- v.U = i
-
- case *Mpflt:
- f := newMpflt()
- f.Set(u)
- v.U = f
-
- case *Mpcplx:
- c := new(Mpcplx)
- c.Real.Set(&u.Real)
- c.Imag.Set(&u.Imag)
- v.U = c
- }
-
- return v
-}
-
func tocplx(v Val) Val {
switch u := v.U.(type) {
case *Mpint:
@@ -585,10 +562,6 @@ func tostr(v Val) Val {
i = u.Int64()
}
v.U = string(i)
-
- case *NilVal:
- // Can happen because of string([]byte(nil)).
- v.U = ""
}
return v
@@ -609,50 +582,55 @@ func Isconst(n *Node, ct Ctype) bool {
return t == ct || (ct == CTINT && t == CTRUNE)
}
-// if n is constant, rewrite as OLITERAL node.
+// evconst rewrites constant expressions into OLITERAL nodes.
func evconst(n *Node) {
- // pick off just the opcodes that can be
- // constant evaluated.
- switch n.Op {
- default:
- return
+ nl, nr := n.Left, n.Right
- case OADD,
- OAND,
- OANDAND,
- OANDNOT,
- OARRAYBYTESTR,
- OCOM,
- ODIV,
- OEQ,
- OGE,
- OGT,
- OLE,
- OLSH,
- OLT,
- OMINUS,
- OMOD,
- OMUL,
- ONE,
- ONOT,
- OOR,
- OOROR,
- OPLUS,
- ORSH,
- OSUB,
- OXOR:
- break
+ // Pick off just the opcodes that can be constant evaluated.
+ switch op := n.Op; op {
+ case OPLUS, OMINUS, OCOM, ONOT:
+ if nl.Op == OLITERAL {
+ setconst(n, unaryOp(op, nl.Val(), n.Type))
+ }
+
+ case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, binaryOp(nl.Val(), op, nr.Val()))
+ }
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ if nl.Type.IsInterface() != nr.Type.IsInterface() {
+ // Mixed interface/non-interface
+ // constant comparison means comparing
+ // nil interface with some typed
+ // constant, which is always unequal.
+ // E.g., interface{}(nil) == (*int)(nil).
+ setboolconst(n, op == ONE)
+ } else {
+ setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
+ }
+ }
+
+ case OLSH, ORSH:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, shiftOp(nl.Val(), op, nr.Val()))
+ }
case OCONV:
- if n.Type == nil {
- return
- }
- if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
- return
+ if n.Type != nil && okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ // TODO(mdempsky): There should be a convval function.
+ setconst(n, convlit1(nl, n.Type, true, false).Val())
+ }
+
+ case OARRAYBYTESTR:
+ // string([]byte(nil)) or string([]rune(nil))
+ if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL {
+ setconst(n, Val{U: ""})
}
- // merge adjacent constants in the argument list.
case OADDSTR:
+ // Merge adjacent constants in the argument list.
s := n.List.Slice()
for i1 := 0; i1 < len(s); i1++ {
if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
@@ -678,521 +656,292 @@ func evconst(n *Node) {
} else {
n.List.Set(s)
}
+ }
+}
- return
+func match(x, y Val) (Val, Val) {
+ switch {
+ case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
+ return tocplx(x), tocplx(y)
+ case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
+ return toflt(x), toflt(y)
}
- nl := n.Left
- if nl == nil || nl.Type == nil {
- return
- }
- if consttype(nl) == 0 {
- return
- }
- wl := nl.Type.Etype
- if isInt[wl] || isFloat[wl] || isComplex[wl] {
- wl = TIDEAL
- }
+ // Mixed int/rune are fine.
+ return x, y
+}
- // avoid constant conversions in switches below
- const (
- CTINT_ = uint32(CTINT)
- CTRUNE_ = uint32(CTRUNE)
- CTFLT_ = uint32(CTFLT)
- CTCPLX_ = uint32(CTCPLX)
- CTSTR_ = uint32(CTSTR)
- CTBOOL_ = uint32(CTBOOL)
- CTNIL_ = uint32(CTNIL)
- OCONV_ = uint32(OCONV) << 16
- OARRAYBYTESTR_ = uint32(OARRAYBYTESTR) << 16
- OPLUS_ = uint32(OPLUS) << 16
- OMINUS_ = uint32(OMINUS) << 16
- OCOM_ = uint32(OCOM) << 16
- ONOT_ = uint32(ONOT) << 16
- OLSH_ = uint32(OLSH) << 16
- ORSH_ = uint32(ORSH) << 16
- OADD_ = uint32(OADD) << 16
- OSUB_ = uint32(OSUB) << 16
- OMUL_ = uint32(OMUL) << 16
- ODIV_ = uint32(ODIV) << 16
- OMOD_ = uint32(OMOD) << 16
- OOR_ = uint32(OOR) << 16
- OAND_ = uint32(OAND) << 16
- OANDNOT_ = uint32(OANDNOT) << 16
- OXOR_ = uint32(OXOR) << 16
- OEQ_ = uint32(OEQ) << 16
- ONE_ = uint32(ONE) << 16
- OLT_ = uint32(OLT) << 16
- OLE_ = uint32(OLE) << 16
- OGE_ = uint32(OGE) << 16
- OGT_ = uint32(OGT) << 16
- OOROR_ = uint32(OOROR) << 16
- OANDAND_ = uint32(OANDAND) << 16
- )
+func compareOp(x Val, op Op, y Val) bool {
+ x, y = match(x, y)
- nr := n.Right
- var rv Val
- var wr types.EType
- var ctype uint32
- var v Val
- if nr == nil {
- // copy numeric value to avoid modifying
- // nl, in case someone still refers to it (e.g. iota).
- v = copyval(nl.Val())
-
- // rune values are int values for the purpose of constant folding.
- ctype = uint32(v.Ctype())
- if ctype == CTRUNE_ {
- ctype = CTINT_
+ switch x.Ctype() {
+ case CTNIL:
+ _, _ = x.U.(*NilVal), y.U.(*NilVal) // assert dynamic types match
+ switch op {
+ case OEQ:
+ return true
+ case ONE:
+ return false
}
- switch uint32(n.Op)<<16 | ctype {
- default:
- if !n.Diag() {
- yyerror("illegal constant expression %v %v", n.Op, nl.Type)
- n.SetDiag(true)
- }
- return
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
+ }
- case OCONV_ | CTNIL_,
- OARRAYBYTESTR_ | CTNIL_:
- if n.Type.IsString() {
- v = tostr(v)
- nl.Type = n.Type
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+ return cmpZero(x.Cmp(y), op)
+
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
+ return cmpZero(x.Cmp(y), op)
+
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
+ eq := x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
+ switch op {
+ case OEQ:
+ return eq
+ case ONE:
+ return !eq
+ }
+
+ case CTSTR:
+ x, y := x.U.(string), y.U.(string)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
+ case OLT:
+ return x < y
+ case OLE:
+ return x <= y
+ case OGT:
+ return x > y
+ case OGE:
+ return x >= y
+ }
+ }
+
+ Fatalf("compareOp: bad comparison: %v %v %v", x, op, y)
+ panic("unreachable")
+}
+
+func cmpZero(x int, op Op) bool {
+ switch op {
+ case OEQ:
+ return x == 0
+ case ONE:
+ return x != 0
+ case OLT:
+ return x < 0
+ case OLE:
+ return x <= 0
+ case OGT:
+ return x > 0
+ case OGE:
+ return x >= 0
+ }
+
+ Fatalf("cmpZero: want comparison operator, got %v", op)
+ panic("unreachable")
+}
+
+func binaryOp(x Val, op Op, y Val) Val {
+ x, y = match(x, y)
+
+Outer:
+ switch x.Ctype() {
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OANDAND:
+ return Val{U: x && y}
+ case OOROR:
+ return Val{U: x || y}
+ }
+
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune || y.Rune
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ u.SetOverflow()
break
}
- fallthrough
- case OCONV_ | CTINT_,
- OCONV_ | CTFLT_,
- OCONV_ | CTCPLX_,
- OCONV_ | CTSTR_,
- OCONV_ | CTBOOL_:
- nl = convlit1(nl, n.Type, true, false)
- v = nl.Val()
-
- case OPLUS_ | CTINT_:
- break
-
- case OMINUS_ | CTINT_:
- v.U.(*Mpint).Neg()
-
- case OCOM_ | CTINT_:
- et := Txxx
- if nl.Type != nil {
- et = nl.Type.Etype
+ u.Quo(y)
+ case OMOD:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ u.SetOverflow()
+ break
}
+ u.Rem(y)
+ case OOR:
+ u.Or(y)
+ case OAND:
+ u.And(y)
+ case OANDNOT:
+ u.AndNot(y)
+ case OXOR:
+ u.Xor(y)
+ default:
+ break Outer
+ }
+ return Val{U: u}
- // calculate the mask in b
- // result will be (a ^ mask)
- var b Mpint
- switch et {
- // signed guys change sign
- default:
- b.SetInt64(-1)
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
- // unsigned guys invert their bits
- case TUINT8,
- TUINT16,
- TUINT32,
- TUINT64,
- TUINT,
- TUINTPTR:
- b.Set(maxintval[et])
+ u := newMpflt()
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpFloat64(0) == 0 {
+ yyerror("division by zero")
+ u.SetFloat64(1)
+ break
}
-
- v.U.(*Mpint).Xor(&b)
-
- case OPLUS_ | CTFLT_:
- break
-
- case OMINUS_ | CTFLT_:
- v.U.(*Mpflt).Neg()
-
- case OPLUS_ | CTCPLX_:
- break
-
- case OMINUS_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Neg()
- v.U.(*Mpcplx).Imag.Neg()
-
- case ONOT_ | CTBOOL_:
- if !v.U.(bool) {
- goto settrue
- }
- goto setfalse
- }
- goto ret
- }
- if nr.Type == nil {
- return
- }
- if consttype(nr) == 0 {
- return
- }
- wr = nr.Type.Etype
- if isInt[wr] || isFloat[wr] || isComplex[wr] {
- wr = TIDEAL
- }
-
- // check for compatible general types (numeric, string, etc)
- if wl != wr {
- if wl == TINTER || wr == TINTER {
- if n.Op == ONE {
- goto settrue
- }
- goto setfalse
- }
- goto illegal
- }
-
- // check for compatible types.
- switch n.Op {
- // ideal const mixes with anything but otherwise must match.
- default:
- if nl.Type.Etype != TIDEAL {
- nr = defaultlit(nr, nl.Type)
- n.Right = nr
- }
-
- if nr.Type.Etype != TIDEAL {
- nl = defaultlit(nl, nr.Type)
- n.Left = nl
- }
-
- if nl.Type.Etype != nr.Type.Etype {
- goto illegal
- }
-
- // right must be unsigned.
- // left can be ideal.
- case OLSH, ORSH:
- nr = defaultlit(nr, types.Types[TUINT])
-
- n.Right = nr
- if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) {
- goto illegal
- }
- if nl.Val().Ctype() != CTRUNE {
- nl.SetVal(toint(nl.Val()))
- }
- nr.SetVal(toint(nr.Val()))
- }
-
- // copy numeric value to avoid modifying
- // n->left, in case someone still refers to it (e.g. iota).
- v = copyval(nl.Val())
- rv = nr.Val()
-
- // convert to common ideal
- if v.Ctype() == CTCPLX || rv.Ctype() == CTCPLX {
- v = tocplx(v)
- rv = tocplx(rv)
- }
-
- if v.Ctype() == CTFLT || rv.Ctype() == CTFLT {
- v = toflt(v)
- rv = toflt(rv)
- }
-
- // Rune and int turns into rune.
- if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
- i := new(Mpint)
- i.Set(rv.U.(*Mpint))
- i.Rune = true
- rv.U = i
- }
- if v.Ctype() == CTINT && rv.Ctype() == CTRUNE {
- if n.Op == OLSH || n.Op == ORSH {
- i := new(Mpint)
- i.Set(rv.U.(*Mpint))
- rv.U = i
- } else {
- i := new(Mpint)
- i.Set(v.U.(*Mpint))
- i.Rune = true
- v.U = i
- }
- }
-
- if v.Ctype() != rv.Ctype() {
- // Use of undefined name as constant?
- if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
- return
- }
- Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
- }
-
- // rune values are int values for the purpose of constant folding.
- ctype = uint32(v.Ctype())
- if ctype == CTRUNE_ {
- ctype = CTINT_
- }
-
- // run op
- switch uint32(n.Op)<<16 | ctype {
- default:
- goto illegal
-
- case OADD_ | CTINT_:
- v.U.(*Mpint).Add(rv.U.(*Mpint))
-
- case OSUB_ | CTINT_:
- v.U.(*Mpint).Sub(rv.U.(*Mpint))
-
- case OMUL_ | CTINT_:
- v.U.(*Mpint).Mul(rv.U.(*Mpint))
-
- case ODIV_ | CTINT_:
- if rv.U.(*Mpint).CmpInt64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpint).SetOverflow()
- break
- }
-
- v.U.(*Mpint).Quo(rv.U.(*Mpint))
-
- case OMOD_ | CTINT_:
- if rv.U.(*Mpint).CmpInt64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpint).SetOverflow()
- break
- }
-
- v.U.(*Mpint).Rem(rv.U.(*Mpint))
-
- case OLSH_ | CTINT_:
- v.U.(*Mpint).Lsh(rv.U.(*Mpint))
-
- case ORSH_ | CTINT_:
- v.U.(*Mpint).Rsh(rv.U.(*Mpint))
-
- case OOR_ | CTINT_:
- v.U.(*Mpint).Or(rv.U.(*Mpint))
-
- case OAND_ | CTINT_:
- v.U.(*Mpint).And(rv.U.(*Mpint))
-
- case OANDNOT_ | CTINT_:
- v.U.(*Mpint).AndNot(rv.U.(*Mpint))
-
- case OXOR_ | CTINT_:
- v.U.(*Mpint).Xor(rv.U.(*Mpint))
-
- case OADD_ | CTFLT_:
- v.U.(*Mpflt).Add(rv.U.(*Mpflt))
-
- case OSUB_ | CTFLT_:
- v.U.(*Mpflt).Sub(rv.U.(*Mpflt))
-
- case OMUL_ | CTFLT_:
- v.U.(*Mpflt).Mul(rv.U.(*Mpflt))
-
- case ODIV_ | CTFLT_:
- if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpflt).SetFloat64(1.0)
- break
- }
-
- v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
-
- // The default case above would print 'ideal % ideal',
- // which is not quite an ideal error.
- case OMOD_ | CTFLT_:
- if !n.Diag() {
+ u.Quo(y)
+ case OMOD:
+ // TODO(mdempsky): Move to typecheck.
yyerror("illegal constant expression: floating-point %% operation")
- n.SetDiag(true)
+ default:
+ break Outer
}
+ return Val{U: u}
- return
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
- case OADD_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Add(&rv.U.(*Mpcplx).Real)
- v.U.(*Mpcplx).Imag.Add(&rv.U.(*Mpcplx).Imag)
-
- case OSUB_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Sub(&rv.U.(*Mpcplx).Real)
- v.U.(*Mpcplx).Imag.Sub(&rv.U.(*Mpcplx).Imag)
-
- case OMUL_ | CTCPLX_:
- v.U.(*Mpcplx).Mul(rv.U.(*Mpcplx))
-
- case ODIV_ | CTCPLX_:
- if !v.U.(*Mpcplx).Div(rv.U.(*Mpcplx)) {
- yyerror("complex division by zero")
- rv.U.(*Mpcplx).Real.SetFloat64(1.0)
- rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
- break
+ u := new(Mpcplx)
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ switch op {
+ case OADD:
+ u.Real.Add(&y.Real)
+ u.Imag.Add(&y.Imag)
+ case OSUB:
+ u.Real.Sub(&y.Real)
+ u.Imag.Sub(&y.Imag)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if !u.Div(y) {
+ yyerror("complex division by zero")
+ u.Real.SetFloat64(1)
+ u.Imag.SetFloat64(0)
+ }
+ default:
+ break Outer
}
-
- case OEQ_ | CTNIL_:
- goto settrue
-
- case ONE_ | CTNIL_:
- goto setfalse
-
- case OEQ_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) > 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) < 0 {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) <= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) >= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) > 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTCPLX_:
- if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) == 0 && v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTCPLX_:
- if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) != 0 || v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTSTR_:
- if strlit(nl) == strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTSTR_:
- if strlit(nl) != strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTSTR_:
- if strlit(nl) < strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTSTR_:
- if strlit(nl) <= strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTSTR_:
- if strlit(nl) >= strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTSTR_:
- if strlit(nl) > strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OOROR_ | CTBOOL_:
- if v.U.(bool) || rv.U.(bool) {
- goto settrue
- }
- goto setfalse
-
- case OANDAND_ | CTBOOL_:
- if v.U.(bool) && rv.U.(bool) {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTBOOL_:
- if v.U.(bool) == rv.U.(bool) {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTBOOL_:
- if v.U.(bool) != rv.U.(bool) {
- goto settrue
- }
- goto setfalse
+ return Val{U: u}
}
-ret:
- setconst(n, v)
- return
+ Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
+ panic("unreachable")
+}
-settrue:
- setconst(n, Val{true})
- return
+func unaryOp(op Op, x Val, t *types.Type) Val {
+ switch op {
+ case OPLUS:
+ switch x.Ctype() {
+ case CTINT, CTRUNE, CTFLT, CTCPLX:
+ return x
+ }
-setfalse:
- setconst(n, Val{false})
- return
+ case OMINUS:
+ switch x.Ctype() {
+ case CTINT, CTRUNE:
+ x := x.U.(*Mpint)
+ u := new(Mpint)
+ u.Rune = x.Rune
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
-illegal:
- if !n.Diag() {
- yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
- n.SetDiag(true)
+ case CTFLT:
+ x := x.U.(*Mpflt)
+ u := newMpflt()
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
+
+ case CTCPLX:
+ x := x.U.(*Mpcplx)
+ u := new(Mpcplx)
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ u.Real.Neg()
+ u.Imag.Neg()
+ return Val{U: u}
+ }
+
+ case OCOM:
+ x := x.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune
+ if t.IsSigned() || t.IsUntyped() {
+ // Signed values change sign.
+ u.SetInt64(-1)
+ } else {
+ // Unsigned values invert their bits.
+ u.Set(maxintval[t.Etype])
+ }
+ u.Xor(x)
+ return Val{U: u}
+
+ case ONOT:
+ return Val{U: !x.U.(bool)}
}
+
+ Fatalf("unaryOp: bad operation: %v %v", op, x)
+ panic("unreachable")
+}
+
+func shiftOp(x Val, op Op, y Val) Val {
+ if x.Ctype() != CTRUNE {
+ x = toint(x)
+ }
+ y = toint(y)
+
+ u := new(Mpint)
+ u.Set(x.U.(*Mpint))
+ u.Rune = x.U.(*Mpint).Rune
+ switch op {
+ case OLSH:
+ u.Lsh(y.U.(*Mpint))
+ case ORSH:
+ u.Rsh(y.U.(*Mpint))
+ default:
+ Fatalf("shiftOp: bad operator: %v", op)
+ panic("unreachable")
+ }
+ return Val{U: u}
}
// setconst rewrites n as an OLITERAL with value v.
@@ -1223,6 +972,10 @@ func setconst(n *Node, v Val) {
}
}
+func setboolconst(n *Node, v bool) {
+ setconst(n, Val{U: v})
+}
+
func setintconst(n *Node, v int64) {
u := new(Mpint)
u.SetInt64(v)
From 6c85693bf14e246e5a53466048329cb7571a674c Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Tue, 9 Oct 2018 09:50:56 -0400
Subject: [PATCH 066/240] cmd/go: check that package paths are invariantly
non-empty
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The empty string is never a valid package path.
Passing an empty string to a function that expects a package path
indicates some missing validation step further up the call chain —
typically (and most easily) a missed error check.
Change-Id: I78a2403d95b473bacb0d40814cd9d477ecfd5351
Reviewed-on: https://go-review.googlesource.com/c/140857
Run-TryBot: Bryan C. Mills
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/go/internal/load/pkg.go | 10 ++++++++++
src/cmd/go/internal/modload/build.go | 3 +++
src/cmd/go/internal/modload/load.go | 3 +++
3 files changed, 16 insertions(+)
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index ec2fa730c6..3d1b0e649d 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -440,6 +440,10 @@ const (
// this package, as part of a bigger load operation, and by GOPATH-based "go get".
// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
+ if path == "" {
+ panic("LoadImport called with empty package path")
+ }
+
stk.Push(path)
defer stk.Pop()
@@ -1750,6 +1754,9 @@ func LoadPackageNoFlags(arg string, stk *ImportStack) *Package {
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *ImportStack) *Package {
+ if arg == "" {
+ panic("loadPackage called with empty package path")
+ }
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
@@ -1848,6 +1855,9 @@ func PackagesAndErrors(patterns []string) []*Package {
for _, m := range matches {
for _, pkg := range m.Pkgs {
+ if pkg == "" {
+ panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern))
+ }
p := loadPackage(pkg, &stk)
p.Match = append(p.Match, m.Pattern)
p.Internal.CmdlinePkg = true
diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go
index acee4a91e7..4e7741c5fb 100644
--- a/src/cmd/go/internal/modload/build.go
+++ b/src/cmd/go/internal/modload/build.go
@@ -30,6 +30,9 @@ func isStandardImportPath(path string) bool {
}
func findStandardImportPath(path string) string {
+ if path == "" {
+ panic("findStandardImportPath called with empty path")
+ }
if search.IsStandardImportPath(path) {
if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
return filepath.Join(cfg.GOROOT, "src", path)
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 6c1525da9a..3b8c0b6435 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -397,6 +397,9 @@ func ModuleUsedDirectly(path string) bool {
// Lookup requires that one of the Load functions in this package has already
// been called.
func Lookup(path string) (dir, realPath string, err error) {
+ if path == "" {
+ panic("Lookup called with empty package path")
+ }
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
if !ok {
// The loader should have found all the relevant paths.
From 45e668879d763dd6b312034c98f8c5ffa7228ce6 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Tue, 9 Oct 2018 10:21:53 -0400
Subject: [PATCH 067/240] cmd/go: remove extraneous 'file' from usage message
in script_test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously, erroneous usage would produce error messages like:
FAIL: testdata/script/mod_tidy_replace.txt:4: usage: stdout [-count=N] 'pattern' file
where the “file” argument is not actually valid for the stdout command.
Change-Id: I74100960f4d25da122faa6c82620995a3fbfc75f
Reviewed-on: https://go-review.googlesource.com/c/140858
Run-TryBot: Bryan C. Mills
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/go/script_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index 31c6ede2a5..8708dacd41 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -614,7 +614,7 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
want = 2
}
if len(args) != want {
- ts.fatalf("usage: %s [-count=N] 'pattern' file%s", name, extraUsage)
+ ts.fatalf("usage: %s [-count=N] 'pattern'%s", name, extraUsage)
}
pattern := args[0]
From dc2ae2886fbcd2297d2a0ea67a5d220ae2c74152 Mon Sep 17 00:00:00 2001
From: Muhammad Falak R Wani
Date: Tue, 9 Oct 2018 22:12:40 +0530
Subject: [PATCH 068/240] runtime/cgo: annotate unused variable with
__attribute__((unused))
Fixes #28095
Change-Id: Id8668d52986c9805213e8847f49fe42dfde2e01a
Reviewed-on: https://go-review.googlesource.com/c/140797
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/runtime/cgo/gcc_libinit.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 3dc5bde4cc..3dafd10b7b 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -63,7 +63,7 @@ _cgo_wait_runtime_init_done() {
}
void
-x_cgo_notify_runtime_init_done(void* dummy) {
+x_cgo_notify_runtime_init_done(void* dummy __attribute__ ((unused))) {
pthread_mutex_lock(&runtime_init_mu);
runtime_init_done = 1;
pthread_cond_broadcast(&runtime_init_cond);
From 49be65eeba37a3d29a8a33379794e7a84df6cca1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:24:32 +0200
Subject: [PATCH 069/240] syscall: change solaris files to libc files
AIX and Solaris both requires libc to make any syscalls and their
implementation is really similar.
Therefore, Solaris files reused by AIX have their name changed to *_libc.
exec_libc.go is also adapted to AIX.
Updates: #25893
Change-Id: I50d1d7b964831637013d5e64799187cd9565c42b
Reviewed-on: https://go-review.googlesource.com/c/138719
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/runtime/syscall_solaris.go | 7 +++
src/syscall/asm_solaris_amd64.s | 4 ++
src/syscall/{exec_solaris.go => exec_libc.go} | 23 +++++++--
src/syscall/exec_unix.go | 12 ++---
src/syscall/mkall.sh | 13 ++++-
...mksyscall_solaris.pl => mksyscall_libc.pl} | 50 ++++++++++++++++---
6 files changed, 89 insertions(+), 20 deletions(-)
rename src/syscall/{exec_solaris.go => exec_libc.go} (92%)
rename src/syscall/{mksyscall_solaris.pl => mksyscall_libc.pl} (89%)
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index 9f05a47892..94e018d479 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -83,6 +83,13 @@ func syscall_close(fd int32) int32 {
return int32(sysvicall1(&libc_close, uintptr(fd)))
}
+const _F_DUP2FD = 0x9
+
+//go:nosplit
+func syscall_dup2(oldfd, newfd uintptr) (val, err uintptr) {
+ return syscall_fcntl(oldfd, _F_DUP2FD, newfd)
+}
+
//go:nosplit
func syscall_execve(path, argv, envp uintptr) (err uintptr) {
call := libcall{
diff --git a/src/syscall/asm_solaris_amd64.s b/src/syscall/asm_solaris_amd64.s
index 6fa041866d..c61e04a42f 100644
--- a/src/syscall/asm_solaris_amd64.s
+++ b/src/syscall/asm_solaris_amd64.s
@@ -23,6 +23,10 @@ TEXT ·chroot1(SB),NOSPLIT,$0
TEXT ·close(SB),NOSPLIT,$0
JMP runtime·syscall_close(SB)
+TEXT ·dup2child(SB),NOSPLIT,$0
+ JMP runtime·syscall_dup2(SB)
+ RET
+
TEXT ·execve(SB),NOSPLIT,$0
JMP runtime·syscall_execve(SB)
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_libc.go
similarity index 92%
rename from src/syscall/exec_solaris.go
rename to src/syscall/exec_libc.go
index 9735ae5706..d6d34c04c3 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_libc.go
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build aix solaris
+
+// This file handles forkAndExecInChild function for OS using libc syscall like AIX or Solaris.
+
package syscall
import (
@@ -28,6 +32,7 @@ func runtime_AfterForkInChild()
func chdir(path uintptr) (err Errno)
func chroot1(path uintptr) (err Errno)
func close(fd uintptr) (err Errno)
+func dup2child(old uintptr, new uintptr) (val uintptr, err Errno)
func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
func exit(code uintptr)
func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
@@ -43,7 +48,7 @@ func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
// syscall defines this global on our behalf to avoid a build dependency on other platforms
func init() {
- execveSolaris = execve
+ execveLibc = execve
}
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
@@ -178,7 +183,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
if pipe < nextfd {
- _, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
+ _, err1 = dup2child(uintptr(pipe), uintptr(nextfd))
if err1 != 0 {
goto childerror
}
@@ -191,11 +196,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if nextfd == pipe { // don't stomp on pipe
nextfd++
}
- _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
+ _, err1 = dup2child(uintptr(fd[i]), uintptr(nextfd))
+ if err1 != 0 {
+ goto childerror
+ }
+ _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
if err1 != 0 {
goto childerror
}
- fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
fd[i] = nextfd
nextfd++
}
@@ -218,7 +226,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// The new fd is created NOT close-on-exec,
// which is exactly what we want.
- _, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
+ _, err1 = dup2child(uintptr(fd[i]), uintptr(i))
if err1 != 0 {
goto childerror
}
@@ -242,6 +250,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Set the controlling TTY to Ctty
if sys.Setctty {
+ // On AIX, TIOCSCTTY is undefined
+ if TIOCSCTTY == 0 {
+ err1 = ENOSYS
+ goto childerror
+ }
err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
if err1 != 0 {
goto childerror
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 9a950ac17f..3b84256b8e 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Fork, exec, wait, etc.
@@ -246,9 +246,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
func runtime_BeforeExec()
func runtime_AfterExec()
-// execveSolaris is non-nil on Solaris, set to execve in exec_solaris.go; this
+// execveLibc is non-nil on OS using libc syscall, set to execve in exec_libc.go; this
// avoids a build dependency for other platforms.
-var execveSolaris func(path uintptr, argv uintptr, envp uintptr) (err Errno)
+var execveLibc func(path uintptr, argv uintptr, envp uintptr) (err Errno)
// Exec invokes the execve(2) system call.
func Exec(argv0 string, argv []string, envv []string) (err error) {
@@ -267,9 +267,9 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
runtime_BeforeExec()
var err1 Errno
- if runtime.GOOS == "solaris" {
- // RawSyscall should never be used on Solaris.
- err1 = execveSolaris(
+ if runtime.GOOS == "solaris" || runtime.GOOS == "aix" {
+ // RawSyscall should never be used on Solaris or AIX.
+ err1 = execveLibc(
uintptr(unsafe.Pointer(argv0p)),
uintptr(unsafe.Pointer(&argvp[0])),
uintptr(unsafe.Pointer(&envvp[0])))
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index b381b93161..b783921d1a 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -115,6 +115,11 @@ _* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
+aix_ppc64)
+ mkerrors="$mkerrors -maix64"
+ mksyscall="./mksyscall_libc.pl -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
darwin_386)
mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32"
@@ -301,7 +306,7 @@ plan9_386)
mktypes="XXX"
;;
solaris_amd64)
- mksyscall="./mksyscall_solaris.pl"
+ mksyscall="./mksyscall_libc.pl -solaris"
mkerrors="$mkerrors -m64"
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
@@ -327,5 +332,9 @@ esac
if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
- if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |go run mkpost.go >ztypes_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then
+ # ztypes_$GOOSARCH.go could be erased before "go run mkpost.go" is called.
+ # Therefore, "go run" tries to recompile syscall package but ztypes is empty and it fails.
+ echo "$mktypes types_$GOOS.go |go run mkpost.go >ztypes_$GOOSARCH.go.NEW && mv ztypes_$GOOSARCH.go.NEW ztypes_$GOOSARCH.go";
+ fi
) | $run
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_libc.pl
similarity index 89%
rename from src/syscall/mksyscall_solaris.pl
rename to src/syscall/mksyscall_libc.pl
index 9172975914..6f57bee79e 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_libc.pl
@@ -19,10 +19,12 @@
use strict;
-my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
+my $cmdline = "mksyscall_libc.pl " . join(' ', @ARGV);
my $errors = 0;
my $_32bit = "";
my $tags = ""; # build tags
+my $aix = 0;
+my $solaris = 0;
binmode STDOUT;
@@ -33,14 +35,23 @@ if($ARGV[0] eq "-b32") {
$_32bit = "little-endian";
shift;
}
+if($ARGV[0] eq "-aix") {
+ $aix = 1;
+ shift;
+}
+if($ARGV[0] eq "-solaris") {
+ $solaris = 1;
+ shift;
+}
if($ARGV[0] eq "-tags") {
shift;
$tags = $ARGV[0];
shift;
}
+
if($ARGV[0] =~ /^-/) {
- print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n";
+ print STDERR "usage: mksyscall_libc.pl [-b32 | -l32] [-aix | -solaris] [-tags x,y] [file ...]\n";
exit 1;
}
@@ -96,8 +107,22 @@ while(<>) {
my @out = parseparamlist($out);
# So file name.
- if($modname eq "") {
- $modname = "libc";
+ if($aix) {
+ if($modname eq "") {
+ $modname = "libc.a/shr_64.o";
+ } else {
+ print STDERR "$func: only syscall using libc are available\n";
+ $errors = 1;
+ next;
+ }
+
+ }
+ if($solaris) {
+ if($modname eq "") {
+ $modname = "libc";
+ }
+ $modname .= ".so";
+
}
# System call name.
@@ -114,7 +139,7 @@ while(<>) {
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
# Runtime import of function to allow cross-platform builds.
- $dynimports .= "//go:cgo_import_dynamic ${sysvarname} ${sysname} \"$modname.so\"\n";
+ $dynimports .= "//go:cgo_import_dynamic ${sysvarname} ${sysname} \"$modname\"\n";
# Link symbol to proc address variable.
$linknames .= "//go:linkname ${sysvarname} ${sysvarname}\n";
# Library proc address variable.
@@ -184,10 +209,21 @@ while(<>) {
}
my $nargs = @args;
+ my $asmfuncname="";
+ my $asmrawfuncname="";
+
+ if($aix){
+ $asmfuncname="syscall6";
+ $asmrawfuncname="rawSyscall6";
+ } else {
+ $asmfuncname="sysvicall6";
+ $asmrawfuncname="rawSysvicall6";
+ }
+
# Determine which form to use; pad args with zeros.
- my $asm = "${syscalldot}sysvicall6";
+ my $asm = "${syscalldot}${asmfuncname}";
if ($nonblock) {
- $asm = "${syscalldot}rawSysvicall6";
+ $asm = "${syscalldot}${asmrawfuncname}";
}
if(@args <= 6) {
while(@args < 6) {
From 95d06ab6c982f58b127b14a52c3325acf0bd3926 Mon Sep 17 00:00:00 2001
From: Wil Selwood
Date: Thu, 2 Aug 2018 20:29:38 +0100
Subject: [PATCH 070/240] testing: try to Log through parent if test has
completed
If the test has already completed when a go routine with a panic
handler reports an error the location of the error call is lost.
Added logDepth to be able to log location of failure at different
depths down the stack.
Fixes #26720
Change-Id: I8b7789ddae757ef6f4bd315cb20356709f4fadec
Reviewed-on: https://go-review.googlesource.com/c/127596
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/testing/sub_test.go | 23 +++++++++++++++++++++++
src/testing/testing.go | 22 +++++++++++++++++++---
2 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index 29803c06e2..e9b2233520 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -411,6 +411,29 @@ func TestTRun(t *T) {
ch <- true
<-ch
},
+ }, {
+ desc: "log in finished sub test logs to parent",
+ ok: false,
+ output: `
+ --- FAIL: log in finished sub test logs to parent (N.NNs)
+ sub_test.go:NNN: message2
+ sub_test.go:NNN: message1
+ sub_test.go:NNN: error`,
+ maxPar: 1,
+ f: func(t *T) {
+ ch := make(chan bool)
+ t.Run("sub", func(t2 *T) {
+ go func() {
+ <-ch
+ t2.Log("message1")
+ ch <- true
+ }()
+ })
+ t.Log("message2")
+ ch <- true
+ <-ch
+ t.Errorf("error")
+ },
}}
for _, tc := range testCases {
ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 179987b699..0bc222c0bb 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -403,8 +403,8 @@ func (c *common) frameSkip(skip int) runtime.Frame {
// decorate prefixes the string with the file and line of the call site
// and inserts the final newline if needed and indentation spaces for formatting.
// This function must be called with c.mu held.
-func (c *common) decorate(s string) string {
- frame := c.frameSkip(3) // decorate + log + public function.
+func (c *common) decorate(s string, skip int) string {
+ frame := c.frameSkip(skip)
file := frame.File
line := frame.Line
if file != "" {
@@ -599,9 +599,25 @@ func (c *common) FailNow() {
// log generates the output. It's always at the same stack depth.
func (c *common) log(s string) {
+ c.logDepth(s, 3) // logDepth + log + public function
+}
+
+// logDepth generates the output. At an arbitary stack depth
+func (c *common) logDepth(s string, depth int) {
c.mu.Lock()
defer c.mu.Unlock()
- c.output = append(c.output, c.decorate(s)...)
+ // If this test has already finished try and log this message with our parent
+ // with this test name tagged so we know where it came from.
+ // If we don't have a parent panic.
+ if c.done {
+ if c.parent != nil {
+ c.parent.logDepth(s, depth+1)
+ } else {
+ panic("Log in goroutine after " + c.name + " has completed")
+ }
+ } else {
+ c.output = append(c.output, c.decorate(s, depth+1)...)
+ }
}
// Log formats its arguments using default formatting, analogous to Println,
From c870d56f98eab5370726afd223fe0ab14d9e88ab Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick
Date: Tue, 9 Oct 2018 16:01:20 -0700
Subject: [PATCH 071/240] net/http/httputil: fix race/crash in previous
ReverseProxy change
The previous ReverseProxy change, CL 137335, introduced a bug which could cause
a race and/or a crash.
This reliably crashed before:
$ go test -short -race -v -run=TestReverseProxyFlushInterval -count=20 net/http/httputil
The problem was a goroutine was running http.ResponseWriter.Flush
after the http.Handler's ServeHTTP completed. There was code to
prevent that (a deferred stop call) but the stop call didn't consider
the case where time.AfterFunc had already fired off a new goroutine
but that goroutine hadn't yet scheduled.
Change-Id: I06357908465a3b953efc33e63c70dec19a501adf
Reviewed-on: https://go-review.googlesource.com/c/140977
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
Reviewed-by: Dmitri Shuralyov
---
src/net/http/httputil/reverseproxy.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 1efcbd3bbc..f82d820a43 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -448,6 +448,9 @@ func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
func (m *maxLatencyWriter) delayedFlush() {
m.mu.Lock()
defer m.mu.Unlock()
+ if !m.flushPending { // if stop was called but AfterFunc already started this goroutine
+ return
+ }
m.dst.Flush()
m.flushPending = false
}
@@ -455,6 +458,7 @@ func (m *maxLatencyWriter) delayedFlush() {
func (m *maxLatencyWriter) stop() {
m.mu.Lock()
defer m.mu.Unlock()
+ m.flushPending = false
if m.t != nil {
m.t.Stop()
}
From 8f9902da269c08ad9a741d828d7f6781f56a7a42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:29:58 +0200
Subject: [PATCH 072/240] syscall: add AIX operating system
This commit adds AIX operating system to syscall package for ppc64
architecture.
It also adds the file syscall_aix.go in the runtime package for
syscalls needed during fork and exec.
Updates: #25893
Change-Id: I301b1051b178a3efb7bbc39cdbd8e00b594d65ef
Reviewed-on: https://go-review.googlesource.com/c/138720
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/runtime/syscall_aix.go | 212 +++++
src/syscall/dirent.go | 2 +-
src/syscall/env_unix.go | 2 +-
src/syscall/exec_aix_test.go | 37 +
src/syscall/exec_unix_test.go | 2 +-
src/syscall/flock_aix.go | 41 +
src/syscall/forkpipe.go | 2 +-
src/syscall/mkerrors.sh | 10 +
src/syscall/mmap_unix_test.go | 2 +-
src/syscall/sockcmsg_unix.go | 2 +-
src/syscall/syscall_aix.go | 651 +++++++++++++++
src/syscall/syscall_aix_ppc64.go | 17 +
src/syscall/syscall_unix.go | 2 +-
src/syscall/timestruct.go | 2 +-
src/syscall/types_aix.go | 172 ++++
src/syscall/zerrors_aix_ppc64.go | 1248 +++++++++++++++++++++++++++++
src/syscall/zsyscall_aix_ppc64.go | 1167 +++++++++++++++++++++++++++
src/syscall/ztypes_aix_ppc64.go | 272 +++++++
18 files changed, 3835 insertions(+), 8 deletions(-)
create mode 100644 src/runtime/syscall_aix.go
create mode 100644 src/syscall/exec_aix_test.go
create mode 100644 src/syscall/flock_aix.go
create mode 100644 src/syscall/syscall_aix.go
create mode 100644 src/syscall/syscall_aix_ppc64.go
create mode 100644 src/syscall/types_aix.go
create mode 100644 src/syscall/zerrors_aix_ppc64.go
create mode 100644 src/syscall/zsyscall_aix_ppc64.go
create mode 100644 src/syscall/ztypes_aix_ppc64.go
diff --git a/src/runtime/syscall_aix.go b/src/runtime/syscall_aix.go
new file mode 100644
index 0000000000..376e22d59a
--- /dev/null
+++ b/src/runtime/syscall_aix.go
@@ -0,0 +1,212 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+// This file handles some syscalls from the syscall package
+// Especially, syscalls use during forkAndExecInChild which must not split the stack
+
+//go:cgo_import_dynamic libc_chdir chdir "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_chroot chroot "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_dup2 dup2 "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_execve execve "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_fork fork "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setgid setgid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setgroups setgroups "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setsid setsid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setuid setuid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setpgid setpgid "libc.a/shr_64.o"
+
+//go:linkname libc_chdir libc_chdir
+//go:linkname libc_chroot libc_chroot
+//go:linkname libc_dup2 libc_dup2
+//go:linkname libc_execve libc_execve
+//go:linkname libc_fcntl libc_fcntl
+//go:linkname libc_fork libc_fork
+//go:linkname libc_ioctl libc_ioctl
+//go:linkname libc_setgid libc_setgid
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_setsid libc_setsid
+//go:linkname libc_setuid libc_setuid
+//go:linkname libc_setpgid libc_setpgid
+
+var (
+ libc_chdir,
+ libc_chroot,
+ libc_dup2,
+ libc_execve,
+ libc_fcntl,
+ libc_fork,
+ libc_ioctl,
+ libc_setgid,
+ libc_setgroups,
+ libc_setsid,
+ libc_setuid,
+ libc_setpgid libFunc
+)
+
+// In syscall_syscall6 and syscall_rawsyscall6, r2 is always 0
+// as it's never used on AIX
+// TODO: remove r2 from zsyscall_aix_$GOARCH.go
+
+// Syscall is needed because some packages (like net) need it too.
+// The best way is to return EINVAL and let Golang handles its failure
+// If the syscall can't fail, this function can redirect it to a real syscall.
+//go:linkname syscall_Syscall syscall.Syscall
+//go:nosplit
+func syscall_Syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+ return 0, 0, _EINVAL
+}
+
+// This is syscall.RawSyscall, it exists to satisfy some build dependency,
+// but it doesn't work.
+//go:linkname syscall_RawSyscall syscall.RawSyscall
+func syscall_RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+ panic("RawSyscall not available on AIX")
+}
+
+//go:linkname syscall_syscall6 syscall.syscall6
+//go:nosplit
+func syscall_syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+ c := getg().m.libcall
+ c.fn = uintptr(unsafe.Pointer(fn))
+ c.n = nargs
+ c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+
+ entersyscallblock()
+ asmcgocall(unsafe.Pointer(&asmsyscall6), unsafe.Pointer(&c))
+ exitsyscall()
+ return c.r1, 0, c.err
+}
+
+//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
+//go:nosplit
+func syscall_rawSyscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+ c := getg().m.libcall
+ c.fn = uintptr(unsafe.Pointer(fn))
+ c.n = nargs
+ c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+
+ asmcgocall(unsafe.Pointer(&asmsyscall6), unsafe.Pointer(&c))
+
+ return c.r1, 0, c.err
+}
+
+//go:linkname syscall_chdir syscall.chdir
+//go:nosplit
+func syscall_chdir(path uintptr) (err uintptr) {
+ _, err = syscall1(&libc_chdir, path)
+ return
+}
+
+//go:linkname syscall_chroot1 syscall.chroot1
+//go:nosplit
+func syscall_chroot1(path uintptr) (err uintptr) {
+ _, err = syscall1(&libc_chroot, path)
+ return
+}
+
+// like close, but must not split stack, for fork.
+//go:linkname syscall_close syscall.close
+//go:nosplit
+func syscall_close(fd int32) int32 {
+ _, err := syscall1(&libc_close, uintptr(fd))
+ return int32(err)
+}
+
+//go:linkname syscall_dup2child syscall.dup2child
+//go:nosplit
+func syscall_dup2child(old, new uintptr) (val, err uintptr) {
+ val, err = syscall2(&libc_dup2, old, new)
+ return
+}
+
+//go:linkname syscall_execve syscall.execve
+//go:nosplit
+func syscall_execve(path, argv, envp uintptr) (err uintptr) {
+ _, err = syscall3(&libc_execve, path, argv, envp)
+ return
+}
+
+// like exit, but must not split stack, for fork.
+//go:linkname syscall_exit syscall.exit
+//go:nosplit
+func syscall_exit(code uintptr) {
+ syscall1(&libc_exit, code)
+}
+
+//go:linkname syscall_fcntl1 syscall.fcntl1
+//go:nosplit
+func syscall_fcntl1(fd, cmd, arg uintptr) (val, err uintptr) {
+ val, err = syscall3(&libc_fcntl, fd, cmd, arg)
+ return
+
+}
+
+//go:linkname syscall_forkx syscall.forkx
+//go:nosplit
+func syscall_forkx(flags uintptr) (pid uintptr, err uintptr) {
+ pid, err = syscall1(&libc_fork, flags)
+ return
+}
+
+//go:linkname syscall_getpid syscall.getpid
+//go:nosplit
+func syscall_getpid() (pid, err uintptr) {
+ pid, err = syscall0(&libc_getpid)
+ return
+}
+
+//go:linkname syscall_ioctl syscall.ioctl
+//go:nosplit
+func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
+ _, err = syscall3(&libc_ioctl, fd, req, arg)
+ return
+}
+
+//go:linkname syscall_setgid syscall.setgid
+//go:nosplit
+func syscall_setgid(gid uintptr) (err uintptr) {
+ _, err = syscall1(&libc_setgid, gid)
+ return
+}
+
+//go:linkname syscall_setgroups1 syscall.setgroups1
+//go:nosplit
+func syscall_setgroups1(ngid, gid uintptr) (err uintptr) {
+ _, err = syscall2(&libc_setgroups, ngid, gid)
+ return
+}
+
+//go:linkname syscall_setsid syscall.setsid
+//go:nosplit
+func syscall_setsid() (pid, err uintptr) {
+ pid, err = syscall0(&libc_setsid)
+ return
+}
+
+//go:linkname syscall_setuid syscall.setuid
+//go:nosplit
+func syscall_setuid(uid uintptr) (err uintptr) {
+ _, err = syscall1(&libc_setuid, uid)
+ return
+}
+
+//go:linkname syscall_setpgid syscall.setpgid
+//go:nosplit
+func syscall_setpgid(pid, pgid uintptr) (err uintptr) {
+ _, err = syscall2(&libc_setpgid, pid, pgid)
+ return
+}
+
+//go:linkname syscall_write1 syscall.write1
+//go:nosplit
+func syscall_write1(fd, buf, nbyte uintptr) (n, err uintptr) {
+ n, err = syscall3(&libc_write, fd, buf, nbyte)
+ return
+}
diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go
index 26cbbbce2a..5c7af42b0c 100644
--- a/src/syscall/dirent.go
+++ b/src/syscall/dirent.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package syscall
diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go
index 1ebc0b17f2..0b6b711a8f 100644
--- a/src/syscall/env_unix.go
+++ b/src/syscall/env_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
// Unix environment variables.
diff --git a/src/syscall/exec_aix_test.go b/src/syscall/exec_aix_test.go
new file mode 100644
index 0000000000..22b752cf27
--- /dev/null
+++ b/src/syscall/exec_aix_test.go
@@ -0,0 +1,37 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix
+
+package syscall
+
+import "unsafe"
+
+//go:cgo_import_dynamic libc_Getpgid getpgid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.a/shr_64.o"
+
+//go:linkname libc_Getpgid libc_Getpgid
+//go:linkname libc_Getpgrp libc_Getpgrp
+
+var (
+ libc_Getpgid,
+ libc_Getpgrp libcFunc
+)
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+var Ioctl = ioctl
diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go
index 9bb95c0f39..33614f5221 100644
--- a/src/syscall/exec_unix_test.go
+++ b/src/syscall/exec_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall_test
diff --git a/src/syscall/flock_aix.go b/src/syscall/flock_aix.go
new file mode 100644
index 0000000000..9745236dcb
--- /dev/null
+++ b/src/syscall/flock_aix.go
@@ -0,0 +1,41 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+// On AIX, there is no flock() system call, we emulate it.
+// Moreover, we can't call the default fcntl syscall because the arguments
+// must be integer and it's not possible to transform a pointer (lk)
+// to a int value.
+// It's easier to call syscall6 than to transform fcntl for every GOOS.
+func fcntlFlock(fd, cmd int, lk *Flock_t) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Flock(fd int, op int) (err error) {
+ lk := &Flock_t{}
+ if (op & LOCK_UN) != 0 {
+ lk.Type = F_UNLCK
+ } else if (op & LOCK_EX) != 0 {
+ lk.Type = F_WRLCK
+ } else if (op & LOCK_SH) != 0 {
+ lk.Type = F_RDLCK
+ } else {
+ return nil
+ }
+ if (op & LOCK_NB) != 0 {
+ err = fcntlFlock(fd, F_SETLK, lk)
+ if err != nil && (err == EAGAIN || err == EACCES) {
+ return EWOULDBLOCK
+ }
+ return err
+ }
+ return fcntlFlock(fd, F_SETLKW, lk)
+}
diff --git a/src/syscall/forkpipe.go b/src/syscall/forkpipe.go
index 71890a29ba..d9999cb8b8 100644
--- a/src/syscall/forkpipe.go
+++ b/src/syscall/forkpipe.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly solaris
+// +build aix darwin dragonfly solaris
package syscall
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index 93d6f7d2b6..d5880dcaf2 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -20,6 +20,16 @@ fi
uname=$(uname)
+includes_AIX='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+'
+
includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL
diff --git a/src/syscall/mmap_unix_test.go b/src/syscall/mmap_unix_test.go
index 01f7783022..d0b3644b59 100644
--- a/src/syscall/mmap_unix_test.go
+++ b/src/syscall/mmap_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build aix darwin dragonfly freebsd linux netbsd openbsd
package syscall_test
diff --git a/src/syscall/sockcmsg_unix.go b/src/syscall/sockcmsg_unix.go
index 5712bf13f2..5020033bad 100644
--- a/src/syscall/sockcmsg_unix.go
+++ b/src/syscall/sockcmsg_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Socket control messages
diff --git a/src/syscall/syscall_aix.go b/src/syscall/syscall_aix.go
new file mode 100644
index 0000000000..bddc590c34
--- /dev/null
+++ b/src/syscall/syscall_aix.go
@@ -0,0 +1,651 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Aix system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Implemented in runtime/syscall_aix.go.
+func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
+// Constant expected by package but not supported
+const (
+ _ = iota
+ TIOCSCTTY
+ F_DUPFD_CLOEXEC
+ SYS_EXECVE
+ SYS_FCNTL
+)
+
+/*
+ * Wrapped
+ */
+
+// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
+// There is no way to create a custom fcntl and to keep //sys fcntl easily,
+// because we need fcntl name for its libc symbol. This is linked with the script.
+// But, as fcntl is currently not exported and isn't called with F_DUP2FD,
+// it doesn't matter.
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+//sys dup2(old int, new int) (val int, err error)
+
+//sysnb pipe(p *[2]_C_int) (err error)
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys readlink(path string, buf []byte, bufSize uint64) (n int, err error)
+func Readlink(path string, buf []byte) (n int, err error) {
+ s := uint64(len(buf))
+ return readlink(path, buf, s)
+}
+
+//sys utimes(path string, times *[2]Timeval) (err error)
+func Utimes(path string, tv []Timeval) error {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
+func UtimesNano(path string, ts []Timespec) error {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+}
+
+//sys unlinkat(dirfd int, path string, flags int) (err error)
+func Unlinkat(dirfd int, path string) (err error) {
+ return unlinkat(dirfd, path, 0)
+}
+
+//sys getcwd(buf *byte, size uint64) (err error)
+
+const ImplementsGetwd = true
+
+func Getwd() (ret string, err error) {
+ for len := uint64(4096); ; len *= 2 {
+ b := make([]byte, len)
+ err := getcwd(&b[0], len)
+ if err == nil {
+ i := 0
+ for b[i] != 0 {
+ i++
+ }
+ return string(b[0:i]), nil
+ }
+ if err != ERANGE {
+ return "", err
+ }
+ }
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+ err = getcwd(&buf[0], uint64(len(buf)))
+ if err == nil {
+ i := 0
+ for buf[i] != 0 {
+ i++
+ }
+ n = i + 1
+ }
+ return
+}
+
+//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
+//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
+
+func Getgroups() (gids []int, err error) {
+ n, err := getgroups(0, nil)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != nil {
+ return nil, err
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (err error) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+ err = gettimeofday(tv, nil)
+ return
+}
+
+// TODO
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return -1, ENOSYS
+}
+
+//sys getdirent(fd int, buf []byte) (n int, err error)
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ return getdirent(fd, buf)
+}
+
+//sys wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error)
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ var status _C_int
+ var r Pid_t
+ err = ERESTART
+ // AIX wait4 may return with ERESTART errno, while the processus is still
+ // active.
+ for err == ERESTART {
+ r, err = wait4(Pid_t(pid), &status, options, rusage)
+ }
+ wpid = int(r)
+ if wstatus != nil {
+ *wstatus = WaitStatus(status)
+ }
+ return
+}
+
+/*
+ * Socket
+ */
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys Getkerninfo(op int32, where uintptr, size uintptr, arg int64) (i int32, err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys Listen(s int, backlog int) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sys socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+//sys Shutdown(s int, how int) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
+}
+
+func (sa *RawSockaddrUnix) setLen(n int) {
+ sa.Len = uint8(3 + n) // 2 for Family, Len; 1 for NUL.
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ name := sa.Name
+ n := len(name)
+ if n > len(sa.raw.Path) {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ sa.raw.setLen(n)
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = uint8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := _Socklen(2)
+ if n > 0 {
+ sl += _Socklen(n) + 1
+ }
+
+ return unsafe.Pointer(&sa.raw), sl, nil
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if err = getsockname(fd, &rsa, &len); err != nil {
+ return
+ }
+ return anyToSockaddr(&rsa)
+}
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
+ return
+ }
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ var sockType int
+ sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
+ if err != nil {
+ return
+ }
+ // receive at least one normal byte
+ if sockType != SOCK_DGRAM && len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
+ return
+ }
+ oobn = int(msg.Controllen)
+ recvflags = int(msg.Flags)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, err = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ var ptr unsafe.Pointer
+ var salen _Socklen
+ if to != nil {
+ ptr, salen, err = to.sockaddr()
+ if err != nil {
+ return 0, err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ var sockType int
+ sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
+ if err != nil {
+ return 0, err
+ }
+ // send at least one normal byte
+ if sockType != SOCK_DGRAM && len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, err = sendmsg(fd, &msg, flags); err != nil {
+ return 0, err
+ }
+ if len(oob) > 0 && len(p) == 0 {
+ n = 0
+ }
+ return n, nil
+}
+
+func (sa *RawSockaddrUnix) getLen() (int, error) {
+ // Some versions of AIX have a bug in getsockname (see IV78655).
+ // We can't rely on sa.Len being set correctly.
+ n := SizeofSockaddrUnix - 3 // substract leading Family, Len, terminating NUL.
+ for i := 0; i < n; i++ {
+ if sa.Path[i] == 0 {
+ n = i
+ break
+ }
+ }
+ return n, nil
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ n, err := pp.getLen()
+ if err != nil {
+ return nil, err
+ }
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))
+ sa.Name = string(bytes[0:n])
+ return sa, nil
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+ }
+ return nil, EAFNOSUPPORT
+}
+
+/*
+ * Wait
+ */
+
+type WaitStatus uint32
+
+func (w WaitStatus) Stopped() bool { return w&0x40 != 0 }
+func (w WaitStatus) StopSignal() Signal {
+ if !w.Stopped() {
+ return -1
+ }
+ return Signal(w>>8) & 0xFF
+}
+
+func (w WaitStatus) Exited() bool { return w&0xFF == 0 }
+func (w WaitStatus) ExitStatus() int {
+ if !w.Exited() {
+ return -1
+ }
+ return int((w >> 8) & 0xFF)
+}
+
+func (w WaitStatus) Signaled() bool { return w&0x40 == 0 && w&0xFF != 0 }
+func (w WaitStatus) Signal() Signal {
+ if !w.Signaled() {
+ return -1
+ }
+ return Signal(w>>16) & 0xFF
+}
+
+func (w WaitStatus) Continued() bool { return w&0x01000000 != 0 }
+
+func (w WaitStatus) CoreDump() bool { return w&0x200 == 0 }
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+/*
+ * ptrace
+ */
+
+//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
+//sys ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err error)
+
+func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno {
+ if request == PTRACE_TRACEME {
+ // Convert to AIX ptrace call.
+ err := ptrace64(PT_TRACE_ME, 0, 0, 0, 0)
+ if err != nil {
+ return err.(Errno)
+ }
+ return 0
+ }
+ return ENOSYS
+}
+
+func ptracePeek(pid int, addr uintptr, out []byte) (count int, err error) {
+ n := 0
+ for len(out) > 0 {
+ bsize := len(out)
+ if bsize > 1024 {
+ bsize = 1024
+ }
+ err = ptrace64(PT_READ_BLOCK, int64(pid), int64(addr), bsize, uintptr(unsafe.Pointer(&out[0])))
+ if err != nil {
+ return 0, err
+ }
+ addr += uintptr(bsize)
+ n += bsize
+ out = out[n:]
+ }
+ return n, nil
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) {
+ return ptracePeek(pid, addr, out)
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
+ return ptracePeek(pid, addr, out)
+}
+
+func ptracePoke(pid int, addr uintptr, data []byte) (count int, err error) {
+ n := 0
+ for len(data) > 0 {
+ bsize := len(data)
+ if bsize > 1024 {
+ bsize = 1024
+ }
+ err = ptrace64(PT_WRITE_BLOCK, int64(pid), int64(addr), bsize, uintptr(unsafe.Pointer(&data[0])))
+ if err != nil {
+ return 0, err
+ }
+ addr += uintptr(bsize)
+ n += bsize
+ data = data[n:]
+ }
+ return n, nil
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
+ return ptracePoke(pid, addr, data)
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
+ return ptracePoke(pid, addr, data)
+}
+
+func PtraceCont(pid int, signal int) (err error) {
+ return ptrace64(PT_CONTINUE, int64(pid), 1, signal, 0)
+}
+
+func PtraceSingleStep(pid int) (err error) { return ptrace64(PT_STEP, int64(pid), 1, 0, 0) }
+
+func PtraceAttach(pid int) (err error) { return ptrace64(PT_ATTACH, int64(pid), 0, 0, 0) }
+
+func PtraceDetach(pid int) (err error) { return ptrace64(PT_DETACH, int64(pid), 0, 0, 0) }
+
+/*
+ * Direct access
+ */
+
+//sys Acct(path string) (err error)
+//sys Chdir(path string) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Close(fd int) (err error)
+//sys Dup(fd int) (nfd int, err error)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fchdir(fd int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Fsync(fd int) (err error)
+//sysnb Getgid() (gid int)
+//sysnb Getpid() (pid int)
+//sys Geteuid() (euid int)
+//sys Getegid() (egid int)
+//sys Getppid() (ppid int)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getuid() (uid int)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys read(fd int, p []byte) (n int, err error)
+//sys Reboot(how int) (err error)
+//sys Rename(from string, to string) (err error)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys Umask(newmask int) (oldmask int)
+//sys Unlink(path string) (err error)
+//sysnb Uname(buf *Utsname) (err error)
+//sys write(fd int, p []byte) (n int, err error)
+
+//sys gettimeofday(tv *Timeval, tzp *Timezone) (err error)
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
+}
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+/*
+ * Map
+ */
+
+var mapper = &mmapper{
+ active: make(map[*byte][]byte),
+ mmap: mmap,
+ munmap: munmap,
+}
+
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
+ return mapper.Mmap(fd, offset, length, prot, flags)
+}
+
+func Munmap(b []byte) (err error) {
+ return mapper.Munmap(b)
+}
diff --git a/src/syscall/syscall_aix_ppc64.go b/src/syscall/syscall_aix_ppc64.go
new file mode 100644
index 0000000000..21ad5bc296
--- /dev/null
+++ b/src/syscall/syscall_aix_ppc64.go
@@ -0,0 +1,17 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go
index c9c0f62dd2..4336851554 100644
--- a/src/syscall/syscall_unix.go
+++ b/src/syscall/syscall_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall
diff --git a/src/syscall/timestruct.go b/src/syscall/timestruct.go
index 84a00a77d8..d17811c121 100644
--- a/src/syscall/timestruct.go
+++ b/src/syscall/timestruct.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package syscall
diff --git a/src/syscall/types_aix.go b/src/syscall/types_aix.go
new file mode 100644
index 0000000000..f9f05af667
--- /dev/null
+++ b/src/syscall/types_aix.go
@@ -0,0 +1,172 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+
+#include
+#include
+#include
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+ PathMax = C.PATH_MAX
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timeval32 C.struct_timeval32
+
+type Timezone C.struct_timezone
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type Pid_t C.pid_t
+
+type _Gid_t C.gid_t
+
+// Files
+
+type Flock_t C.struct_flock
+
+type Stat_t C.struct_stat
+
+type Statfs_t C.struct_statfs
+
+type Fsid64_t C.fsid64_t
+
+type StTimespec_t C.st_timespec_t
+
+type Dirent C.struct_dirent
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Cmsghdr C.struct_cmsghdr
+
+type ICMPv6Filter C.struct_icmp6_filter
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Linger C.struct_linger
+
+type Msghdr C.struct_msghdr
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+)
+
+// Ptrace requests
+
+const (
+ PTRACE_TRACEME = C.PT_TRACE_ME
+ PTRACE_CONT = C.PT_CONTINUE
+ PTRACE_KILL = C.PT_KILL
+)
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+)
+
+type IfMsgHdr C.struct_if_msghdr
+
+// Misc
+
+type Utsname C.struct_utsname
+
+const (
+ _AT_FDCWD = C.AT_FDCWD
+ _AT_REMOVEDIR = C.AT_REMOVEDIR
+ _AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
+)
diff --git a/src/syscall/zerrors_aix_ppc64.go b/src/syscall/zerrors_aix_ppc64.go
new file mode 100644
index 0000000000..60130099a7
--- /dev/null
+++ b/src/syscall/zerrors_aix_ppc64.go
@@ -0,0 +1,1248 @@
+// mkerrors.sh -maix64
+// Code generated by the command above; DO NOT EDIT.
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs -- -maix64 _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_BYPASS = 0x19
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x18
+ AF_INTF = 0x14
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_MAX = 0x1e
+ AF_NDD = 0x17
+ AF_NETWARE = 0x16
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_RIF = 0x15
+ AF_ROUTE = 0x11
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ ARPHRD_802_3 = 0x6
+ ARPHRD_802_5 = 0x6
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FDDI = 0x1
+ B0 = 0x0
+ B110 = 0x3
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B2400 = 0xb
+ B300 = 0x7
+ B38400 = 0xf
+ B4800 = 0xc
+ B50 = 0x1
+ B600 = 0x8
+ B75 = 0x2
+ B9600 = 0xd
+ CFLUSH = 0xf
+ CSIOCGIFCONF = -0x3fef96dc
+ CSTART = '\021'
+ CSTOP = '\023'
+ CSUSP = 0x1a
+ ECHO = 0x8
+ ECH_ICMPID = 0x2
+ ETHERNET_CSMACD = 0x6
+ EVENP = 0x80
+ EXCONTINUE = 0x0
+ EXDLOK = 0x3
+ EXIO = 0x2
+ EXPGIO = 0x0
+ EXRESUME = 0x2
+ EXRETURN = 0x1
+ EXSIG = 0x4
+ EXTA = 0xe
+ EXTB = 0xf
+ EXTRAP = 0x1
+ EYEC_RTENTRYA = 0x257274656e747241
+ EYEC_RTENTRYF = 0x257274656e747246
+ E_ACC = 0x0
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0xfffe
+ FLUSHBAND = 0x40
+ FLUSHLOW = 0x8
+ FLUSHO = 0x100000
+ FLUSHR = 0x1
+ FLUSHRW = 0x3
+ FLUSHW = 0x2
+ F_CLOSEM = 0xa
+ F_DUP2FD = 0xe
+ F_DUPFD = 0x0
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0xb
+ F_GETLK64 = 0xb
+ F_GETOWN = 0x8
+ F_LOCK = 0x1
+ F_OK = 0x0
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0xc
+ F_SETLK64 = 0xc
+ F_SETLKW = 0xd
+ F_SETLKW64 = 0xd
+ F_SETOWN = 0x9
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_TSTLK = 0xf
+ F_ULOCK = 0x0
+ F_UNLCK = 0x3
+ F_WRLCK = 0x2
+ ICMP6_FILTER = 0x26
+ ICMP6_SEC_SEND_DEL = 0x46
+ ICMP6_SEC_SEND_GET = 0x47
+ ICMP6_SEC_SEND_SET = 0x44
+ ICMP6_SEC_SEND_SET_CGA_ADDR = 0x45
+ IFA_FIRSTALIAS = 0x2000
+ IFA_ROUTE = 0x1
+ IFF_64BIT = 0x4000000
+ IFF_ALLCAST = 0x20000
+ IFF_ALLMULTI = 0x200
+ IFF_BPF = 0x8000000
+ IFF_BRIDGE = 0x40000
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x80c52
+ IFF_CHECKSUM_OFFLOAD = 0x10000000
+ IFF_D1 = 0x8000
+ IFF_D2 = 0x4000
+ IFF_D3 = 0x2000
+ IFF_D4 = 0x1000
+ IFF_DEBUG = 0x4
+ IFF_DEVHEALTH = 0x4000
+ IFF_DO_HW_LOOPBACK = 0x10000
+ IFF_GROUP_ROUTING = 0x2000000
+ IFF_IFBUFMGT = 0x800000
+ IFF_LINK0 = 0x100000
+ IFF_LINK1 = 0x200000
+ IFF_LINK2 = 0x400000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x80000
+ IFF_NOARP = 0x80
+ IFF_NOECHO = 0x800
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_PSEG = 0x40000000
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_SNAP = 0x8000
+ IFF_TCP_DISABLE_CKSUM = 0x20000000
+ IFF_TCP_NOCKSUM = 0x1000000
+ IFF_UP = 0x1
+ IFF_VIPA = 0x80000000
+ IFNAMSIZ = 0x10
+ IFO_FLUSH = 0x1
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_CEPT = 0x13
+ IFT_CLUSTER = 0x3e
+ IFT_DS3 = 0x1e
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FCS = 0x3a
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIFTUNNEL = 0x3c
+ IFT_HDH1822 = 0x3
+ IFT_HF = 0x3d
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IB = 0xc7
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SN = 0x38
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SP = 0x39
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_TUNNEL = 0x3b
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_VIPA = 0x37
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ IN_USE = 0x1
+ IPPROTO_AH = 0x33
+ IPPROTO_BIP = 0x53
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GIF = 0x8c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_LOCAL = 0x3f
+ IPPROTO_MAX = 0x100
+ IPPROTO_MH = 0x87
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PUP = 0xc
+ IPPROTO_QOS = 0x2d
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPV6_ADDRFORM = 0x16
+ IPV6_ADDR_PREFERENCES = 0x4a
+ IPV6_ADD_MEMBERSHIP = 0xc
+ IPV6_AIXRAWSOCKET = 0x39
+ IPV6_CHECKSUM = 0x27
+ IPV6_DONTFRAG = 0x2d
+ IPV6_DROP_MEMBERSHIP = 0xd
+ IPV6_DSTOPTS = 0x36
+ IPV6_FLOWINFO_FLOWLABEL = 0xffffff
+ IPV6_FLOWINFO_PRIFLOW = 0xfffffff
+ IPV6_FLOWINFO_PRIORITY = 0xf000000
+ IPV6_FLOWINFO_SRFLAG = 0x10000000
+ IPV6_FLOWINFO_VERSION = 0xf0000000
+ IPV6_HOPLIMIT = 0x28
+ IPV6_HOPOPTS = 0x34
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MIPDSTOPTS = 0x36
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_NOPROBE = 0x1c
+ IPV6_PATHMTU = 0x2e
+ IPV6_PKTINFO = 0x21
+ IPV6_PKTOPTIONS = 0x24
+ IPV6_PRIORITY_10 = 0xa000000
+ IPV6_PRIORITY_11 = 0xb000000
+ IPV6_PRIORITY_12 = 0xc000000
+ IPV6_PRIORITY_13 = 0xd000000
+ IPV6_PRIORITY_14 = 0xe000000
+ IPV6_PRIORITY_15 = 0xf000000
+ IPV6_PRIORITY_8 = 0x8000000
+ IPV6_PRIORITY_9 = 0x9000000
+ IPV6_PRIORITY_BULK = 0x4000000
+ IPV6_PRIORITY_CONTROL = 0x7000000
+ IPV6_PRIORITY_FILLER = 0x1000000
+ IPV6_PRIORITY_INTERACTIVE = 0x6000000
+ IPV6_PRIORITY_RESERVED1 = 0x3000000
+ IPV6_PRIORITY_RESERVED2 = 0x5000000
+ IPV6_PRIORITY_UNATTENDED = 0x2000000
+ IPV6_PRIORITY_UNCHARACTERIZED = 0x0
+ IPV6_RECVDSTOPTS = 0x38
+ IPV6_RECVHOPLIMIT = 0x29
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVHOPS = 0x22
+ IPV6_RECVIF = 0x1e
+ IPV6_RECVPATHMTU = 0x2f
+ IPV6_RECVPKTINFO = 0x23
+ IPV6_RECVRTHDR = 0x33
+ IPV6_RECVSRCRT = 0x1d
+ IPV6_RECVTCLASS = 0x2a
+ IPV6_RTHDR = 0x32
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_RTHDR_TYPE_2 = 0x2
+ IPV6_SENDIF = 0x1f
+ IPV6_SRFLAG_LOOSE = 0x0
+ IPV6_SRFLAG_STRICT = 0x10000000
+ IPV6_TCLASS = 0x2b
+ IPV6_TOKEN_LENGTH = 0x40
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_USE_MIN_MTU = 0x2c
+ IPV6_V6ONLY = 0x25
+ IPV6_VERSION = 0x60000000
+ IP_ADDRFORM = 0x16
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_ADD_SOURCE_MEMBERSHIP = 0x3c
+ IP_BLOCK_SOURCE = 0x3a
+ IP_BROADCAST_IF = 0x10
+ IP_CACHE_LINE_SIZE = 0x80
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DHCPMODE = 0x11
+ IP_DONTFRAG = 0x19
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DROP_SOURCE_MEMBERSHIP = 0x3d
+ IP_FINDPMTU = 0x1a
+ IP_HDRINCL = 0x2
+ IP_INC_MEMBERSHIPS = 0x14
+ IP_INIT_MEMBERSHIP = 0x14
+ IP_MAXPACKET = 0xffff
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_HOPS = 0xa
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_OPT = 0x1b
+ IP_OPTIONS = 0x1
+ IP_PMTUAGE = 0x1b
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVIFINFO = 0xf
+ IP_RECVINTERFACE = 0x20
+ IP_RECVMACHDR = 0xe
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x22
+ IP_RETOPTS = 0x8
+ IP_SOURCE_FILTER = 0x48
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x3b
+ IP_UNICAST_HOPS = 0x4
+ I_FLUSH = 0x20005305
+ LNOFLSH = 0x8000
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_SPACEAVAIL = 0x5
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x10
+ MAP_ANONYMOUS = 0x10
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x100
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_TYPE = 0xf0
+ MAP_VARIABLE = 0x0
+ MCL_CURRENT = 0x100
+ MCL_FUTURE = 0x200
+ MSG_ANY = 0x4
+ MSG_ARGEXT = 0x400
+ MSG_BAND = 0x2
+ MSG_COMPAT = 0x8000
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_EOR = 0x8
+ MSG_HIPRI = 0x1
+ MSG_MAXIOVLEN = 0x10
+ MSG_MPEG2 = 0x80
+ MSG_NONBLOCK = 0x4000
+ MSG_NOSIGNAL = 0x100
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITFORONE = 0x200
+ MS_ASYNC = 0x10
+ MS_EINTR = 0x80
+ MS_INVALIDATE = 0x40
+ MS_PER_SEC = 0x3e8
+ MS_SYNC = 0x20
+ NOFLUSH = 0x80000000
+ O_ACCMODE = 0x23
+ O_APPEND = 0x8
+ O_CIO = 0x80
+ O_CIOR = 0x800000000
+ O_CLOEXEC = 0x800000
+ O_CREAT = 0x100
+ O_DEFER = 0x2000
+ O_DELAY = 0x4000
+ O_DIRECT = 0x8000000
+ O_DIRECTORY = 0x80000
+ O_DSYNC = 0x400000
+ O_EFSOFF = 0x400000000
+ O_EFSON = 0x200000000
+ O_EXCL = 0x400
+ O_EXEC = 0x20
+ O_LARGEFILE = 0x4000000
+ O_NDELAY = 0x8000
+ O_NOCACHE = 0x100000
+ O_NOCTTY = 0x800
+ O_NOFOLLOW = 0x1000000
+ O_NONBLOCK = 0x4
+ O_NONE = 0x3
+ O_NSHARE = 0x10000
+ O_RAW = 0x100000000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSHARE = 0x1000
+ O_RSYNC = 0x200000
+ O_SEARCH = 0x20
+ O_SNAPSHOT = 0x40
+ O_SYNC = 0x10
+ O_TRUNC = 0x200
+ O_TTY_INIT = 0x0
+ O_WRONLY = 0x1
+ PENDIN = 0x20000000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PR_64BIT = 0x20
+ PR_ADDR = 0x2
+ PR_ARGEXT = 0x400
+ PR_ATOMIC = 0x1
+ PR_CONNREQUIRED = 0x4
+ PR_FASTHZ = 0x5
+ PR_INP = 0x40
+ PR_INTRLEVEL = 0x8000
+ PR_MLS = 0x100
+ PR_MLS_1_LABEL = 0x200
+ PR_NOEOR = 0x4000
+ PR_RIGHTS = 0x10
+ PR_SLOWHZ = 0x2
+ PR_WANTRCVD = 0x8
+ PT_ATTACH = 0x1e
+ PT_CLEAR = 0x26
+ PT_COMMAND_MAX = 0x45
+ PT_CONTINUE = 0x7
+ PT_DETACH = 0x1f
+ PT_GET_UKEY = 0x40
+ PT_KILL = 0x8
+ PT_LDINFO = 0x22
+ PT_LDXINFO = 0x27
+ PT_MULTI = 0x23
+ PT_NEXT = 0x24
+ PT_QUERY = 0x28
+ PT_READ_BLOCK = 0x11
+ PT_READ_D = 0x2
+ PT_READ_FPR = 0xc
+ PT_READ_GPR = 0xb
+ PT_READ_I = 0x1
+ PT_REATT = 0x21
+ PT_REGSET = 0x20
+ PT_SET = 0x25
+ PT_STEP = 0x9
+ PT_TRACE_ME = 0x0
+ PT_WATCH = 0x29
+ PT_WRITE_BLOCK = 0x13
+ PT_WRITE_D = 0x5
+ PT_WRITE_FPR = 0xf
+ PT_WRITE_GPR = 0xe
+ PT_WRITE_I = 0x4
+ RLIMIT_AS = 0x6
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DOWNSTREAM = 0x100
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_ACTIVE_DGD = 0x1000000
+ RTF_BCE = 0x80000
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_BUL = 0x2000
+ RTF_CLONE = 0x10000
+ RTF_CLONED = 0x20000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FREE_IN_PROG = 0x4000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PERMANENT6 = 0x8000000
+ RTF_PINNED = 0x100000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_SMALLMTU = 0x40000
+ RTF_STATIC = 0x800
+ RTF_STOPSRCH = 0x2000000
+ RTF_UNREACHABLE = 0x10000000
+ RTF_UP = 0x1
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_EXPIRE = 0xf
+ RTM_GET = 0x4
+ RTM_GETNEXT = 0x11
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTLOST = 0x10
+ RTM_RTTUNIT = 0xf4240
+ RTM_SAMEADDR = 0x12
+ RTM_SET = 0x13
+ RTM_VERSION = 0x2
+ RTM_VERSION_GR = 0x4
+ RTM_VERSION_GR_COMPAT = 0x3
+ RTM_VERSION_POLICY = 0x5
+ RTM_VERSION_POLICY_EXT = 0x6
+ RTM_VERSION_POLICY_PRFN = 0x7
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_RIGHTS = 0x1
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGQUEUE_MAX = 0x20
+ SIOCADDIFVIPA = 0x20006942
+ SIOCADDMTU = -0x7ffb9690
+ SIOCADDMULTI = -0x7fdf96cf
+ SIOCADDNETID = -0x7fd796a9
+ SIOCADDRT = -0x7fc78df6
+ SIOCAIFADDR = -0x7fbf96e6
+ SIOCATMARK = 0x40047307
+ SIOCDARP = -0x7fb396e0
+ SIOCDELIFVIPA = 0x20006943
+ SIOCDELMTU = -0x7ffb968f
+ SIOCDELMULTI = -0x7fdf96ce
+ SIOCDELPMTU = -0x7fd78ff6
+ SIOCDELRT = -0x7fc78df5
+ SIOCDIFADDR = -0x7fd796e7
+ SIOCDNETOPT = -0x3ffe9680
+ SIOCDX25XLATE = -0x7fd7969b
+ SIOCFIFADDR = -0x7fdf966d
+ SIOCGARP = -0x3fb396da
+ SIOCGETMTUS = 0x2000696f
+ SIOCGETSGCNT = -0x3feb8acc
+ SIOCGETVIFCNT = -0x3feb8acd
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = -0x3fd796df
+ SIOCGIFADDRS = 0x2000698c
+ SIOCGIFBAUDRATE = -0x3fd79693
+ SIOCGIFBRDADDR = -0x3fd796dd
+ SIOCGIFCONF = -0x3fef96bb
+ SIOCGIFCONFGLOB = -0x3fef9670
+ SIOCGIFDSTADDR = -0x3fd796de
+ SIOCGIFFLAGS = -0x3fd796ef
+ SIOCGIFGIDLIST = 0x20006968
+ SIOCGIFHWADDR = -0x3fab966b
+ SIOCGIFMETRIC = -0x3fd796e9
+ SIOCGIFMTU = -0x3fd796aa
+ SIOCGIFNETMASK = -0x3fd796db
+ SIOCGIFOPTIONS = -0x3fd796d6
+ SIOCGISNO = -0x3fd79695
+ SIOCGLOADF = -0x3ffb967e
+ SIOCGLOWAT = 0x40047303
+ SIOCGNETOPT = -0x3ffe96a5
+ SIOCGNETOPT1 = -0x3fdf967f
+ SIOCGNMTUS = 0x2000696e
+ SIOCGPGRP = 0x40047309
+ SIOCGSIZIFCONF = 0x4004696a
+ SIOCGSRCFILTER = -0x3fe796cb
+ SIOCGTUNEPHASE = -0x3ffb9676
+ SIOCGX25XLATE = -0x3fd7969c
+ SIOCIFATTACH = -0x7fdf9699
+ SIOCIFDETACH = -0x7fdf969a
+ SIOCIFGETPKEY = -0x7fdf969b
+ SIOCIF_ATM_DARP = -0x7fdf9683
+ SIOCIF_ATM_DUMPARP = -0x7fdf9685
+ SIOCIF_ATM_GARP = -0x7fdf9682
+ SIOCIF_ATM_IDLE = -0x7fdf9686
+ SIOCIF_ATM_SARP = -0x7fdf9681
+ SIOCIF_ATM_SNMPARP = -0x7fdf9687
+ SIOCIF_ATM_SVC = -0x7fdf9684
+ SIOCIF_ATM_UBR = -0x7fdf9688
+ SIOCIF_DEVHEALTH = -0x7ffb966c
+ SIOCIF_IB_ARP_INCOMP = -0x7fdf9677
+ SIOCIF_IB_ARP_TIMER = -0x7fdf9678
+ SIOCIF_IB_CLEAR_PINFO = -0x3fdf966f
+ SIOCIF_IB_DEL_ARP = -0x7fdf967f
+ SIOCIF_IB_DEL_PINFO = -0x3fdf9670
+ SIOCIF_IB_DUMP_ARP = -0x7fdf9680
+ SIOCIF_IB_GET_ARP = -0x7fdf967e
+ SIOCIF_IB_GET_INFO = -0x3f879675
+ SIOCIF_IB_GET_STATS = -0x3f879672
+ SIOCIF_IB_NOTIFY_ADDR_REM = -0x3f87966a
+ SIOCIF_IB_RESET_STATS = -0x3f879671
+ SIOCIF_IB_RESIZE_CQ = -0x7fdf9679
+ SIOCIF_IB_SET_ARP = -0x7fdf967d
+ SIOCIF_IB_SET_PKEY = -0x7fdf967c
+ SIOCIF_IB_SET_PORT = -0x7fdf967b
+ SIOCIF_IB_SET_QKEY = -0x7fdf9676
+ SIOCIF_IB_SET_QSIZE = -0x7fdf967a
+ SIOCLISTIFVIPA = 0x20006944
+ SIOCSARP = -0x7fb396e2
+ SIOCSHIWAT = 0xffffffff80047300
+ SIOCSIFADDR = -0x7fd796f4
+ SIOCSIFADDRORI = -0x7fdb9673
+ SIOCSIFBRDADDR = -0x7fd796ed
+ SIOCSIFDSTADDR = -0x7fd796f2
+ SIOCSIFFLAGS = -0x7fd796f0
+ SIOCSIFGIDLIST = 0x20006969
+ SIOCSIFMETRIC = -0x7fd796e8
+ SIOCSIFMTU = -0x7fd796a8
+ SIOCSIFNETDUMP = -0x7fd796e4
+ SIOCSIFNETMASK = -0x7fd796ea
+ SIOCSIFOPTIONS = -0x7fd796d7
+ SIOCSIFSUBCHAN = -0x7fd796e5
+ SIOCSISNO = -0x7fd79694
+ SIOCSLOADF = -0x3ffb967d
+ SIOCSLOWAT = 0xffffffff80047302
+ SIOCSNETOPT = -0x7ffe96a6
+ SIOCSPGRP = 0xffffffff80047308
+ SIOCSX25XLATE = -0x7fd7969d
+ SOCK_CONN_DGRAM = 0x6
+ SOCK_DGRAM = 0x2
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x400
+ SO_ACCEPTCONN = 0x2
+ SO_AUDIT = 0x8000
+ SO_BROADCAST = 0x20
+ SO_CKSUMRECV = 0x800
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_KERNACCEPT = 0x2000
+ SO_LINGER = 0x80
+ SO_NOMULTIPATH = 0x4000
+ SO_NOREUSEADDR = 0x1000
+ SO_OOBINLINE = 0x100
+ SO_PEERID = 0x1009
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMPNS = 0x100a
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ SO_USE_IFBUFS = 0x400
+ S_BANDURG = 0x400
+ S_EMODFMT = 0x3c000000
+ S_ENFMT = 0x400
+ S_ERROR = 0x100
+ S_HANGUP = 0x200
+ S_HIPRI = 0x2
+ S_ICRYPTO = 0x80000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFJOURNAL = 0x10000
+ S_IFLNK = 0xa000
+ S_IFMPX = 0x2200
+ S_IFMT = 0xf000
+ S_IFPDIR = 0x4000000
+ S_IFPSDIR = 0x8000000
+ S_IFPSSDIR = 0xc000000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFSYSEA = 0x30000000
+ S_INPUT = 0x1
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_ITCB = 0x1000000
+ S_ITP = 0x800000
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXACL = 0x2000000
+ S_IXATTR = 0x40000
+ S_IXGRP = 0x8
+ S_IXINTERFACE = 0x100000
+ S_IXMOD = 0x40000000
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ S_MSG = 0x8
+ S_OUTPUT = 0x4
+ S_RDBAND = 0x20
+ S_RDNORM = 0x10
+ S_RESERVED1 = 0x20000
+ S_RESERVED2 = 0x200000
+ S_RESERVED3 = 0x400000
+ S_RESERVED4 = 0x80000000
+ S_RESFMT1 = 0x10000000
+ S_RESFMT10 = 0x34000000
+ S_RESFMT11 = 0x38000000
+ S_RESFMT12 = 0x3c000000
+ S_RESFMT2 = 0x14000000
+ S_RESFMT3 = 0x18000000
+ S_RESFMT4 = 0x1c000000
+ S_RESFMT5 = 0x20000000
+ S_RESFMT6 = 0x24000000
+ S_RESFMT7 = 0x28000000
+ S_RESFMT8 = 0x2c000000
+ S_WRBAND = 0x80
+ S_WRNORM = 0x40
+ TCP_24DAYS_WORTH_OF_SLOWTICKS = 0x3f4800
+ TCP_ACLADD = 0x23
+ TCP_ACLBIND = 0x26
+ TCP_ACLCLEAR = 0x22
+ TCP_ACLDEL = 0x24
+ TCP_ACLDENY = 0x8
+ TCP_ACLFLUSH = 0x21
+ TCP_ACLGID = 0x1
+ TCP_ACLLS = 0x25
+ TCP_ACLSUBNET = 0x4
+ TCP_ACLUID = 0x2
+ TCP_CWND_DF = 0x16
+ TCP_CWND_IF = 0x15
+ TCP_DELAY_ACK_FIN = 0x2
+ TCP_DELAY_ACK_SYN = 0x1
+ TCP_FASTNAME = 0x101080a
+ TCP_KEEPCNT = 0x13
+ TCP_KEEPIDLE = 0x11
+ TCP_KEEPINTVL = 0x12
+ TCP_LSPRIV = 0x29
+ TCP_LUID = 0x20
+ TCP_MAXBURST = 0x8
+ TCP_MAXDF = 0x64
+ TCP_MAXIF = 0x64
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAXWINDOWSCALE = 0xe
+ TCP_MAX_SACK = 0x4
+ TCP_MSS = 0x5b4
+ TCP_NODELAY = 0x1
+ TCP_NODELAYACK = 0x14
+ TCP_NOREDUCE_CWND_EXIT_FRXMT = 0x19
+ TCP_NOREDUCE_CWND_IN_FRXMT = 0x18
+ TCP_NOTENTER_SSTART = 0x17
+ TCP_OPT = 0x19
+ TCP_RFC1323 = 0x4
+ TCP_SETPRIV = 0x27
+ TCP_STDURG = 0x10
+ TCP_TIMESTAMP_OPTLEN = 0xc
+ TCP_UNSETPRIV = 0x28
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0xffffffff80047462
+ TIOCEXCL = 0x2000740d
+ TIOCFLUSH = 0xffffffff80047410
+ TIOCGETC = 0x40067412
+ TIOCGETD = 0x40047400
+ TIOCGETP = 0x40067408
+ TIOCGLTC = 0x40067474
+ TIOCGPGRP = 0x40047477
+ TIOCGSID = 0x40047448
+ TIOCGSIZE = 0x40087468
+ TIOCGWINSZ = 0x40087468
+ TIOCHPCL = 0x20007402
+ TIOCLBIC = 0xffffffff8004747e
+ TIOCLBIS = 0xffffffff8004747f
+ TIOCLGET = 0x4004747c
+ TIOCLSET = 0xffffffff8004747d
+ TIOCMBIC = 0xffffffff8004746b
+ TIOCMBIS = 0xffffffff8004746c
+ TIOCMGET = 0x4004746a
+ TIOCMIWAIT = 0xffffffff80047464
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0xffffffff80047404
+ TIOCMSET = 0xffffffff8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0xffffffff80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCREMOTE = 0xffffffff80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSDTR = 0x20007479
+ TIOCSETC = 0xffffffff80067411
+ TIOCSETD = 0xffffffff80047401
+ TIOCSETN = 0xffffffff8006740a
+ TIOCSETP = 0xffffffff80067409
+ TIOCSLTC = 0xffffffff80067475
+ TIOCSPGRP = 0xffffffff80047476
+ TIOCSSIZE = 0xffffffff80087467
+ TIOCSTART = 0x2000746e
+ TIOCSTI = 0xffffffff80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0xffffffff80087467
+ TIOCUCNTL = 0xffffffff80047466
+ TOSTOP = 0x10000
+ VTDELAY = 0x2000
+ WPARSTART = 0x1
+ WPARSTOP = 0x2
+ WPARTTYNAME = "Global"
+ _FDATAFLUSH = 0x2000000000
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x43)
+ EADDRNOTAVAIL = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x42)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x38)
+ EBADF = Errno(0x9)
+ EBADMSG = Errno(0x78)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x75)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x25)
+ ECLONEME = Errno(0x52)
+ ECONNABORTED = Errno(0x48)
+ ECONNREFUSED = Errno(0x4f)
+ ECONNRESET = Errno(0x49)
+ ECORRUPT = Errno(0x59)
+ EDEADLK = Errno(0x2d)
+ EDESTADDREQ = Errno(0x3a)
+ EDESTADDRREQ = Errno(0x3a)
+ EDIST = Errno(0x35)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x58)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFORMAT = Errno(0x30)
+ EHOSTDOWN = Errno(0x50)
+ EHOSTUNREACH = Errno(0x51)
+ EIDRM = Errno(0x24)
+ EILSEQ = Errno(0x74)
+ EINPROGRESS = Errno(0x37)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x4b)
+ EISDIR = Errno(0x15)
+ EL2HLT = Errno(0x2c)
+ EL2NSYNC = Errno(0x26)
+ EL3HLT = Errno(0x27)
+ EL3RST = Errno(0x28)
+ ELNRNG = Errno(0x29)
+ ELOOP = Errno(0x55)
+ EMEDIA = Errno(0x6e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x3b)
+ EMULTIHOP = Errno(0x7d)
+ ENAMETOOLONG = Errno(0x56)
+ ENETDOWN = Errno(0x45)
+ ENETRESET = Errno(0x47)
+ ENETUNREACH = Errno(0x46)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x70)
+ ENOBUFS = Errno(0x4a)
+ ENOCONNECT = Errno(0x32)
+ ENOCSI = Errno(0x2b)
+ ENODATA = Errno(0x7a)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x31)
+ ENOLINK = Errno(0x7e)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x23)
+ ENOPROTOOPT = Errno(0x3d)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x76)
+ ENOSTR = Errno(0x7b)
+ ENOSYS = Errno(0x6d)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x4c)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x11)
+ ENOTREADY = Errno(0x2e)
+ ENOTRECOVERABLE = Errno(0x5e)
+ ENOTRUST = Errno(0x72)
+ ENOTSOCK = Errno(0x39)
+ ENOTSUP = Errno(0x7c)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x40)
+ EOVERFLOW = Errno(0x7f)
+ EOWNERDEAD = Errno(0x5f)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x41)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x53)
+ EPROTO = Errno(0x79)
+ EPROTONOSUPPORT = Errno(0x3e)
+ EPROTOTYPE = Errno(0x3c)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x5d)
+ ERESTART = Errno(0x52)
+ EROFS = Errno(0x1e)
+ ESAD = Errno(0x71)
+ ESHUTDOWN = Errno(0x4d)
+ ESOCKTNOSUPPORT = Errno(0x3f)
+ ESOFT = Errno(0x6f)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x34)
+ ESYSERROR = Errno(0x5a)
+ ETIME = Errno(0x77)
+ ETIMEDOUT = Errno(0x4e)
+ ETOOMANYREFS = Errno(0x73)
+ ETXTBSY = Errno(0x1a)
+ EUNATCH = Errno(0x2a)
+ EUSERS = Errno(0x54)
+ EWOULDBLOCK = Errno(0xb)
+ EWRPROTECT = Errno(0x2f)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGAIO = Signal(0x17)
+ SIGALRM = Signal(0xe)
+ SIGALRM1 = Signal(0x26)
+ SIGBUS = Signal(0xa)
+ SIGCAPI = Signal(0x31)
+ SIGCHLD = Signal(0x14)
+ SIGCLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGCPUFAIL = Signal(0x3b)
+ SIGDANGER = Signal(0x21)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGGRANT = Signal(0x3c)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOINT = Signal(0x10)
+ SIGIOT = Signal(0x6)
+ SIGKAP = Signal(0x3c)
+ SIGKILL = Signal(0x9)
+ SIGLOST = Signal(0x6)
+ SIGMAX = Signal(0xff)
+ SIGMAX32 = Signal(0x3f)
+ SIGMAX64 = Signal(0xff)
+ SIGMIGRATE = Signal(0x23)
+ SIGMSG = Signal(0x1b)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x17)
+ SIGPRE = Signal(0x24)
+ SIGPROF = Signal(0x20)
+ SIGPTY = Signal(0x17)
+ SIGPWR = Signal(0x1d)
+ SIGQUIT = Signal(0x3)
+ SIGRECONFIG = Signal(0x3a)
+ SIGRETRACT = Signal(0x3d)
+ SIGSAK = Signal(0x3f)
+ SIGSEGV = Signal(0xb)
+ SIGSOUND = Signal(0x3e)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGSYSERROR = Signal(0x30)
+ SIGTALRM = Signal(0x26)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVIRT = Signal(0x25)
+ SIGVTALRM = Signal(0x22)
+ SIGWAITING = Signal(0x27)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "not owner",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "I/O error",
+ 6: "no such device or address",
+ 7: "arg list too long",
+ 8: "exec format error",
+ 9: "bad file number",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "not enough space",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "file table overflow",
+ 24: "too many open files",
+ 25: "not a typewriter",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "argument out of domain",
+ 34: "result too large",
+ 35: "no message of desired type",
+ 36: "identifier removed",
+ 37: "channel number out of range",
+ 38: "level 2 not synchronized",
+ 39: "level 3 halted",
+ 40: "level 3 reset",
+ 41: "link number out of range",
+ 42: "protocol driver not attached",
+ 43: "no CSI structure available",
+ 44: "level 2 halted",
+ 45: "deadlock condition if locked",
+ 46: "device not ready",
+ 47: "write-protected media",
+ 48: "unformatted or incompatible media",
+ 49: "no locks available",
+ 50: "cannot Establish Connection",
+ 52: "missing file or filesystem",
+ 53: "requests blocked by Administrator",
+ 55: "operation now in progress",
+ 56: "operation already in progress",
+ 57: "socket operation on non-socket",
+ 58: "destination address required",
+ 59: "message too long",
+ 60: "protocol wrong type for socket",
+ 61: "protocol not available",
+ 62: "protocol not supported",
+ 63: "socket type not supported",
+ 64: "operation not supported on socket",
+ 65: "protocol family not supported",
+ 66: "addr family not supported by protocol",
+ 67: "address already in use",
+ 68: "can't assign requested address",
+ 69: "network is down",
+ 70: "network is unreachable",
+ 71: "network dropped connection on reset",
+ 72: "software caused connection abort",
+ 73: "connection reset by peer",
+ 74: "no buffer space available",
+ 75: "socket is already connected",
+ 76: "socket is not connected",
+ 77: "can't send after socket shutdown",
+ 78: "connection timed out",
+ 79: "connection refused",
+ 80: "host is down",
+ 81: "no route to host",
+ 82: "restart the system call",
+ 83: "too many processes",
+ 84: "too many users",
+ 85: "too many levels of symbolic links",
+ 86: "file name too long",
+ 88: "disk quota exceeded",
+ 89: "invalid file system control data detected",
+ 90: "for future use ",
+ 93: "item is not local to host",
+ 94: "state not recoverable ",
+ 95: "previous owner died ",
+ 109: "function not implemented",
+ 110: "media surface error",
+ 111: "I/O completed, but needs relocation",
+ 112: "no attribute found",
+ 113: "security Authentication Denied",
+ 114: "not a Trusted Program",
+ 115: "too many references: can't splice",
+ 116: "invalid wide character",
+ 117: "asynchronous I/O cancelled",
+ 118: "out of STREAMS resources",
+ 119: "system call timed out",
+ 120: "next message has wrong type",
+ 121: "error in protocol",
+ 122: "no message on stream head read q",
+ 123: "fd not associated with a stream",
+ 124: "unsupported attribute value",
+ 125: "multihop is not allowed",
+ 126: "the server link has been severed",
+ 127: "value too large to be stored in data type",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "IOT/Abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "stopped (signal)",
+ 18: "stopped",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible/complete",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 27: "input device data",
+ 28: "window size changes",
+ 29: "power-failure",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+ 32: "profiling timer expired",
+ 33: "paging space low",
+ 34: "virtual timer expired",
+ 35: "signal 35",
+ 36: "signal 36",
+ 37: "signal 37",
+ 38: "signal 38",
+ 39: "signal 39",
+ 48: "signal 48",
+ 49: "signal 49",
+ 58: "signal 58",
+ 59: "CPU Failure Predicted",
+ 60: "monitor mode granted",
+ 61: "monitor mode retracted",
+ 62: "sound completed",
+ 63: "secure attention",
+ 255: "signal 255",
+}
diff --git a/src/syscall/zsyscall_aix_ppc64.go b/src/syscall/zsyscall_aix_ppc64.go
new file mode 100644
index 0000000000..d9f009953f
--- /dev/null
+++ b/src/syscall/zsyscall_aix_ppc64.go
@@ -0,0 +1,1167 @@
+// mksyscall_lib.pl -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go
+// Code generated by the command above; DO NOT EDIT.
+
+// +build aix,ppc64
+
+package syscall
+
+import "unsafe"
+
+//go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_dup2 dup2 "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_pipe pipe "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_readlink readlink "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_utimes utimes "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_utimensat utimensat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_unlinkat unlinkat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getcwd getcwd "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getgroups getgroups "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setgroups setgroups "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getdirent getdirent "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_wait4 wait4 "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_bind bind "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_connect connect "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getkerninfo getkerninfo "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getsockopt getsockopt "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Listen listen "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_setsockopt setsockopt "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_socket socket "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_socketpair socketpair "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getpeername getpeername "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_getsockname getsockname "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_recvfrom recvfrom "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_sendto sendto "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Shutdown shutdown "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_recvmsg recvmsg "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_sendmsg sendmsg "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_accept accept "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Openat openat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_ptrace64 ptrace64 "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Acct acct "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Chdir chdir "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Chmod chmod "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Chown chown "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Close close "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Dup dup "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Faccessat faccessat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fchdir fchdir "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fchmod fchmod "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fchmodat fchmodat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fchown fchown "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fchownat fchownat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fpathconf fpathconf "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fstat fstat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fstatfs fstatfs "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Ftruncate ftruncate "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Fsync fsync "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getgid getgid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getpid getpid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Geteuid geteuid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getegid getegid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getppid getppid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getrlimit getrlimit "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Getuid getuid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Kill kill "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Lchown lchown "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Link link "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Lstat lstat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Mkdir mkdir "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Mkdirat mkdirat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Mknodat mknodat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Open open "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Pread pread "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Pwrite pwrite "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_read read "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Reboot reboot "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Rename rename "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Renameat renameat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Rmdir rmdir "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_lseek lseek "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Setegid setegid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Seteuid seteuid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Setgid setgid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Setpgid setpgid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Setregid setregid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Setreuid setreuid "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Stat stat "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Statfs statfs "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Symlink symlink "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Truncate truncate "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Umask umask "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Unlink unlink "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_Uname uname "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_write write "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_gettimeofday gettimeofday "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_mmap mmap "libc.a/shr_64.o"
+//go:cgo_import_dynamic libc_munmap munmap "libc.a/shr_64.o"
+
+//go:linkname libc_fcntl libc_fcntl
+//go:linkname libc_dup2 libc_dup2
+//go:linkname libc_pipe libc_pipe
+//go:linkname libc_readlink libc_readlink
+//go:linkname libc_utimes libc_utimes
+//go:linkname libc_utimensat libc_utimensat
+//go:linkname libc_unlinkat libc_unlinkat
+//go:linkname libc_getcwd libc_getcwd
+//go:linkname libc_getgroups libc_getgroups
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_getdirent libc_getdirent
+//go:linkname libc_wait4 libc_wait4
+//go:linkname libc_bind libc_bind
+//go:linkname libc_connect libc_connect
+//go:linkname libc_Getkerninfo libc_Getkerninfo
+//go:linkname libc_getsockopt libc_getsockopt
+//go:linkname libc_Listen libc_Listen
+//go:linkname libc_setsockopt libc_setsockopt
+//go:linkname libc_socket libc_socket
+//go:linkname libc_socketpair libc_socketpair
+//go:linkname libc_getpeername libc_getpeername
+//go:linkname libc_getsockname libc_getsockname
+//go:linkname libc_recvfrom libc_recvfrom
+//go:linkname libc_sendto libc_sendto
+//go:linkname libc_Shutdown libc_Shutdown
+//go:linkname libc_recvmsg libc_recvmsg
+//go:linkname libc_sendmsg libc_sendmsg
+//go:linkname libc_accept libc_accept
+//go:linkname libc_Openat libc_Openat
+//go:linkname libc_ptrace64 libc_ptrace64
+//go:linkname libc_Acct libc_Acct
+//go:linkname libc_Chdir libc_Chdir
+//go:linkname libc_Chmod libc_Chmod
+//go:linkname libc_Chown libc_Chown
+//go:linkname libc_Close libc_Close
+//go:linkname libc_Dup libc_Dup
+//go:linkname libc_Faccessat libc_Faccessat
+//go:linkname libc_Fchdir libc_Fchdir
+//go:linkname libc_Fchmod libc_Fchmod
+//go:linkname libc_Fchmodat libc_Fchmodat
+//go:linkname libc_Fchown libc_Fchown
+//go:linkname libc_Fchownat libc_Fchownat
+//go:linkname libc_Fpathconf libc_Fpathconf
+//go:linkname libc_Fstat libc_Fstat
+//go:linkname libc_Fstatfs libc_Fstatfs
+//go:linkname libc_Ftruncate libc_Ftruncate
+//go:linkname libc_Fsync libc_Fsync
+//go:linkname libc_Getgid libc_Getgid
+//go:linkname libc_Getpid libc_Getpid
+//go:linkname libc_Geteuid libc_Geteuid
+//go:linkname libc_Getegid libc_Getegid
+//go:linkname libc_Getppid libc_Getppid
+//go:linkname libc_Getrlimit libc_Getrlimit
+//go:linkname libc_Getuid libc_Getuid
+//go:linkname libc_Kill libc_Kill
+//go:linkname libc_Lchown libc_Lchown
+//go:linkname libc_Link libc_Link
+//go:linkname libc_Lstat libc_Lstat
+//go:linkname libc_Mkdir libc_Mkdir
+//go:linkname libc_Mkdirat libc_Mkdirat
+//go:linkname libc_Mknodat libc_Mknodat
+//go:linkname libc_Open libc_Open
+//go:linkname libc_Pread libc_Pread
+//go:linkname libc_Pwrite libc_Pwrite
+//go:linkname libc_read libc_read
+//go:linkname libc_Reboot libc_Reboot
+//go:linkname libc_Rename libc_Rename
+//go:linkname libc_Renameat libc_Renameat
+//go:linkname libc_Rmdir libc_Rmdir
+//go:linkname libc_lseek libc_lseek
+//go:linkname libc_Setegid libc_Setegid
+//go:linkname libc_Seteuid libc_Seteuid
+//go:linkname libc_Setgid libc_Setgid
+//go:linkname libc_Setpgid libc_Setpgid
+//go:linkname libc_Setregid libc_Setregid
+//go:linkname libc_Setreuid libc_Setreuid
+//go:linkname libc_Stat libc_Stat
+//go:linkname libc_Statfs libc_Statfs
+//go:linkname libc_Symlink libc_Symlink
+//go:linkname libc_Truncate libc_Truncate
+//go:linkname libc_Umask libc_Umask
+//go:linkname libc_Unlink libc_Unlink
+//go:linkname libc_Uname libc_Uname
+//go:linkname libc_write libc_write
+//go:linkname libc_gettimeofday libc_gettimeofday
+//go:linkname libc_mmap libc_mmap
+//go:linkname libc_munmap libc_munmap
+
+type libcFunc uintptr
+
+var (
+ libc_fcntl,
+ libc_dup2,
+ libc_pipe,
+ libc_readlink,
+ libc_utimes,
+ libc_utimensat,
+ libc_unlinkat,
+ libc_getcwd,
+ libc_getgroups,
+ libc_setgroups,
+ libc_getdirent,
+ libc_wait4,
+ libc_bind,
+ libc_connect,
+ libc_Getkerninfo,
+ libc_getsockopt,
+ libc_Listen,
+ libc_setsockopt,
+ libc_socket,
+ libc_socketpair,
+ libc_getpeername,
+ libc_getsockname,
+ libc_recvfrom,
+ libc_sendto,
+ libc_Shutdown,
+ libc_recvmsg,
+ libc_sendmsg,
+ libc_accept,
+ libc_Openat,
+ libc_ptrace64,
+ libc_Acct,
+ libc_Chdir,
+ libc_Chmod,
+ libc_Chown,
+ libc_Close,
+ libc_Dup,
+ libc_Faccessat,
+ libc_Fchdir,
+ libc_Fchmod,
+ libc_Fchmodat,
+ libc_Fchown,
+ libc_Fchownat,
+ libc_Fpathconf,
+ libc_Fstat,
+ libc_Fstatfs,
+ libc_Ftruncate,
+ libc_Fsync,
+ libc_Getgid,
+ libc_Getpid,
+ libc_Geteuid,
+ libc_Getegid,
+ libc_Getppid,
+ libc_Getrlimit,
+ libc_Getuid,
+ libc_Kill,
+ libc_Lchown,
+ libc_Link,
+ libc_Lstat,
+ libc_Mkdir,
+ libc_Mkdirat,
+ libc_Mknodat,
+ libc_Open,
+ libc_Pread,
+ libc_Pwrite,
+ libc_read,
+ libc_Reboot,
+ libc_Rename,
+ libc_Renameat,
+ libc_Rmdir,
+ libc_lseek,
+ libc_Setegid,
+ libc_Seteuid,
+ libc_Setgid,
+ libc_Setpgid,
+ libc_Setregid,
+ libc_Setreuid,
+ libc_Stat,
+ libc_Statfs,
+ libc_Symlink,
+ libc_Truncate,
+ libc_Umask,
+ libc_Unlink,
+ libc_Uname,
+ libc_write,
+ libc_gettimeofday,
+ libc_mmap,
+ libc_munmap libcFunc
+)
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func dup2(old int, new int) (val int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_dup2)), 2, uintptr(old), uintptr(new), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func pipe(p *[2]_C_int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_pipe)), 1, uintptr(unsafe.Pointer(p)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func readlink(path string, buf []byte, bufSize uint64) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ if len(buf) > 0 {
+ _p1 = &buf[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_readlink)), 4, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), uintptr(bufSize), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_utimes)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_utimensat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flag), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func unlinkat(dirfd int, path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_unlinkat)), 3, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getcwd(buf *byte, size uint64) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getcwd)), 2, uintptr(unsafe.Pointer(buf)), uintptr(size), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getdirent(fd int, buf []byte) (n int, err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getdirent)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_wait4)), 4, uintptr(pid), uintptr(unsafe.Pointer(status)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = Pid_t(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Getkerninfo(op int32, where uintptr, size uintptr, arg int64) (i int32, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Getkerninfo)), 4, uintptr(op), uintptr(where), uintptr(size), uintptr(arg), 0, 0)
+ i = int32(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_recvfrom)), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_sendto)), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Openat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_ptrace64)), 5, uintptr(request), uintptr(id), uintptr(addr), uintptr(data), uintptr(buff), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Acct(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Acct)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Chdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Chmod)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Chown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Close(fd int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Faccessat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchmodat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchownat)), 5, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fstatfs)), 2, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Getgid() (gid int) {
+ r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+func Getpid() (pid int) {
+ r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+func Geteuid() (euid int) {
+ r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+func Getegid() (egid int) {
+ r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+func Getppid() (ppid int) {
+ r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Getuid() (uid int) {
+ r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+func Kill(pid int, signum Signal) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Lchown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Link(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Link)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Lstat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Mkdir)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Mkdirat)), 3, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Mknodat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Open)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Pread)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Pwrite)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Reboot(how int) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Reboot)), 1, uintptr(how), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Rename(from string, to string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(from)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(to)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Rename)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Renameat)), 4, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Rmdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+ newoffset = int64(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Stat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Statfs(path string, buf *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Statfs)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Symlink(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Symlink)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Truncate)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Unlink)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func Uname(buf *Utsname) (err error) {
+ _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Uname)), 1, uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 *byte
+ if len(p) > 0 {
+ _p0 = &p[0]
+ }
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func gettimeofday(tv *Timeval, tzp *Timezone) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_gettimeofday)), 2, uintptr(unsafe.Pointer(tv)), uintptr(unsafe.Pointer(tzp)), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_mmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
diff --git a/src/syscall/ztypes_aix_ppc64.go b/src/syscall/ztypes_aix_ppc64.go
new file mode 100644
index 0000000000..4fbbe23134
--- /dev/null
+++ b/src/syscall/ztypes_aix_ppc64.go
@@ -0,0 +1,272 @@
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_aix.go | go run mkpost.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x3ff
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Timeval32 struct {
+ Sec int32
+ Usec int32
+}
+
+type Timezone struct {
+ Minuteswest int32
+ Dsttime int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type Pid_t int32
+
+type _Gid_t uint32
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Sysid uint32
+ Pid int32
+ Vfs int32
+ Start int64
+ Len int64
+}
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Mode uint32
+ Nlink int16
+ Flag uint16
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ Ssize int32
+ Pad_cgo_0 [4]byte
+ Atim StTimespec_t
+ Mtim StTimespec_t
+ Ctim StTimespec_t
+ Blksize int64
+ Blocks int64
+ Vfstype int32
+ Vfs uint32
+ Type uint32
+ Gen uint32
+ Reserved [9]uint32
+ Padto_ll uint32
+ Size int64
+}
+
+type Statfs_t struct {
+ Version int32
+ Type int32
+ Bsize uint64
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid Fsid64_t
+ Vfstype int32
+ Pad_cgo_0 [4]byte
+ Fsize uint64
+ Vfsnumber int32
+ Vfsoff int32
+ Vfslen int32
+ Vfsvers int32
+ Fname [32]uint8
+ Fpack [32]uint8
+ Name_max int32
+ Pad_cgo_1 [4]byte
+}
+
+type Fsid64_t struct {
+ Val [2]uint64
+}
+
+type StTimespec_t struct {
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Dirent struct {
+ Offset uint64
+ Ino uint64
+ Reclen uint16
+ Namlen uint16
+ Name [256]uint8
+ Pad_cgo_0 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [1023]uint8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]uint8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [1012]uint8
+}
+
+type _Socklen uint32
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type ICMPv6Filter struct {
+ Filt [8]uint32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_cgo_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x404
+ SizeofSockaddrUnix = 0x401
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofICMPv6Filter = 0x20
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+const (
+ SizeofIfMsghdr = 0x10
+)
+
+type IfMsgHdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Addrlen uint8
+ Pad_cgo_0 [1]byte
+}
+
+type Utsname struct {
+ Sysname [32]uint8
+ Nodename [32]uint8
+ Release [32]uint8
+ Version [32]uint8
+ Machine [32]uint8
+}
+
+const (
+ _AT_FDCWD = -0x2
+ _AT_REMOVEDIR = 0x1
+ _AT_SYMLINK_NOFOLLOW = 0x1
+)
From f776d51bf7fe90926f8b929aee65d802a9091d5e Mon Sep 17 00:00:00 2001
From: Lynn Boger
Date: Wed, 26 Sep 2018 10:43:15 -0400
Subject: [PATCH 073/240] cmd/internal/obj/ppc64: generate float 0 more
efficiently on ppc64x
This change makes use of a VSX instruction to generate the
float 0 value instead of generating a constant in memory and
loading it from there.
This uses 1 instruction instead of 2 and avoids a memory reference.
in the +0 case, uses 2 instructions in the -0 case but avoids
the memory reference.
Since this is done in the assembler for ppc64x, an update has
been made to the assembler test.
Change-Id: Ief7dddcb057bfb602f78215f6947664e8c841464
Reviewed-on: https://go-review.googlesource.com/c/139420
Reviewed-by: Michael Munday
---
src/cmd/asm/internal/asm/testdata/ppc64enc.s | 3 +++
src/cmd/internal/obj/ppc64/asm9.go | 22 ++++++++++++++++++++
src/cmd/internal/obj/ppc64/obj9.go | 11 ++++++----
3 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64enc.s b/src/cmd/asm/internal/asm/testdata/ppc64enc.s
index 7ab1a578f8..0133a85b98 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64enc.s
@@ -98,4 +98,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
LDAR (R4),$0,R5 // 7ca020a8
LDAR (R3),R5 // 7ca018a8
+ // float constants
+ FMOVD $(0.0), F1 // f0210cd0
+ FMOVD $(-0.0), F1 // f0210cd0fc200850
RET
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 756170bc55..66a77b308c 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -35,6 +35,7 @@ import (
"encoding/binary"
"fmt"
"log"
+ "math"
"sort"
)
@@ -342,6 +343,8 @@ var optab = []Optab{
{AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB},
{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 36, 8, REGSP},
{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 36, 8, REGZERO},
+ {AFMOVD, C_ZCON, C_NONE, C_NONE, C_FREG, 24, 4, 0},
+ {AFMOVD, C_ADDCON, C_NONE, C_NONE, C_FREG, 24, 8, 0},
{AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
@@ -829,6 +832,18 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
case obj.TYPE_TEXTSIZE:
return C_TEXTSIZE
+ case obj.TYPE_FCONST:
+ // The only cases where FCONST will occur are with float64 +/- 0.
+ // All other float constants are generated in memory.
+ f64 := a.Val.(float64)
+ if f64 == 0 {
+ if math.Signbit(f64) {
+ return C_ADDCON
+ }
+ return C_ZCON
+ }
+ log.Fatalf("Unexpected nonzero FCONST operand %v", a)
+
case obj.TYPE_CONST,
obj.TYPE_ADDR:
switch a.Name {
@@ -2763,6 +2778,13 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
c.ctxt.Diag("%v is not supported", p)
}
+ case 24: /* lfd fA,float64(0) -> xxlxor xsA,xsaA,xsaA + fneg for -0 */
+ o1 = AOP_XX3I(c.oprrr(AXXLXOR), uint32(p.To.Reg), uint32(p.To.Reg), uint32(p.To.Reg), uint32(0))
+ // This is needed for -0.
+ if o.size == 8 {
+ o2 = AOP_RRR(c.oprrr(AFNEG), uint32(p.To.Reg), 0, uint32(p.To.Reg))
+ }
+
case 25:
/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
v := c.regoff(&p.From)
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index f42d675805..7a07b5058c 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -67,10 +67,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
case AFMOVD:
if p.From.Type == obj.TYPE_FCONST {
f64 := p.From.Val.(float64)
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = ctxt.Float64Sym(f64)
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
+ // Constant not needed in memory for float +/- 0
+ if f64 != 0 {
+ p.From.Type = obj.TYPE_MEM
+ p.From.Sym = ctxt.Float64Sym(f64)
+ p.From.Name = obj.NAME_EXTERN
+ p.From.Offset = 0
+ }
}
// Put >32-bit constants in memory and load them
From 1c88ce5f7bae4698b39cb7dbbb200f59c5b22a91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:32:52 +0200
Subject: [PATCH 074/240] time: add AIX operating system
This commit adds AIX operating system to time package for ppc64
architecture.
Updates: #25893
Change-Id: I4fb6fb47eae7671bf4e22729d6d160f557083c44
Reviewed-on: https://go-review.googlesource.com/c/138721
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/time/sys_unix.go | 2 +-
src/time/zoneinfo_unix.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go
index e064e0046c..f4756b18a6 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package time
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index 682e24b566..fca8e5497b 100644
--- a/src/time/zoneinfo_unix.go
+++ b/src/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,386 darwin,amd64 dragonfly freebsd js,wasm linux,!android nacl netbsd openbsd solaris
+// +build aix darwin,386 darwin,amd64 dragonfly freebsd js,wasm linux,!android nacl netbsd openbsd solaris
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
From 29907b13db0455eded50263b4e37445045c82e6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:42:19 +0200
Subject: [PATCH 075/240] crypto: add AIX operating system
This commit adds AIX operating system to crypto package for ppc64
architecture.
Updates: #25893
Change-Id: I20047ff2fef0051b8b235ec15b064c4a95c2b9c3
Reviewed-on: https://go-review.googlesource.com/c/138722
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/crypto/rand/eagain.go | 2 +-
src/crypto/rand/rand_unix.go | 2 +-
src/crypto/x509/root_aix.go | 10 ++++++++++
src/crypto/x509/root_unix.go | 3 ++-
4 files changed, 14 insertions(+), 3 deletions(-)
create mode 100644 src/crypto/x509/root_aix.go
diff --git a/src/crypto/rand/eagain.go b/src/crypto/rand/eagain.go
index 7ed2f47ea6..045d037d20 100644
--- a/src/crypto/rand/eagain.go
+++ b/src/crypto/rand/eagain.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package rand
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index d49f693746..f3091f51c5 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
// Unix cryptographically secure pseudorandom number
// generator.
diff --git a/src/crypto/x509/root_aix.go b/src/crypto/x509/root_aix.go
new file mode 100644
index 0000000000..6d427739a4
--- /dev/null
+++ b/src/crypto/x509/root_aix.go
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/var/ssl/certs/ca-bundle.crt",
+}
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index 8e7036234d..48de50b4ea 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package x509
@@ -19,6 +19,7 @@ var certDirectories = []string{
"/usr/local/share/certs", // FreeBSD
"/etc/pki/tls/certs", // Fedora/RHEL
"/etc/openssl/certs", // NetBSD
+ "/var/ssl/certs", // AIX
}
const (
From 05581fcc5c100cc2efa58355af8665cb93fed758 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:44:06 +0200
Subject: [PATCH 076/240] mime: add AIX operating system
This commit adds AIX operating system to mime package for ppc64
architecture.
Updates: #25893
Change-Id: I1b81a9204446c8c76ae24ea5c6fd33077c373ae4
Reviewed-on: https://go-review.googlesource.com/c/138723
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/mime/type_unix.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mime/type_unix.go b/src/mime/type_unix.go
index 6549c0f5e9..dfc1f88b2a 100644
--- a/src/mime/type_unix.go
+++ b/src/mime/type_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package mime
From ceb0c371d9a535826497289ac7d0b206a59526e6 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Mon, 8 Oct 2018 17:46:45 -0700
Subject: [PATCH 077/240] cmd/compile: make []byte("...") more efficient
Do []byte(string) conversions more efficiently when the string
is a constant. Instead of calling stringtobyteslice, allocate
just the space we need and encode the initialization directly.
[]byte("foo") rewrites to the following pseudocode:
var s [3]byte // on heap or stack, depending on whether b escapes
s = *(*[3]byte)(&"foo"[0]) // initialize s from the string
b = s[:]
which generates this assembly:
0x001d 00029 (tmp1.go:9) LEAQ type.[3]uint8(SB), AX
0x0024 00036 (tmp1.go:9) MOVQ AX, (SP)
0x0028 00040 (tmp1.go:9) CALL runtime.newobject(SB)
0x002d 00045 (tmp1.go:9) MOVQ 8(SP), AX
0x0032 00050 (tmp1.go:9) MOVBLZX go.string."foo"+2(SB), CX
0x0039 00057 (tmp1.go:9) MOVWLZX go.string."foo"(SB), DX
0x0040 00064 (tmp1.go:9) MOVW DX, (AX)
0x0043 00067 (tmp1.go:9) MOVB CL, 2(AX)
// Then the slice is b = {AX, 3, 3}
The generated code is still not optimal, as it still does load/store
from read-only memory instead of constant stores. Next CL...
Update #26498
Fixes #10170
Change-Id: I4b990b19f9a308f60c8f4f148934acffefe0a5bd
Reviewed-on: https://go-review.googlesource.com/c/140698
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/internal/gc/esc.go | 3 +-
src/cmd/compile/internal/gc/go.go | 12 +++++-
src/cmd/compile/internal/gc/walk.go | 37 +++++++++++++++++--
.../compile/internal/ssa/gen/generic.rules | 2 +-
.../compile/internal/ssa/rewritegeneric.go | 14 ++++---
test/codegen/strings.go | 7 ++++
6 files changed, 61 insertions(+), 14 deletions(-)
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index eba66d9c67..5beb43d548 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -798,9 +798,8 @@ func (e *EscState) esc(n *Node, parent *Node) {
// gathered here.
if n.Esc != EscHeap && n.Type != nil &&
(n.Type.Width > maxStackVarSize ||
- (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
+ (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
-
// isSmallMakeSlice returns false for non-constant len/cap.
// If that's the case, print a more accurate escape reason.
var msgVerb, escapeMsg string
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index d8ab5eb39c..605afd6407 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -13,8 +13,18 @@ import (
)
const (
- BADWIDTH = types.BADWIDTH
+ BADWIDTH = types.BADWIDTH
+
+ // maximum size variable which we will allocate on the stack.
+ // This limit is for explicit variable declarations like "var x T" or "x := ...".
maxStackVarSize = 10 * 1024 * 1024
+
+ // maximum size of implicit variables that we will allocate on the stack.
+ // p := new(T) allocating T on the stack
+ // p := &T{} allocating T on the stack
+ // s := make([]T, n) allocating [n]T on the stack
+ // s := []byte("...") allocating [n]byte on the stack
+ maxImplicitStackVarSize = 64 * 1024
)
// isRuntimePkg reports whether p is package runtime.
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 80fdc55b5d..c3201c1404 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -367,7 +367,7 @@ func isSmallMakeSlice(n *Node) bool {
}
t := n.Type
- return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
+ return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width)
}
// walk the whole tree of the body of an
@@ -1204,7 +1204,7 @@ opswitch:
case ONEW:
if n.Esc == EscNone {
- if n.Type.Elem().Width >= 1<<16 {
+ if n.Type.Elem().Width >= maxImplicitStackVarSize {
Fatalf("large ONEW with EscNone: %v", n)
}
r := temp(n.Type.Elem())
@@ -1593,8 +1593,36 @@ opswitch:
n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
- // stringtoslicebyte(*32[byte], string) []byte;
case OSTRARRAYBYTE:
+ s := n.Left
+ if Isconst(s, CTSTR) {
+ sc := s.Val().U.(string)
+
+ // Allocate a [n]byte of the right size.
+ t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
+ var a *Node
+ if n.Esc == EscNone && len(sc) <= maxImplicitStackVarSize {
+ a = nod(OADDR, temp(t), nil)
+ } else {
+ a = callnew(t)
+ }
+ p := temp(t.PtrTo()) // *[n]byte
+ init.Append(typecheck(nod(OAS, p, a), Etop))
+
+ // Copy from the static string data to the [n]byte.
+ if len(sc) > 0 {
+ as := nod(OAS,
+ nod(OIND, p, nil),
+ nod(OIND, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil))
+ init.Append(typecheck(as, Etop))
+ }
+
+ // Slice the [n]byte to a []byte.
+ n.Op = OSLICEARR
+ n.Left = p
+ n = walkexpr(n, init)
+ break
+ }
a := nodnil()
if n.Esc == EscNone {
@@ -1604,7 +1632,8 @@ opswitch:
a = nod(OADDR, temp(t), nil)
}
- n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
+ // stringtoslicebyte(*32[byte], string) []byte;
+ n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING]))
case OSTRARRAYBYTETMP:
// []byte(string) conversion that creates a slice
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index d490e32f3d..8d2691d29c 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -816,7 +816,7 @@
// Decomposing StringMake and lowering of StringPtr and StringLen
// happens in a later pass, dec, so that these operations are available
// to other passes for optimizations.
-(StringPtr (StringMake (Const64 [c]) _)) -> (Const64 [c])
+(StringPtr (StringMake (Addr {s} base) _)) -> (Addr {s} base)
(StringLen (StringMake _ (Const64 [c]))) -> (Const64 [c])
(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
(StringMake (ConstNil) (Const32 [0]))
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 2f239faa49..26341a9217 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -28748,9 +28748,9 @@ func rewriteValuegeneric_OpStringLen_0(v *Value) bool {
return false
}
func rewriteValuegeneric_OpStringPtr_0(v *Value) bool {
- // match: (StringPtr (StringMake (Const64 [c]) _))
+ // match: (StringPtr (StringMake (Addr {s} base) _))
// cond:
- // result: (Const64 [c])
+ // result: (Addr {s} base)
for {
v_0 := v.Args[0]
if v_0.Op != OpStringMake {
@@ -28758,14 +28758,16 @@ func rewriteValuegeneric_OpStringPtr_0(v *Value) bool {
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpConst64 {
+ if v_0_0.Op != OpAddr {
break
}
t := v_0_0.Type
- c := v_0_0.AuxInt
- v.reset(OpConst64)
+ s := v_0_0.Aux
+ base := v_0_0.Args[0]
+ v.reset(OpAddr)
v.Type = t
- v.AuxInt = c
+ v.Aux = s
+ v.AddArg(base)
return true
}
return false
diff --git a/test/codegen/strings.go b/test/codegen/strings.go
index ccb6bd4273..f4adfac0cc 100644
--- a/test/codegen/strings.go
+++ b/test/codegen/strings.go
@@ -13,3 +13,10 @@ func CountRunes(s string) int { // Issue #24923
// amd64:`.*countrunes`
return len([]rune(s))
}
+
+func ToByteSlice() []byte { // Issue #24698
+ // amd64:`LEAQ\ttype\.\[3\]uint8`
+ // amd64:`CALL\truntime\.newobject`
+ // amd64:-`.*runtime.stringtoslicebyte`
+ return []byte("foo")
+}
From 9ff11b026089791c4d2bc14c17647f3cb4f4aa22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:50:01 +0200
Subject: [PATCH 078/240] net: add AIX operating system
This commit adds AIX operating system to net package for ppc64
architecture.
Updates: #25893
Change-Id: I46bbc7b03931019beb969443cb3f9a756956c66c
Reviewed-on: https://go-review.googlesource.com/c/138724
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/net/addrselect.go | 2 +-
src/net/conf.go | 2 +-
src/net/dial_unix_test.go | 2 +-
src/net/dnsclient_unix.go | 2 +-
src/net/dnsclient_unix_test.go | 2 +-
src/net/dnsconfig_unix.go | 2 +-
src/net/dnsconfig_unix_test.go | 2 +-
src/net/error_posix.go | 2 +-
src/net/error_unix.go | 2 +-
src/net/fd_unix.go | 2 +-
src/net/file_unix.go | 2 +-
src/net/hook_unix.go | 2 +-
src/net/interface_aix.go | 165 +++++++++++++++++++++++
src/net/internal/socktest/switch_unix.go | 2 +-
src/net/internal/socktest/sys_unix.go | 2 +-
src/net/iprawsock_posix.go | 2 +-
src/net/ipsock_posix.go | 4 +-
src/net/listen_test.go | 2 +-
src/net/lookup_unix.go | 2 +-
src/net/main_unix_test.go | 2 +-
src/net/nss.go | 2 +-
src/net/platform_test.go | 2 +-
src/net/port_unix.go | 2 +-
src/net/rawconn_unix_test.go | 2 +-
src/net/sendfile_stub.go | 2 +-
src/net/sock_posix.go | 2 +-
src/net/sock_stub.go | 2 +-
src/net/sockaddr_posix.go | 2 +-
src/net/sockopt_aix.go | 38 ++++++
src/net/sockopt_posix.go | 2 +-
src/net/sockoptip_bsdvar.go | 2 +-
src/net/sockoptip_posix.go | 2 +-
src/net/sys_cloexec.go | 2 +-
src/net/tcpsock_posix.go | 2 +-
src/net/tcpsockopt_posix.go | 2 +-
src/net/tcpsockopt_unix.go | 2 +-
src/net/udpsock_posix.go | 2 +-
src/net/unixsock_posix.go | 2 +-
38 files changed, 240 insertions(+), 37 deletions(-)
create mode 100644 src/net/interface_aix.go
create mode 100644 src/net/sockopt_aix.go
diff --git a/src/net/addrselect.go b/src/net/addrselect.go
index 1ab9fc5326..7c0dfe261c 100644
--- a/src/net/addrselect.go
+++ b/src/net/addrselect.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Minimal RFC 6724 address selection.
diff --git a/src/net/conf.go b/src/net/conf.go
index 127aba30cb..971b1a399a 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/net/dial_unix_test.go b/src/net/dial_unix_test.go
index 0adc10d0bd..3cfc9d81b8 100644
--- a/src/net/dial_unix_test.go
+++ b/src/net/dial_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 9a0b1d69a8..3b0293025d 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 9482fc466f..7dccb6b8ec 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 64c66f96b8..842d408e56 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Read system DNS config from /etc/resolv.conf
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index 37bdeb04c8..0797559d1a 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/net/error_posix.go b/src/net/error_posix.go
index 0000700809..70efa4c66f 100644
--- a/src/net/error_posix.go
+++ b/src/net/error_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package net
diff --git a/src/net/error_unix.go b/src/net/error_unix.go
index b5a5829eaa..e615330388 100644
--- a/src/net/error_unix.go
+++ b/src/net/error_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris
package net
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 055ecf0336..e7ab9a45fd 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package net
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 676798d693..452a079bfc 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
index d672bd01b0..a1568319f3 100644
--- a/src/net/hook_unix.go
+++ b/src/net/hook_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package net
diff --git a/src/net/interface_aix.go b/src/net/interface_aix.go
new file mode 100644
index 0000000000..8b70206206
--- /dev/null
+++ b/src/net/interface_aix.go
@@ -0,0 +1,165 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ //"os"
+ "syscall"
+ "unsafe"
+)
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [120]byte
+}
+
+const _KINFO_RT_IFLIST = (0x1 << 8) | 3 | (1 << 30)
+
+const _RTAX_NETMASK = 2
+const _RTAX_IFA = 5
+const _RTAX_MAX = 8
+
+func getIfList() ([]byte, error) {
+ needed, err := syscall.Getkerninfo(_KINFO_RT_IFLIST, 0, 0, 0)
+ if err != nil {
+ return nil, nil // XXX
+ }
+ tab := make([]byte, needed)
+ _, err = syscall.Getkerninfo(_KINFO_RT_IFLIST, uintptr(unsafe.Pointer(&tab[0])), uintptr(unsafe.Pointer(&needed)), 0)
+ if err != nil {
+ return nil, nil // XXX
+ }
+ return tab[:needed], nil
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otherwise it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, error) {
+ tab, err := getIfList()
+ if err != nil {
+ return nil, err
+ }
+
+ var ift []Interface
+ for len(tab) > 0 {
+ ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
+ if ifm.Msglen == 0 {
+ break
+ }
+ if ifm.Type == syscall.RTM_IFINFO {
+ if ifindex == 0 || ifindex == int(ifm.Index) {
+ sdl := (*RawSockaddrDatalink)(unsafe.Pointer(&tab[syscall.SizeofIfMsghdr]))
+
+ ifi := &Interface{Index: int(ifm.Index), Flags: linkFlags(ifm.Flags)}
+ ifi.Name = string(sdl.Data[:sdl.Nlen])
+ ifi.HardwareAddr = sdl.Data[sdl.Nlen : sdl.Nlen+sdl.Alen]
+ /* XXX MTU? */
+ ift = append(ift, *ifi)
+ if ifindex == int(ifm.Index) {
+ break
+ }
+ }
+ }
+ tab = tab[ifm.Msglen:]
+ }
+
+ return ift, nil
+}
+
+func linkFlags(rawFlags int32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+ tab, err := getIfList()
+ if err != nil {
+ return nil, err
+ }
+
+ var ifat []Addr
+ for len(tab) > 0 {
+ ifm := (*syscall.IfMsgHdr)(unsafe.Pointer(&tab[0]))
+ if ifm.Msglen == 0 {
+ break
+ }
+ if ifm.Type == syscall.RTM_NEWADDR {
+ if ifi == nil || ifi.Index == int(ifm.Index) {
+ mask := ifm.Addrs
+ off := uint(syscall.SizeofIfMsghdr)
+
+ var iprsa, nmrsa *syscall.RawSockaddr
+ for i := uint(0); i < _RTAX_MAX; i++ {
+ if mask&(1<
Date: Wed, 10 Oct 2018 10:51:28 +0200
Subject: [PATCH 079/240] syscall: add marker comments to
zsyscall_{aix,solaris}_*.go
These marker comments are in every other zsyscall_*.go file generated by
mksyscall.pl. Also add them to the files generated by mksyscall_libc.pl
used for aix and solaris.
Change-Id: I7fd125df3549d83c658bbe7424861c76c024f2e5
Reviewed-on: https://go-review.googlesource.com/c/141037
Run-TryBot: Tobias Klauser
Reviewed-by: Ian Lance Taylor
---
src/syscall/mksyscall_libc.pl | 5 +
src/syscall/zsyscall_aix_ppc64.go | 176 +++++++++++++++++++++++++-
src/syscall/zsyscall_solaris_amd64.go | 168 +++++++++++++++++++++++-
3 files changed, 347 insertions(+), 2 deletions(-)
diff --git a/src/syscall/mksyscall_libc.pl b/src/syscall/mksyscall_libc.pl
index 6f57bee79e..5ceedc812a 100755
--- a/src/syscall/mksyscall_libc.pl
+++ b/src/syscall/mksyscall_libc.pl
@@ -106,6 +106,11 @@ while(<>) {
my @in = parseparamlist($in);
my @out = parseparamlist($out);
+ # Try in vain to keep people from editing this file.
+ # The theory is that they jump into the middle of the file
+ # without reading the header.
+ $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
+
# So file name.
if($aix) {
if($modname eq "") {
diff --git a/src/syscall/zsyscall_aix_ppc64.go b/src/syscall/zsyscall_aix_ppc64.go
index d9f009953f..3ea11f8af3 100644
--- a/src/syscall/zsyscall_aix_ppc64.go
+++ b/src/syscall/zsyscall_aix_ppc64.go
@@ -1,4 +1,4 @@
-// mksyscall_lib.pl -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go
+// mksyscall_libc.pl -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go
// Code generated by the command above; DO NOT EDIT.
// +build aix,ppc64
@@ -275,6 +275,8 @@ var (
libc_munmap libcFunc
)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
val = int(r0)
@@ -284,6 +286,8 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func dup2(old int, new int) (val int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_dup2)), 2, uintptr(old), uintptr(new), 0, 0, 0, 0)
val = int(r0)
@@ -293,6 +297,8 @@ func dup2(old int, new int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe(p *[2]_C_int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_pipe)), 1, uintptr(unsafe.Pointer(p)), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -301,6 +307,8 @@ func pipe(p *[2]_C_int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func readlink(path string, buf []byte, bufSize uint64) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -319,6 +327,8 @@ func readlink(path string, buf []byte, bufSize uint64) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, times *[2]Timeval) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -332,6 +342,8 @@ func utimes(path string, times *[2]Timeval) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -345,6 +357,8 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func unlinkat(dirfd int, path string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -358,6 +372,8 @@ func unlinkat(dirfd int, path string, flags int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getcwd(buf *byte, size uint64) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getcwd)), 2, uintptr(unsafe.Pointer(buf)), uintptr(size), 0, 0, 0, 0)
if e1 != 0 {
@@ -366,6 +382,8 @@ func getcwd(buf *byte, size uint64) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
n = int(r0)
@@ -375,6 +393,8 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
if e1 != 0 {
@@ -383,6 +403,8 @@ func setgroups(ngid int, gid *_Gid_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getdirent(fd int, buf []byte) (n int, err error) {
var _p0 *byte
if len(buf) > 0 {
@@ -396,6 +418,8 @@ func getdirent(fd int, buf []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_wait4)), 4, uintptr(pid), uintptr(unsafe.Pointer(status)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = Pid_t(r0)
@@ -405,6 +429,8 @@ func wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t,
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
@@ -413,6 +439,8 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
@@ -421,6 +449,8 @@ func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getkerninfo(op int32, where uintptr, size uintptr, arg int64) (i int32, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Getkerninfo)), 4, uintptr(op), uintptr(where), uintptr(size), uintptr(arg), 0, 0)
i = int32(r0)
@@ -430,6 +460,8 @@ func Getkerninfo(op int32, where uintptr, size uintptr, arg int64) (i int32, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
@@ -438,6 +470,8 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
if e1 != 0 {
@@ -446,6 +480,8 @@ func Listen(s int, backlog int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
@@ -454,6 +490,8 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
fd = int(r0)
@@ -463,6 +501,8 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
if e1 != 0 {
@@ -471,6 +511,8 @@ func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
if e1 != 0 {
@@ -479,6 +521,8 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
if e1 != 0 {
@@ -487,6 +531,8 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -500,6 +546,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 *byte
if len(buf) > 0 {
@@ -512,6 +560,8 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
if e1 != 0 {
@@ -520,6 +570,8 @@ func Shutdown(s int, how int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
@@ -529,6 +581,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
@@ -538,6 +592,8 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
fd = int(r0)
@@ -547,6 +603,8 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -561,6 +619,8 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_ptrace64)), 5, uintptr(request), uintptr(id), uintptr(addr), uintptr(data), uintptr(buff), 0)
if e1 != 0 {
@@ -569,6 +629,8 @@ func ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err er
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Acct(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -582,6 +644,8 @@ func Acct(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -595,6 +659,8 @@ func Chdir(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chmod(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -608,6 +674,8 @@ func Chmod(path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chown(path string, uid int, gid int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -621,6 +689,8 @@ func Chown(path string, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -629,6 +699,8 @@ func Close(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
nfd = int(r0)
@@ -638,6 +710,8 @@ func Dup(fd int) (nfd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -651,6 +725,8 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchdir(fd int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -659,6 +735,8 @@ func Fchdir(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
if e1 != 0 {
@@ -667,6 +745,8 @@ func Fchmod(fd int, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -680,6 +760,8 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
if e1 != 0 {
@@ -688,6 +770,8 @@ func Fchown(fd int, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -701,6 +785,8 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
val = int(r0)
@@ -710,6 +796,8 @@ func Fpathconf(fd int, name int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
if e1 != 0 {
@@ -718,6 +806,8 @@ func Fstat(fd int, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, buf *Statfs_t) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fstatfs)), 2, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0)
if e1 != 0 {
@@ -726,6 +816,8 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
if e1 != 0 {
@@ -734,6 +826,8 @@ func Ftruncate(fd int, length int64) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -742,36 +836,48 @@ func Fsync(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
gid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpid() (pid int) {
r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
pid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Geteuid() (euid int) {
r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
euid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
egid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getppid() (ppid int) {
r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
ppid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
if e1 != 0 {
@@ -780,12 +886,16 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := rawSyscall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
uid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kill(pid int, signum Signal) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
if e1 != 0 {
@@ -794,6 +904,8 @@ func Kill(pid int, signum Signal) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -807,6 +919,8 @@ func Lchown(path string, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -825,6 +939,8 @@ func Link(path string, link string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -838,6 +954,8 @@ func Lstat(path string, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Mkdir(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -851,6 +969,8 @@ func Mkdir(path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Mkdirat(dirfd int, path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -864,6 +984,8 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -877,6 +999,8 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -891,6 +1015,8 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -904,6 +1030,8 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -917,6 +1045,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func read(fd int, p []byte) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -930,6 +1060,8 @@ func read(fd int, p []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Reboot(how int) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_Reboot)), 1, uintptr(how), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -938,6 +1070,8 @@ func Reboot(how int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
@@ -956,6 +1090,8 @@ func Rename(from string, to string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -974,6 +1110,8 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -987,6 +1125,8 @@ func Rmdir(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
newoffset = int64(r0)
@@ -996,6 +1136,8 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -1004,6 +1146,8 @@ func Setegid(egid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -1012,6 +1156,8 @@ func Seteuid(euid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -1020,6 +1166,8 @@ func Setgid(gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
if e1 != 0 {
@@ -1028,6 +1176,8 @@ func Setpgid(pid int, pgid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
if e1 != 0 {
@@ -1036,6 +1186,8 @@ func Setregid(rgid int, egid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
if e1 != 0 {
@@ -1044,6 +1196,8 @@ func Setreuid(ruid int, euid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1057,6 +1211,8 @@ func Stat(path string, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, buf *Statfs_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1070,6 +1226,8 @@ func Statfs(path string, buf *Statfs_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1088,6 +1246,8 @@ func Symlink(path string, link string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1101,12 +1261,16 @@ func Truncate(path string, length int64) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Umask(newmask int) (oldmask int) {
r0, _, _ := syscall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
oldmask = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1120,6 +1284,8 @@ func Unlink(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Uname(buf *Utsname) (err error) {
_, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Uname)), 1, uintptr(unsafe.Pointer(buf)), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -1128,6 +1294,8 @@ func Uname(buf *Utsname) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func write(fd int, p []byte) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -1141,6 +1309,8 @@ func write(fd int, p []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func gettimeofday(tv *Timeval, tzp *Timezone) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_gettimeofday)), 2, uintptr(unsafe.Pointer(tv)), uintptr(unsafe.Pointer(tzp)), 0, 0, 0, 0)
if e1 != 0 {
@@ -1149,6 +1319,8 @@ func gettimeofday(tv *Timeval, tzp *Timezone) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_mmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
ret = uintptr(r0)
@@ -1158,6 +1330,8 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
if e1 != 0 {
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index ecd37902e0..446ebfc503 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,4 +1,4 @@
-// mksyscall_solaris.pl -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go
+// mksyscall_libc.pl -solaris -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go
// Code generated by the command above; DO NOT EDIT.
// +build solaris,amd64
@@ -263,6 +263,8 @@ var (
libc_utimensat libcFunc
)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getcwd(buf []byte) (n int, err error) {
var _p0 *byte
if len(buf) > 0 {
@@ -276,6 +278,8 @@ func Getcwd(buf []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
n = int(r0)
@@ -285,6 +289,8 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
if e1 != 0 {
@@ -293,6 +299,8 @@ func setgroups(ngid int, gid *_Gid_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
val = int(r0)
@@ -302,6 +310,8 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
fd = int(r0)
@@ -311,6 +321,8 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
@@ -320,6 +332,8 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -333,6 +347,8 @@ func Access(path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Adjtime)), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
if e1 != 0 {
@@ -341,6 +357,8 @@ func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -354,6 +372,8 @@ func Chdir(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chmod(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -367,6 +387,8 @@ func Chmod(path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chown(path string, uid int, gid int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -380,6 +402,8 @@ func Chown(path string, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -393,6 +417,8 @@ func Chroot(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -401,6 +427,8 @@ func Close(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
nfd = int(r0)
@@ -410,6 +438,8 @@ func Dup(fd int) (nfd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchdir(fd int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -418,6 +448,8 @@ func Fchdir(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
if e1 != 0 {
@@ -426,6 +458,8 @@ func Fchmod(fd int, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
if e1 != 0 {
@@ -434,6 +468,8 @@ func Fchown(fd int, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
val = int(r0)
@@ -443,6 +479,8 @@ func Fpathconf(fd int, name int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
if e1 != 0 {
@@ -451,6 +489,8 @@ func Fstat(fd int, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 *byte
if len(buf) > 0 {
@@ -464,36 +504,48 @@ func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
gid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpid() (pid int) {
r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
pid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Geteuid() (euid int) {
r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
euid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
egid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getppid() (ppid int) {
r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
ppid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpriority(which int, who int) (n int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
n = int(r0)
@@ -503,6 +555,8 @@ func Getpriority(which int, who int) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
if e1 != 0 {
@@ -511,6 +565,8 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettimeofday(tv *Timeval) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Gettimeofday)), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -519,12 +575,16 @@ func Gettimeofday(tv *Timeval) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
uid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kill(pid int, signum Signal) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
if e1 != 0 {
@@ -533,6 +593,8 @@ func Kill(pid int, signum Signal) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -546,6 +608,8 @@ func Lchown(path string, uid int, gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -564,6 +628,8 @@ func Link(path string, link string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
if e1 != 0 {
@@ -572,6 +638,8 @@ func Listen(s int, backlog int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -585,6 +653,8 @@ func Lstat(path string, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Mkdir(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -598,6 +668,8 @@ func Mkdir(path string, mode uint32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Mknod(path string, mode uint32, dev int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -611,6 +683,8 @@ func Mknod(path string, mode uint32, dev int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Nanosleep)), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
if e1 != 0 {
@@ -619,6 +693,8 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -633,6 +709,8 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pathconf(path string, name int) (val int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -647,6 +725,8 @@ func Pathconf(path string, name int) (val int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -660,6 +740,8 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -673,6 +755,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func read(fd int, p []byte) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -686,6 +770,8 @@ func read(fd int, p []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Readlink(path string, buf []byte) (n int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -704,6 +790,8 @@ func Readlink(path string, buf []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
@@ -722,6 +810,8 @@ func Rename(from string, to string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -735,6 +825,8 @@ func Rmdir(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
newoffset = int64(r0)
@@ -744,6 +836,8 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendfile)), 4, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
written = int(r0)
@@ -753,6 +847,8 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -761,6 +857,8 @@ func Setegid(egid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -769,6 +867,8 @@ func Seteuid(euid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -777,6 +877,8 @@ func Setgid(gid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
if e1 != 0 {
@@ -785,6 +887,8 @@ func Setpgid(pid int, pgid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpriority(which int, who int, prio int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Setpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
if e1 != 0 {
@@ -793,6 +897,8 @@ func Setpriority(which int, who int, prio int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
if e1 != 0 {
@@ -801,6 +907,8 @@ func Setregid(rgid int, egid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
if e1 != 0 {
@@ -809,6 +917,8 @@ func Setreuid(ruid int, euid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
if e1 != 0 {
@@ -817,6 +927,8 @@ func Setrlimit(which int, lim *Rlimit) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, err error) {
r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setsid)), 0, 0, 0, 0, 0, 0, 0)
pid = int(r0)
@@ -826,6 +938,8 @@ func Setsid() (pid int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -834,6 +948,8 @@ func Setuid(uid int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
if e1 != 0 {
@@ -842,6 +958,8 @@ func Shutdown(s int, how int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -855,6 +973,8 @@ func Stat(path string, stat *Stat_t) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -873,6 +993,8 @@ func Symlink(path string, link string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Sync)), 0, 0, 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -881,6 +1003,8 @@ func Sync() (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -894,6 +1018,8 @@ func Truncate(path string, length int64) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
if e1 != 0 {
@@ -902,6 +1028,8 @@ func Fsync(fd int) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
if e1 != 0 {
@@ -910,12 +1038,16 @@ func Ftruncate(fd int, length int64) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Umask(newmask int) (oldmask int) {
r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
oldmask = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -929,6 +1061,8 @@ func Unlink(path string) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, times *[2]Timeval) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -942,6 +1076,8 @@ func utimes(path string, times *[2]Timeval) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
@@ -950,6 +1086,8 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
@@ -958,6 +1096,8 @@ func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_mmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
ret = uintptr(r0)
@@ -967,6 +1107,8 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
if e1 != 0 {
@@ -975,6 +1117,8 @@ func munmap(addr uintptr, length uintptr) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
var _p0 *byte
if len(buf) > 0 {
@@ -987,6 +1131,8 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
fd = int(r0)
@@ -996,6 +1142,8 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc___xnet_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
if e1 != 0 {
@@ -1004,6 +1152,8 @@ func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func write(fd int, p []byte) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -1017,6 +1167,8 @@ func write(fd int, p []byte) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
@@ -1025,6 +1177,8 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
if e1 != 0 {
@@ -1033,6 +1187,8 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
if e1 != 0 {
@@ -1041,6 +1197,8 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
@@ -1049,6 +1207,8 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 *byte
if len(p) > 0 {
@@ -1062,6 +1222,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
@@ -1071,6 +1233,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getexecname() (path unsafe.Pointer, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getexecname)), 0, 0, 0, 0, 0, 0, 0)
path = unsafe.Pointer(r0)
@@ -1080,6 +1244,8 @@ func getexecname() (path unsafe.Pointer, err error) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
From 555d8c455a420df4a2bd024a5cafdaa60ac3ae55 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Mon, 8 Oct 2018 17:43:26 -0700
Subject: [PATCH 080/240] cmd/compile: remove some inl budget hacks
Prior to stack tracing, inlining could cause
dead pointers to be kept alive in some loops.
See #18336 and CL 31674.
The adjustment removed by this change preserved the inlining status quo
in the face of Node structure changes, to avoid creating new problems.
Now that stack tracing provides precision, these hacks can be removed.
Of course, our inlining code model is already hacky (#17566),
but at least now there will be fewer epicyclical hacks.
Newly inline-able functions in std cmd as a result of this change:
hash/adler32/adler32.go:65:6: can inline (*digest).UnmarshalBinary
hash/fnv/fnv.go:281:6: can inline (*sum32).UnmarshalBinary
hash/fnv/fnv.go:292:6: can inline (*sum32a).UnmarshalBinary
reflect/value.go:1298:6: can inline Value.OverflowComplex
compress/bzip2/bit_reader.go:25:6: can inline newBitReader
encoding/xml/xml.go:365:6: can inline (*Decoder).switchToReader
vendor/golang_org/x/crypto/cryptobyte/builder.go:77:6: can inline (*Builder).AddUint16
crypto/x509/x509.go:1851:58: can inline buildExtensions.func2.1.1
crypto/x509/x509.go:1871:58: can inline buildExtensions.func2.3.1
crypto/x509/x509.go:1883:58: can inline buildExtensions.func2.4.1
cmd/vet/internal/cfg/builder.go:463:6: can inline (*builder).labeledBlock
crypto/tls/handshake_messages.go:1450:6: can inline (*newSessionTicketMsg).marshal
crypto/tls/handshake_server.go:769:6: can inline (*serverHandshakeState).clientHelloInfo
crypto/tls/handshake_messages.go:1171:6: can inline (*nextProtoMsg).unmarshal
cmd/link/internal/amd64/obj.go:40:6: can inline Init
cmd/link/internal/ppc64/obj.go:40:6: can inline Init
net/http/httputil/persist.go:54:6: can inline NewServerConn
net/http/fcgi/child.go:83:6: can inline newResponse
cmd/compile/internal/ssa/poset.go:245:6: can inline (*poset).newnode
Change-Id: I19e8e383a6273849673d35189a9358870665f82f
Reviewed-on: https://go-review.googlesource.com/c/141117
Run-TryBot: Josh Bleecher Snyder
TryBot-Result: Gobot Gobot
Reviewed-by: Ilya Tocar
Reviewed-by: Matthew Dempsky
---
src/cmd/compile/internal/gc/inl.go | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index f188c9a9cd..e364104a46 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -404,16 +404,6 @@ func (v *hairyVisitor) visit(n *Node) bool {
}
v.budget--
- // TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
- // See issue 17566 and CL 31674 for discussion.
- switch n.Op {
- case OSTRUCTKEY:
- v.budget--
- case OSLICE, OSLICEARR, OSLICESTR:
- v.budget--
- case OSLICE3, OSLICE3ARR:
- v.budget -= 2
- }
// When debugging, don't stop early, to get full cost of inlining this function
if v.budget < 0 && Debug['m'] < 2 {
From d5e722034ab19d47377507f3606c1a72f484d7eb Mon Sep 17 00:00:00 2001
From: Rob Pike
Date: Wed, 10 Oct 2018 09:54:22 +1100
Subject: [PATCH 081/240] go/doc: add new mode bit PreserveAST to control
clearing of data in AST
To save memory in godoc, this package routinely clears fields of
the AST to avoid keeping data that godoc no longer needs. For other
programs, such as cmd/doc, this behavior is unfortunate. Also, one
should be able to tell any package like this, "don't change my
data".
Add a Mode bit, defaulting to off to preserve existing behavior,
that allows a client to specify that the AST is inviolate.
This is necessary to address some of the outstanding issues
in cmd/doc that require, for example, looking at function bodies.
Fixes #26835
Change-Id: I01cc97c6addc5ab6abff885fff4bd53454a03bbc
Reviewed-on: https://go-review.googlesource.com/c/140958
Reviewed-by: Robert Griesemer
---
src/go/doc/doc.go | 13 +++++++++----
src/go/doc/reader.go | 40 ++++++++++++++++++++++++++--------------
2 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/src/go/doc/doc.go b/src/go/doc/doc.go
index 3c3e28d48f..d0d4d3265b 100644
--- a/src/go/doc/doc.go
+++ b/src/go/doc/doc.go
@@ -79,13 +79,18 @@ type Note struct {
type Mode int
const (
- // extract documentation for all package-level declarations,
- // not just exported ones
+ // AllDecls says to extract documentation for all package-level
+ // declarations, not just exported ones.
AllDecls Mode = 1 << iota
- // show all embedded methods, not just the ones of
- // invisible (unexported) anonymous fields
+ // AllMethods says to show all embedded methods, not just the ones of
+ // invisible (unexported) anonymous fields.
AllMethods
+
+ // PreserveAST says to leave the AST unmodified. Originally, pieces of
+ // the AST such as function bodies were nil-ed out to save memory in
+ // godoc, but not all programs want that behavior.
+ PreserveAST
)
// New computes the package documentation for the given package AST.
diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go
index 21d5907a03..26365e46b5 100644
--- a/src/go/doc/reader.go
+++ b/src/go/doc/reader.go
@@ -36,9 +36,10 @@ func recvString(recv ast.Expr) string {
// set creates the corresponding Func for f and adds it to mset.
// If there are multiple f's with the same name, set keeps the first
-// one with documentation; conflicts are ignored.
+// one with documentation; conflicts are ignored. The boolean
+// specifies whether to leave the AST untouched.
//
-func (mset methodSet) set(f *ast.FuncDecl) {
+func (mset methodSet) set(f *ast.FuncDecl, preserveAST bool) {
name := f.Name.Name
if g := mset[name]; g != nil && g.Doc != "" {
// A function with the same name has already been registered;
@@ -65,7 +66,9 @@ func (mset methodSet) set(f *ast.FuncDecl) {
Recv: recv,
Orig: recv,
}
- f.Doc = nil // doc consumed - remove from AST
+ if !preserveAST {
+ f.Doc = nil // doc consumed - remove from AST
+ }
}
// add adds method m to the method set; m is ignored if the method set
@@ -299,8 +302,9 @@ func (r *reader) readValue(decl *ast.GenDecl) {
Decl: decl,
order: r.order,
})
- decl.Doc = nil // doc consumed - remove from AST
-
+ if r.mode&PreserveAST == 0 {
+ decl.Doc = nil // doc consumed - remove from AST
+ }
// Note: It's important that the order used here is global because the cleanupTypes
// methods may move values associated with types back into the global list. If the
// order is list-specific, sorting is not deterministic because the same order value
@@ -339,12 +343,14 @@ func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
// compute documentation
doc := spec.Doc
- spec.Doc = nil // doc consumed - remove from AST
if doc == nil {
// no doc associated with the spec, use the declaration doc, if any
doc = decl.Doc
}
- decl.Doc = nil // doc consumed - remove from AST
+ if r.mode&PreserveAST == 0 {
+ spec.Doc = nil // doc consumed - remove from AST
+ decl.Doc = nil // doc consumed - remove from AST
+ }
typ.doc = doc.Text()
// record anonymous fields (they may contribute methods)
@@ -362,8 +368,10 @@ func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
// readFunc processes a func or method declaration.
//
func (r *reader) readFunc(fun *ast.FuncDecl) {
- // strip function body
- fun.Body = nil
+ // strip function body if requested.
+ if r.mode&PreserveAST == 0 {
+ fun.Body = nil
+ }
// associate methods with the receiver type, if any
if fun.Recv != nil {
@@ -380,7 +388,7 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
return
}
if typ := r.lookupType(recvTypeName); typ != nil {
- typ.methods.set(fun)
+ typ.methods.set(fun, r.mode&PreserveAST != 0)
}
// otherwise ignore the method
// TODO(gri): There may be exported methods of non-exported types
@@ -414,13 +422,13 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
}
// If there is exactly one result type, associate the function with that type.
if numResultTypes == 1 {
- typ.funcs.set(fun)
+ typ.funcs.set(fun, r.mode&PreserveAST != 0)
return
}
}
// just an ordinary function
- r.funcs.set(fun)
+ r.funcs.set(fun, r.mode&PreserveAST != 0)
}
var (
@@ -481,7 +489,9 @@ func (r *reader) readFile(src *ast.File) {
// add package documentation
if src.Doc != nil {
r.readDoc(src.Doc)
- src.Doc = nil // doc consumed - remove from AST
+ if r.mode&PreserveAST == 0 {
+ src.Doc = nil // doc consumed - remove from AST
+ }
}
// add all declarations
@@ -545,7 +555,9 @@ func (r *reader) readFile(src *ast.File) {
// collect MARKER(...): annotations
r.readNotes(src.Comments)
- src.Comments = nil // consumed unassociated comments - remove from AST
+ if r.mode&PreserveAST == 0 {
+ src.Comments = nil // consumed unassociated comments - remove from AST
+ }
}
func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
From 294d16c9c58187492baf1fd8bac034b5fecbf0ba Mon Sep 17 00:00:00 2001
From: Rob Pike
Date: Wed, 10 Oct 2018 11:50:49 +1100
Subject: [PATCH 082/240] cmd/doc: add a -src flag to show original source
It's long-desired but was blocked by #26835. That is now fixed, so
it's easy. When -src is off, we behave as before. But with -src
set, initialize the go/doc package to preserve the original AST and
things flow very easily.
With -src, since you're seeing inside the package source anyway it
shows unexported fields and constants: you see the original source.
But you still need -u to ask about them.
Fixes #18807
Change-Id: I473e90323b4eff0735360274dc0d2d9dba16ff8b
Reviewed-on: https://go-review.googlesource.com/c/140959
Reviewed-by: Andrew Gerrand
Run-TryBot: Andrew Gerrand
TryBot-Result: Gobot Gobot
---
src/cmd/doc/doc_test.go | 149 +++++++++++++++++++++++----------
src/cmd/doc/main.go | 5 ++
src/cmd/doc/pkg.go | 21 +++--
src/cmd/doc/testdata/pkg.go | 8 +-
src/cmd/go/alldocs.go | 7 ++
src/cmd/go/internal/doc/doc.go | 7 ++
6 files changed, 141 insertions(+), 56 deletions(-)
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 6010f04b56..64b1fb596b 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -127,24 +127,24 @@ var tests = []test{
`type T1 = T2`, // Type alias
},
[]string{
- `const internalConstant = 2`, // No internal constants.
- `var internalVariable = 2`, // No internal variables.
- `func internalFunc(a int) bool`, // No internal functions.
- `Comment about exported constant`, // No comment for single constant.
- `Comment about exported variable`, // No comment for single variable.
- `Comment about block of constants.`, // No comment for constant block.
- `Comment about block of variables.`, // No comment for variable block.
- `Comment before ConstOne`, // No comment for first entry in constant block.
- `Comment before VarOne`, // No comment for first entry in variable block.
- `ConstTwo = 2`, // No second entry in constant block.
- `VarTwo = 2`, // No second entry in variable block.
- `VarFive = 5`, // From block starting with unexported variable.
- `type unexportedType`, // No unexported type.
- `unexportedTypedConstant`, // No unexported typed constant.
- `\bField`, // No fields.
- `Method`, // No methods.
- `someArgument[5-8]`, // No truncated arguments.
- `type T1 T2`, // Type alias does not display as type declaration.
+ `const internalConstant = 2`, // No internal constants.
+ `var internalVariable = 2`, // No internal variables.
+ `func internalFunc(a int) bool`, // No internal functions.
+ `Comment about exported constant`, // No comment for single constant.
+ `Comment about exported variable`, // No comment for single variable.
+ `Comment about block of constants`, // No comment for constant block.
+ `Comment about block of variables`, // No comment for variable block.
+ `Comment before ConstOne`, // No comment for first entry in constant block.
+ `Comment before VarOne`, // No comment for first entry in variable block.
+ `ConstTwo = 2`, // No second entry in constant block.
+ `VarTwo = 2`, // No second entry in variable block.
+ `VarFive = 5`, // From block starting with unexported variable.
+ `type unexportedType`, // No unexported type.
+ `unexportedTypedConstant`, // No unexported typed constant.
+ `\bField`, // No fields.
+ `Method`, // No methods.
+ `someArgument[5-8]`, // No truncated arguments.
+ `type T1 T2`, // Type alias does not display as type declaration.
},
},
// Package dump -u
@@ -207,6 +207,18 @@ var tests = []test{
},
nil,
},
+ // Block of constants -src.
+ {
+ "block of constants with -src",
+ []string{"-src", p, `ConstTwo`},
+ []string{
+ `Comment about block of constants`, // Top comment.
+ `ConstOne.*=.*1`, // Each constant seen.
+ `ConstTwo.*=.*2.*Comment on line with ConstTwo`,
+ `constThree`, // Even unexported constants.
+ },
+ nil,
+ },
// Block of constants with carryover type from unexported field.
{
"block of constants with carryover type",
@@ -295,6 +307,17 @@ var tests = []test{
},
nil,
},
+ // Function with -src.
+ {
+ "function with -src",
+ []string{"-src", p, `ExportedFunc`},
+ []string{
+ `Comment about exported function`, // Include comment.
+ `func ExportedFunc\(a int\) bool`,
+ `return true != false`, // Include body.
+ },
+ nil,
+ },
// Type.
{
@@ -304,21 +327,44 @@ var tests = []test{
`Comment about exported type`, // Include comment.
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int` +
- `.*Comment on line with exported field.`,
- `ExportedEmbeddedType.*Comment on line with exported embedded field.`,
+ `.*Comment on line with exported field`,
+ `ExportedEmbeddedType.*Comment on line with exported embedded field`,
`Has unexported fields`,
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
- `io.Reader.*Comment on line with embedded Reader.`,
+ `io.Reader.*Comment on line with embedded Reader`,
},
[]string{
- `unexportedField`, // No unexported field.
- `int.*embedded`, // No unexported embedded field.
- `Comment about exported method.`, // No comment about exported method.
- `unexportedMethod`, // No unexported method.
- `unexportedTypedConstant`, // No unexported constant.
- `error`, // No embedded error.
+ `unexportedField`, // No unexported field.
+ `int.*embedded`, // No unexported embedded field.
+ `Comment about exported method`, // No comment about exported method.
+ `unexportedMethod`, // No unexported method.
+ `unexportedTypedConstant`, // No unexported constant.
+ `error`, // No embedded error.
+ },
+ },
+ // Type with -src. Will see unexported fields.
+ {
+ "type",
+ []string{"-src", p, `ExportedType`},
+ []string{
+ `Comment about exported type`, // Include comment.
+ `type ExportedType struct`, // Type definition.
+ `Comment before exported field.*\n.*ExportedField +int` +
+ `.*Comment on line with exported field`,
+ `ExportedEmbeddedType.*Comment on line with exported embedded field`,
+ `unexportedType.*Comment on line with unexported embedded field`,
+ `func \(ExportedType\) ExportedMethod\(a int\) bool`,
+ `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
+ `func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
+ `io.Reader.*Comment on line with embedded Reader`,
+ },
+ []string{
+ `int.*embedded`, // No unexported embedded field.
+ `Comment about exported method`, // No comment about exported method.
+ `unexportedMethod`, // No unexported method.
+ `unexportedTypedConstant`, // No unexported constant.
},
},
// Type T1 dump (alias).
@@ -341,14 +387,14 @@ var tests = []test{
`Comment about exported type`, // Include comment.
`type ExportedType struct`, // Type definition.
`Comment before exported field.*\n.*ExportedField +int`,
- `unexportedField.*int.*Comment on line with unexported field.`,
- `ExportedEmbeddedType.*Comment on line with exported embedded field.`,
- `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`,
- `\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field.`,
- `unexportedType.*Comment on line with unexported embedded field.`,
- `\*unexportedType.*Comment on line with unexported embedded \*field.`,
- `io.Reader.*Comment on line with embedded Reader.`,
- `error.*Comment on line with embedded error.`,
+ `unexportedField.*int.*Comment on line with unexported field`,
+ `ExportedEmbeddedType.*Comment on line with exported embedded field`,
+ `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`,
+ `\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`,
+ `unexportedType.*Comment on line with unexported embedded field`,
+ `\*unexportedType.*Comment on line with unexported embedded \*field`,
+ `io.Reader.*Comment on line with embedded Reader`,
+ `error.*Comment on line with embedded error`,
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
`unexportedTypedConstant`,
},
@@ -380,8 +426,8 @@ var tests = []test{
`type ExportedInterface interface`, // Interface definition.
`Comment before exported method.*\n.*ExportedMethod\(\)` +
`.*Comment on line with exported method`,
- `io.Reader.*Comment on line with embedded Reader.`,
- `error.*Comment on line with embedded error.`,
+ `io.Reader.*Comment on line with embedded Reader`,
+ `error.*Comment on line with embedded error`,
`Has unexported methods`,
},
[]string{
@@ -400,9 +446,9 @@ var tests = []test{
`type ExportedInterface interface`, // Interface definition.
`Comment before exported method.*\n.*ExportedMethod\(\)` +
`.*Comment on line with exported method`,
- `unexportedMethod\(\).*Comment on line with unexported method.`,
- `io.Reader.*Comment on line with embedded Reader.`,
- `error.*Comment on line with embedded error.`,
+ `unexportedMethod\(\).*Comment on line with unexported method`,
+ `io.Reader.*Comment on line with embedded Reader`,
+ `error.*Comment on line with embedded error`,
},
[]string{
`Has unexported methods`,
@@ -418,7 +464,7 @@ var tests = []test{
`.*Comment on line with exported method`,
},
[]string{
- `Comment about exported interface.`,
+ `Comment about exported interface`,
},
},
@@ -428,7 +474,7 @@ var tests = []test{
[]string{p, `ExportedType.ExportedMethod`},
[]string{
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
- `Comment about exported method.`,
+ `Comment about exported method`,
},
nil,
},
@@ -438,7 +484,18 @@ var tests = []test{
[]string{"-u", p, `ExportedType.unexportedMethod`},
[]string{
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
- `Comment about unexported method.`,
+ `Comment about unexported method`,
+ },
+ nil,
+ },
+ // Method with -src.
+ {
+ "method with -src",
+ []string{"-src", p, `ExportedType.ExportedMethod`},
+ []string{
+ `func \(ExportedType\) ExportedMethod\(a int\) bool`,
+ `Comment about exported method`,
+ `return true != true`,
},
nil,
},
@@ -450,8 +507,8 @@ var tests = []test{
[]string{
`type ExportedType struct`,
`ExportedField int`,
- `Comment before exported field.`,
- `Comment on line with exported field.`,
+ `Comment before exported field`,
+ `Comment on line with exported field`,
`other fields elided`,
},
nil,
@@ -463,7 +520,7 @@ var tests = []test{
[]string{"-u", p, `ExportedType.unexportedField`},
[]string{
`unexportedField int`,
- `Comment on line with unexported field.`,
+ `Comment on line with unexported field`,
},
nil,
},
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index 982c8e054a..a3e09d3f87 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -28,6 +28,9 @@
// For commands, unless the -cmd flag is present "go doc command"
// shows only the package-level docs for the package.
//
+// The -src flag causes doc to print the full source code for the symbol, such
+// as the body of a struct, function or method.
+//
// For complete documentation, run "go help doc".
package main
@@ -50,6 +53,7 @@ var (
unexported bool // -u flag
matchCase bool // -c flag
showCmd bool // -cmd flag
+ showSrc bool // -src flag
)
// usage is a replacement usage function for the flags package.
@@ -85,6 +89,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
+ flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
flagSet.Parse(args)
var paths []string
var symbol, method string
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index 14e41b9106..154fb7b45f 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -137,7 +137,11 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
// from finding the symbol. Work around this for now, but we
// should fix it in go/doc.
// A similar story applies to factory functions.
- docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
+ mode := doc.AllDecls
+ if showSrc {
+ mode |= doc.PreserveAST // See comment for Package.emit.
+ }
+ docPkg := doc.New(astPkg, pkg.ImportPath, mode)
for _, typ := range docPkg.Types {
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
@@ -177,14 +181,16 @@ func (pkg *Package) newlines(n int) {
}
}
-// emit prints the node.
+// emit prints the node. If showSrc is true, it ignores the provided comment,
+// assuming the comment is in the node itself. Otherwise, the go/doc package
+// clears the stuff we don't want to print anyway. It's a bit of a magic trick.
func (pkg *Package) emit(comment string, node ast.Node) {
if node != nil {
err := format.Node(&pkg.buf, pkg.fs, node)
if err != nil {
log.Fatal(err)
}
- if comment != "" {
+ if comment != "" && !showSrc {
pkg.newlines(1)
doc.ToText(&pkg.buf, comment, " ", indent, indentedWidth)
pkg.newlines(2) // Blank line after comment to separate from next item.
@@ -611,7 +617,6 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
// Symbol is a function.
decl := fun.Decl
- decl.Body = nil
pkg.emit(fun.Doc, decl)
found = true
}
@@ -641,7 +646,7 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
for _, ident := range vspec.Names {
- if isExported(ident.Name) {
+ if showSrc || isExported(ident.Name) {
if vspec.Type == nil && vspec.Values == nil && typ != nil {
// This a standalone identifier, as in the case of iota usage.
// Thus, assume the type comes from the previous type.
@@ -701,9 +706,10 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
// trimUnexportedElems modifies spec in place to elide unexported fields from
-// structs and methods from interfaces (unless the unexported flag is set).
+// structs and methods from interfaces (unless the unexported flag is set or we
+// are asked to show the original source).
func trimUnexportedElems(spec *ast.TypeSpec) {
- if unexported {
+ if unexported || showSrc {
return
}
switch typ := spec.Type.(type) {
@@ -808,7 +814,6 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
for _, meth := range typ.Methods {
if match(method, meth.Name) {
decl := meth.Decl
- decl.Body = nil
pkg.emit(meth.Doc, decl)
found = true
}
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index bc069939f8..50105b5fcc 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -5,6 +5,8 @@
// Package comment.
package pkg
+import "io"
+
// Constants
// Comment about exported constant.
@@ -52,7 +54,9 @@ var (
)
// Comment about exported function.
-func ExportedFunc(a int) bool
+func ExportedFunc(a int) bool {
+ return true != false
+}
// Comment about internal function.
func internalFunc(a int) bool
@@ -73,7 +77,7 @@ type ExportedType struct {
// Comment about exported method.
func (ExportedType) ExportedMethod(a int) bool {
- return true
+ return true != true
}
// Comment about unexported method.
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 9528ca2984..f54f000b07 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -348,6 +348,13 @@
// Treat a command (package main) like a regular package.
// Otherwise package main's exported symbols are hidden
// when showing the package's top-level documentation.
+// -src
+// Show the full source code for the symbol. This will
+// display the full Go source of its declaration and
+// definition, such as a function definition (including
+// the body), type declaration or enclosing const
+// block. The output may therefore include unexported
+// details.
// -u
// Show documentation for unexported as well as exported
// symbols, methods, and fields.
diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go
index 4e7dca082d..262bbb3ecb 100644
--- a/src/cmd/go/internal/doc/doc.go
+++ b/src/cmd/go/internal/doc/doc.go
@@ -112,6 +112,13 @@ Flags:
Treat a command (package main) like a regular package.
Otherwise package main's exported symbols are hidden
when showing the package's top-level documentation.
+ -src
+ Show the full source code for the symbol. This will
+ display the full Go source of its declaration and
+ definition, such as a function definition (including
+ the body), type declaration or enclosing const
+ block. The output may therefore include unexported
+ details.
-u
Show documentation for unexported as well as exported
symbols, methods, and fields.
From 5b2030cbcacf0c1b5ea46230323595ab20fa8099 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Wed, 10 Oct 2018 16:37:01 -0700
Subject: [PATCH 083/240] cmd/compile/internal/types: regen stringer file
Forgot to do this for golang.org/cl/76312.
Change-Id: Ic20fef3eeff14a805f608221aff1fa03934be3ca
Reviewed-on: https://go-review.googlesource.com/c/141357
Run-TryBot: Matthew Dempsky
Reviewed-by: Robert Griesemer
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/types/etype_string.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cmd/compile/internal/types/etype_string.go b/src/cmd/compile/internal/types/etype_string.go
index 503a30d0b4..f234a31fd0 100644
--- a/src/cmd/compile/internal/types/etype_string.go
+++ b/src/cmd/compile/internal/types/etype_string.go
@@ -4,9 +4,9 @@ package types
import "strconv"
-const _EType_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTR32PTR64FUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSDDDFIELDSSATUPLENTYPE"
+const _EType_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSDDDFIELDSSATUPLENTYPE"
-var _EType_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 101, 106, 110, 115, 120, 126, 130, 133, 138, 142, 145, 151, 160, 165, 168, 173, 181, 189, 197, 200, 205, 210}
+var _EType_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 158, 161, 166, 174, 182, 190, 193, 198, 203}
func (i EType) String() string {
if i >= EType(len(_EType_index)-1) {
From 27965c14364a9812794cd4933b539f04a9d7c6c9 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Tue, 9 Oct 2018 11:01:34 +0000
Subject: [PATCH 084/240] cmd/compile: optimize 386's ADDLconstmodifyidx4
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This CL optimize ADDLconstmodifyidx4 to INCL/DECL, when the
constant is +1/-1.
1. The total size of pkg/linux_386/ decreases 28 bytes, excluding
cmd/compile.
2. There is no regression in the go1 benchmark test, excluding noise.
name old time/op new time/op delta
BinaryTree17-4 3.25s ± 2% 3.23s ± 3% -0.70% (p=0.040 n=30+30)
Fannkuch11-4 3.50s ± 1% 3.47s ± 1% -0.68% (p=0.000 n=30+30)
FmtFprintfEmpty-4 44.6ns ± 3% 44.8ns ± 3% +0.46% (p=0.029 n=30+30)
FmtFprintfString-4 79.0ns ± 3% 78.7ns ± 3% ~ (p=0.053 n=30+30)
FmtFprintfInt-4 89.2ns ± 2% 89.4ns ± 3% ~ (p=0.665 n=30+29)
FmtFprintfIntInt-4 142ns ± 3% 142ns ± 3% ~ (p=0.435 n=30+30)
FmtFprintfPrefixedInt-4 182ns ± 2% 182ns ± 2% ~ (p=0.964 n=30+30)
FmtFprintfFloat-4 407ns ± 3% 411ns ± 4% ~ (p=0.080 n=30+30)
FmtManyArgs-4 597ns ± 3% 593ns ± 4% ~ (p=0.222 n=30+30)
GobDecode-4 7.09ms ± 6% 7.07ms ± 7% ~ (p=0.633 n=30+30)
GobEncode-4 6.81ms ± 9% 6.81ms ± 8% ~ (p=0.982 n=30+30)
Gzip-4 398ms ± 4% 400ms ± 6% ~ (p=0.177 n=30+30)
Gunzip-4 41.3ms ± 3% 40.6ms ± 4% -1.71% (p=0.005 n=30+30)
HTTPClientServer-4 63.4µs ± 3% 63.4µs ± 4% ~ (p=0.646 n=30+28)
JSONEncode-4 16.0ms ± 3% 16.1ms ± 3% ~ (p=0.057 n=30+30)
JSONDecode-4 63.3ms ± 8% 63.1ms ± 7% ~ (p=0.786 n=30+30)
Mandelbrot200-4 5.17ms ± 3% 5.15ms ± 8% ~ (p=0.654 n=30+30)
GoParse-4 3.24ms ± 3% 3.23ms ± 2% ~ (p=0.091 n=30+30)
RegexpMatchEasy0_32-4 103ns ± 4% 103ns ± 4% ~ (p=0.575 n=30+30)
RegexpMatchEasy0_1K-4 823ns ± 2% 821ns ± 3% ~ (p=0.827 n=30+30)
RegexpMatchEasy1_32-4 113ns ± 3% 112ns ± 3% ~ (p=0.076 n=30+30)
RegexpMatchEasy1_1K-4 1.02µs ± 4% 1.01µs ± 5% ~ (p=0.087 n=30+30)
RegexpMatchMedium_32-4 129ns ± 3% 127ns ± 4% -1.55% (p=0.009 n=30+30)
RegexpMatchMedium_1K-4 39.3µs ± 4% 39.7µs ± 3% ~ (p=0.054 n=30+30)
RegexpMatchHard_32-4 2.15µs ± 4% 2.15µs ± 4% ~ (p=0.712 n=30+30)
RegexpMatchHard_1K-4 66.0µs ± 3% 65.1µs ± 3% -1.32% (p=0.002 n=30+30)
Revcomp-4 1.85s ± 2% 1.85s ± 3% ~ (p=0.168 n=30+30)
Template-4 69.5ms ± 7% 68.9ms ± 6% ~ (p=0.250 n=28+28)
TimeParse-4 434ns ± 3% 432ns ± 4% ~ (p=0.629 n=30+30)
TimeFormat-4 403ns ± 4% 408ns ± 3% +1.23% (p=0.019 n=30+29)
[Geo mean] 65.5µs 65.3µs -0.20%
name old speed new speed delta
GobDecode-4 108MB/s ± 6% 109MB/s ± 6% ~ (p=0.636 n=30+30)
GobEncode-4 113MB/s ±10% 113MB/s ± 9% ~ (p=0.982 n=30+30)
Gzip-4 48.8MB/s ± 4% 48.6MB/s ± 5% ~ (p=0.178 n=30+30)
Gunzip-4 470MB/s ± 3% 479MB/s ± 4% +1.72% (p=0.006 n=30+30)
JSONEncode-4 121MB/s ± 3% 120MB/s ± 3% ~ (p=0.057 n=30+30)
JSONDecode-4 30.7MB/s ± 8% 30.8MB/s ± 8% ~ (p=0.784 n=30+30)
GoParse-4 17.9MB/s ± 3% 17.9MB/s ± 2% ~ (p=0.090 n=30+30)
RegexpMatchEasy0_32-4 309MB/s ± 4% 309MB/s ± 3% ~ (p=0.530 n=30+30)
RegexpMatchEasy0_1K-4 1.24GB/s ± 2% 1.25GB/s ± 3% ~ (p=0.976 n=30+30)
RegexpMatchEasy1_32-4 282MB/s ± 3% 284MB/s ± 3% +0.81% (p=0.041 n=30+30)
RegexpMatchEasy1_1K-4 1.00GB/s ± 3% 1.01GB/s ± 4% ~ (p=0.091 n=30+30)
RegexpMatchMedium_32-4 7.71MB/s ± 3% 7.84MB/s ± 4% +1.71% (p=0.000 n=30+30)
RegexpMatchMedium_1K-4 26.1MB/s ± 4% 25.8MB/s ± 3% ~ (p=0.051 n=30+30)
RegexpMatchHard_32-4 14.9MB/s ± 4% 14.9MB/s ± 4% ~ (p=0.712 n=30+30)
RegexpMatchHard_1K-4 15.5MB/s ± 3% 15.7MB/s ± 3% +1.34% (p=0.003 n=30+30)
Revcomp-4 138MB/s ± 2% 137MB/s ± 3% ~ (p=0.174 n=30+30)
Template-4 28.0MB/s ± 6% 28.2MB/s ± 6% ~ (p=0.251 n=28+28)
[Geo mean] 82.3MB/s 82.6MB/s +0.36%
Change-Id: I389829699ffe9500a013fcf31be58a97e98043e1
Reviewed-on: https://go-review.googlesource.com/c/140701
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/x86/ssa.go | 21 ++++++++++++++++++++-
test/codegen/arithmetic.go | 2 ++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index 4ed46b9c8c..e0aebb449c 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -603,8 +603,27 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux2(&p.To, v, sc.Off())
+ case ssa.Op386ADDLconstmodifyidx4:
+ sc := v.AuxValAndOff()
+ val := sc.Val()
+ if val == 1 || val == -1 {
+ var p *obj.Prog
+ if val == 1 {
+ p = s.Prog(x86.AINCL)
+ } else {
+ p = s.Prog(x86.ADECL)
+ }
+ off := sc.Off()
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ p.To.Scale = 4
+ p.To.Index = v.Args[1].Reg()
+ gc.AddAux2(&p.To, v, off)
+ break
+ }
+ fallthrough
case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1,
- ssa.Op386ADDLconstmodifyidx4, ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
+ ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
sc := v.AuxValAndOff()
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index 0b209f5130..879aaf285c 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -32,6 +32,8 @@ func SubMem(arr []int, b, c, d int) int {
arr[c] -= b
// 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
arr[d] -= 15
+ // 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)`
+ arr[b]--
// 386:"SUBL\t4"
// amd64:"SUBQ\t8"
return arr[0] - arr[1]
From daf6f254336844ad8cf538640d81f0193988b62a Mon Sep 17 00:00:00 2001
From: Rob Pike
Date: Thu, 11 Oct 2018 13:13:03 +1100
Subject: [PATCH 085/240] unsafe: document that Alignof, Offsetof, and Sizeof
return a constant
Nothing is changing but the documentation, which did not mention
this property of these functions.
Fixes #27587.
Change-Id: I75bcee4a1dd9ec8cd82826c9a6e02ba7d599f719
Reviewed-on: https://go-review.googlesource.com/c/141377
Reviewed-by: Brad Fitzpatrick
---
src/unsafe/unsafe.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 00961cffa3..e16c4aeacb 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -178,11 +178,13 @@ type Pointer *ArbitraryType
// The size does not include any memory possibly referenced by x.
// For instance, if x is a slice, Sizeof returns the size of the slice
// descriptor, not the size of the memory referenced by the slice.
+// The return value of Sizeof is a Go constant.
func Sizeof(x ArbitraryType) uintptr
// Offsetof returns the offset within the struct of the field represented by x,
// which must be of the form structValue.field. In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
+// The return value of Offsetof is a Go constant.
func Offsetof(x ArbitraryType) uintptr
// Alignof takes an expression x of any type and returns the required alignment
@@ -193,4 +195,5 @@ func Offsetof(x ArbitraryType) uintptr
// within that struct, then Alignof(s.f) will return the required alignment
// of a field of that type within a struct. This case is the same as the
// value returned by reflect.TypeOf(s.f).FieldAlign().
+// The return value of Alignof is a Go constant.
func Alignof(x ArbitraryType) uintptr
From 9a9dc36f97bf57e186ab8183a27927abb9aecd61 Mon Sep 17 00:00:00 2001
From: Rob Pike
Date: Thu, 11 Oct 2018 13:21:54 +1100
Subject: [PATCH 086/240] text/template: explain that integer constants can
overflow
This behavior is the same as in Go: constants can be coerced to int
and whether overflow occurs depends on how big an int is, but
this surprises people sometimes, so document it again here.
Fixes #25833.
Change-Id: I557995f1a1e8e871b21004953923d16f36cb9037
Reviewed-on: https://go-review.googlesource.com/c/141378
Reviewed-by: Brad Fitzpatrick
---
src/text/template/doc.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index 4b243067b0..0179dec5c3 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -142,7 +142,9 @@ An argument is a simple value, denoted by one of the following.
- A boolean, string, character, integer, floating-point, imaginary
or complex constant in Go syntax. These behave like Go's untyped
- constants.
+ constants. Note that, as in Go, whether a large integer constant
+ overflows when assigned or passed to a function can depend on whether
+ the host machine's ints are 32 or 64 bits.
- The keyword nil, representing an untyped Go nil.
- The character '.' (period):
.
From c96c2a39bb09da48b3af63de58f65fdc82865746 Mon Sep 17 00:00:00 2001
From: LotusFenn
Date: Sat, 7 Jul 2018 09:21:04 +0800
Subject: [PATCH 087/240] bytes: vary the input alignment to Compare argument
in compare_test.go
Currently there are no tests that vary the alignment of Compare arguments.
Since Compare is written in assembly on most platforms (in internal/bytealg)
we should be testing different input alignments. This change modifies TestCompare
to vary the alignment of the second argument of Compare.
Updates #26129
Change-Id: I4c30a5adf96a41225df748675f4e9beea413b35c
Reviewed-on: https://go-review.googlesource.com/c/122536
Reviewed-by: Lotus Fenn
Reviewed-by: Ian Lance Taylor
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
---
src/bytes/compare_test.go | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/bytes/compare_test.go b/src/bytes/compare_test.go
index 3e33c27c9c..a321f2e086 100644
--- a/src/bytes/compare_test.go
+++ b/src/bytes/compare_test.go
@@ -41,9 +41,16 @@ var compareTests = []struct {
func TestCompare(t *testing.T) {
for _, tt := range compareTests {
- cmp := Compare(tt.a, tt.b)
- if cmp != tt.i {
- t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+ numShifts := 16
+ buffer := make([]byte, len(tt.b)+numShifts)
+ // vary the input alignment of tt.b
+ for offset := 0; offset <= numShifts; offset++ {
+ shiftedB := buffer[offset : len(tt.b)+offset]
+ copy(shiftedB, tt.b)
+ cmp := Compare(tt.a, shiftedB)
+ if cmp != tt.i {
+ t.Errorf(`Compare(%q, %q), offset %d = %v; want %v`, tt.a, tt.b, offset, cmp, tt.i)
+ }
}
}
}
From 23578f9d00bb0d6e92f18d7d6ea961d7c6c52260 Mon Sep 17 00:00:00 2001
From: Carlos Eduardo Seo
Date: Mon, 1 Oct 2018 23:37:00 -0300
Subject: [PATCH 088/240] cmd/compile: intrinsify TrailingZeros16,
OnesCount{8,16} for ppc64x
This change implements TrailingZeros16, OnesCount8 and OnesCount16
as intrinsics for ppc64x.
benchmark old ns/op new ns/op delta
BenchmarkTrailingZeros16-40 2.16 1.61 -25.46%
benchmark old ns/op new ns/op delta
BenchmarkOnesCount-40 0.71 0.71 +0.00%
BenchmarkOnesCount8-40 0.93 0.69 -25.81%
BenchmarkOnesCount16-40 1.54 0.75 -51.30%
BenchmarkOnesCount32-40 0.75 0.74 -1.33%
BenchmarkOnesCount64-40 0.71 0.71 +0.00%
Change-Id: I010fa9c0ef596a09362870d81193c633e70da637
Reviewed-on: https://go-review.googlesource.com/c/139137
Run-TryBot: Lynn Boger
TryBot-Result: Gobot Gobot
Reviewed-by: Lynn Boger
---
src/cmd/compile/internal/gc/ssa.go | 6 +--
src/cmd/compile/internal/ssa/gen/PPC64.rules | 4 +-
src/cmd/compile/internal/ssa/rewritePPC64.go | 54 +++++++++++++++++++-
3 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 469fbb8c96..5b11e15655 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -3236,7 +3236,7 @@ func init() {
y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
},
- sys.ARM64, sys.S390X)
+ sys.ARM64, sys.S390X, sys.PPC64)
addF("math/bits", "TrailingZeros8",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
@@ -3427,12 +3427,12 @@ func init() {
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue1(ssa.OpPopCount16, types.Types[TINT], args[0])
},
- sys.ARM64, sys.S390X)
+ sys.ARM64, sys.S390X, sys.PPC64)
addF("math/bits", "OnesCount8",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return s.newValue1(ssa.OpPopCount8, types.Types[TINT], args[0])
},
- sys.S390X)
+ sys.S390X, sys.PPC64)
addF("math/bits", "OnesCount",
makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
sys.AMD64)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index 21c12591c5..be1bd6de0b 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -297,6 +297,8 @@
(Ctz64 x) -> (POPCNTD (ANDN (ADDconst [-1] x) x))
(Ctz32 x) -> (POPCNTW (MOVWZreg (ANDN (ADDconst [-1] x) x)))
+(Ctz16 x) -> (POPCNTW (MOVHZreg (ANDN (ADDconst [-1] x) x)))
+(Ctz8 x) -> (POPCNTB (MOVBZreg (ANDN (ADDconst [-1] x) x)))
(BitLen64 x) -> (SUB (MOVDconst [64]) (CNTLZD x))
(BitLen32 x) -> (SUB (MOVDconst [32]) (CNTLZW x))
@@ -304,7 +306,7 @@
(PopCount64 x) -> (POPCNTD x)
(PopCount32 x) -> (POPCNTW (MOVWZreg x))
(PopCount16 x) -> (POPCNTW (MOVHZreg x))
-(PopCount8 x) -> (POPCNTB (MOVBreg x))
+(PopCount8 x) -> (POPCNTB (MOVBZreg x))
(And(64|32|16|8) x y) -> (AND x y)
(Or(64|32|16|8) x y) -> (OR x y)
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 9aff3106db..8f100c1a38 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -105,6 +105,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpConstNil_0(v)
case OpCopysign:
return rewriteValuePPC64_OpCopysign_0(v)
+ case OpCtz16:
+ return rewriteValuePPC64_OpCtz16_0(v)
case OpCtz32:
return rewriteValuePPC64_OpCtz32_0(v)
case OpCtz32NonZero:
@@ -113,6 +115,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpCtz64_0(v)
case OpCtz64NonZero:
return rewriteValuePPC64_OpCtz64NonZero_0(v)
+ case OpCtz8:
+ return rewriteValuePPC64_OpCtz8_0(v)
case OpCvt32Fto32:
return rewriteValuePPC64_OpCvt32Fto32_0(v)
case OpCvt32Fto64:
@@ -1323,6 +1327,29 @@ func rewriteValuePPC64_OpCopysign_0(v *Value) bool {
return true
}
}
+func rewriteValuePPC64_OpCtz16_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Ctz16 x)
+ // cond:
+ // result: (POPCNTW (MOVHZreg (ANDN (ADDconst [-1] x) x)))
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64POPCNTW)
+ v0 := b.NewValue0(v.Pos, OpPPC64MOVHZreg, typ.Int64)
+ v1 := b.NewValue0(v.Pos, OpPPC64ANDN, typ.Int16)
+ v2 := b.NewValue0(v.Pos, OpPPC64ADDconst, typ.Int16)
+ v2.AuxInt = -1
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValuePPC64_OpCtz32_0(v *Value) bool {
b := v.Block
_ = b
@@ -1389,6 +1416,29 @@ func rewriteValuePPC64_OpCtz64NonZero_0(v *Value) bool {
return true
}
}
+func rewriteValuePPC64_OpCtz8_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Ctz8 x)
+ // cond:
+ // result: (POPCNTB (MOVBZreg (ANDN (ADDconst [-1] x) x)))
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64POPCNTB)
+ v0 := b.NewValue0(v.Pos, OpPPC64MOVBZreg, typ.Int64)
+ v1 := b.NewValue0(v.Pos, OpPPC64ANDN, typ.UInt8)
+ v2 := b.NewValue0(v.Pos, OpPPC64ADDconst, typ.UInt8)
+ v2.AuxInt = -1
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValuePPC64_OpCvt32Fto32_0(v *Value) bool {
b := v.Block
_ = b
@@ -26653,11 +26703,11 @@ func rewriteValuePPC64_OpPopCount8_0(v *Value) bool {
_ = typ
// match: (PopCount8 x)
// cond:
- // result: (POPCNTB (MOVBreg x))
+ // result: (POPCNTB (MOVBZreg x))
for {
x := v.Args[0]
v.reset(OpPPC64POPCNTB)
- v0 := b.NewValue0(v.Pos, OpPPC64MOVBreg, typ.Int64)
+ v0 := b.NewValue0(v.Pos, OpPPC64MOVBZreg, typ.Int64)
v0.AddArg(x)
v.AddArg(v0)
return true
From 1d0e94b1e13d5e8a323a63cd1cc1ef95290c9c36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:58:19 +0200
Subject: [PATCH 089/240] path/filepath: add AIX operating system
This commit adds AIX operating system to path/filepath package
for ppc64 architecture.
Updates: #25893
Change-Id: Iea551236d334705a58a446c8992b20adcfe4159b
Reviewed-on: https://go-review.googlesource.com/c/138726
Reviewed-by: Brad Fitzpatrick
---
src/path/filepath/path_unix.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 349dea7b53..c10b3288a1 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package filepath
From bac6a2925c50964e9387da5d37f2f23d4e5e7ac4 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Tue, 9 Oct 2018 06:56:49 +0000
Subject: [PATCH 090/240] test/codegen: add more arm64 test cases
This CL adds 3 combined load test cases for arm64.
Change-Id: I2c67308c40fd8a18f9f2d16c6d12911dcdc583e2
Reviewed-on: https://go-review.googlesource.com/c/140700
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
test/codegen/memcombine.go | 40 +++++++++++++++++---------------------
1 file changed, 18 insertions(+), 22 deletions(-)
diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go
index 9c4b36818e..230aadfb74 100644
--- a/test/codegen/memcombine.go
+++ b/test/codegen/memcombine.go
@@ -468,6 +468,24 @@ func store_be_byte_2_idx2(b []byte, idx int, val uint16) {
b[(idx<<1)+0], b[(idx<<1)+1] = byte(val>>8), byte(val)
}
+func store_le_byte_2_idx2(b []byte, idx int, val uint16) {
+ _, _ = b[(idx<<1)+0], b[(idx<<1)+1]
+ // arm64:`MOVH\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<1\)`,-`MOVB`
+ b[(idx<<1)+1], b[(idx<<1)+0] = byte(val>>8), byte(val)
+}
+
+func store_be_byte_4_idx4(b []byte, idx int, val uint32) {
+ _, _, _, _ = b[(idx<<2)+0], b[(idx<<2)+1], b[(idx<<2)+2], b[(idx<<2)+3]
+ // arm64:`REVW`,`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<2\)`,-`MOVB`,-`MOVH`,-`REV16W`
+ b[(idx<<2)+0], b[(idx<<2)+1], b[(idx<<2)+2], b[(idx<<2)+3] = byte(val>>24), byte(val>>16), byte(val>>8), byte(val)
+}
+
+func store_le_byte_4_idx4_inv(b []byte, idx int, val uint32) {
+ _, _, _, _ = b[(idx<<2)+0], b[(idx<<2)+1], b[(idx<<2)+2], b[(idx<<2)+3]
+ // arm64:`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<2\)`,-`MOVB`,-`MOVH`
+ b[(idx<<2)+3], b[(idx<<2)+2], b[(idx<<2)+1], b[(idx<<2)+0] = byte(val>>24), byte(val>>16), byte(val>>8), byte(val)
+}
+
// ------------- //
// Zeroing //
// ------------- //
@@ -501,28 +519,6 @@ func zero_byte_16(b []byte) {
b[12], b[13], b[14], b[15] = 0, 0, 0, 0 // arm64:"STP",-"MOVB",-"MOVH",-"MOVW"
}
-/* TODO: enable them when corresponding optimization are implemented
-func zero_byte_4_idx(b []byte, idx int) {
- // arm64(DISABLED): `MOVW\sZR,\s\(R[0-9]+\)\(R[0-9]+<<2\)`,-`MOV[BH]`
- b[(idx<<2)+0] = 0
- b[(idx<<2)+1] = 0
- b[(idx<<2)+2] = 0
- b[(idx<<2)+3] = 0
-}
-
-func zero_byte_8_idx(b []byte, idx int) {
- // arm64(DISABLED): `MOVD\sZR,\s\(R[0-9]+\)\(R[0-9]+<<3\)`,-`MOV[BHW]`
- b[(idx<<3)+0] = 0
- b[(idx<<3)+1] = 0
- b[(idx<<3)+2] = 0
- b[(idx<<3)+3] = 0
- b[(idx<<3)+4] = 0
- b[(idx<<3)+5] = 0
- b[(idx<<3)+6] = 0
- b[(idx<<3)+7] = 0
-}
-*/
-
func zero_byte_30(a *[30]byte) {
*a = [30]byte{} // arm64:"STP",-"MOVB",-"MOVH",-"MOVW"
}
From 69c5830c2b74b9bf0701352f2e5773227cb6f304 Mon Sep 17 00:00:00 2001
From: David Chase
Date: Wed, 10 Oct 2018 16:08:24 -0400
Subject: [PATCH 091/240] cmd/compile: repair display of values & blocks in
prog column
This restores the printing of vXX and bYY in the left-hand
edge of the last column of ssa.html, where the generated
progs appear.
Change-Id: I81ab9b2fa5ae28e6e5de1b77665cfbed8d14e000
Reviewed-on: https://go-review.googlesource.com/c/141277
Run-TryBot: David Chase
TryBot-Result: Gobot Gobot
Reviewed-by: Yury Smolsky
---
src/cmd/compile/internal/gc/ssa.go | 13 ++++++-------
src/cmd/compile/internal/ssa/debug.go | 6 +++++-
src/cmd/compile/internal/ssa/func.go | 7 ++++---
3 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 5b11e15655..4a4461948c 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -147,6 +147,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.f.Cache.Reset()
s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH", name)
s.f.Name = name
+ s.f.PrintOrHtmlSSA = printssa
if fn.Func.Pragma&Nosplit != 0 {
s.f.NoSplit = true
}
@@ -5000,9 +5001,7 @@ func genssa(f *ssa.Func, pp *Progs) {
var progToValue map[*obj.Prog]*ssa.Value
var progToBlock map[*obj.Prog]*ssa.Block
var valueToProgAfter []*obj.Prog // The first Prog following computation of a value v; v is visible at this point.
- var logProgs = e.log
- if f.HTMLWriter != nil {
- // logProgs can be false, meaning that we do not dump to the Stdout.
+ if f.PrintOrHtmlSSA {
progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
f.Logf("genssa %s\n", f.Name)
@@ -5085,7 +5084,7 @@ func genssa(f *ssa.Func, pp *Progs) {
valueToProgAfter[v.ID] = s.pp.next
}
- if logProgs {
+ if f.PrintOrHtmlSSA {
for ; x != s.pp.next; x = x.Link {
progToValue[x] = v
}
@@ -5103,7 +5102,7 @@ func genssa(f *ssa.Func, pp *Progs) {
x := s.pp.next
s.SetPos(b.Pos)
thearch.SSAGenBlock(&s, b, next)
- if logProgs {
+ if f.PrintOrHtmlSSA {
for ; x != s.pp.next; x = x.Link {
progToBlock[x] = b
}
@@ -5136,7 +5135,7 @@ func genssa(f *ssa.Func, pp *Progs) {
}
}
- if logProgs {
+ if e.log { // spew to stdout
filename := ""
for p := pp.Text; p != nil; p = p.Link {
if p.Pos.IsKnown() && p.InnermostFilename() != filename {
@@ -5155,7 +5154,7 @@ func genssa(f *ssa.Func, pp *Progs) {
f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
}
}
- if f.HTMLWriter != nil {
+ if f.HTMLWriter != nil { // spew to ssa.html
var buf bytes.Buffer
buf.WriteString("")
buf.WriteString("")
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index c1fbdcc517..8df8a94b76 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -153,8 +153,12 @@ var BlockEnd = &Value{
// RegisterSet is a bitmap of registers, indexed by Register.num.
type RegisterSet uint64
+// logf prints debug-specific logging to stdout (always stdout) if the current
+// function is tagged by GOSSAFUNC (for ssa output directed either to stdout or html).
func (s *debugState) logf(msg string, args ...interface{}) {
- s.f.Logf(msg, args...)
+ if s.f.PrintOrHtmlSSA {
+ fmt.Printf(msg, args...)
+ }
}
type debugState struct {
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index eb5775efcb..2ed4086fd1 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -37,9 +37,10 @@ type Func struct {
// Given an environment variable used for debug hash match,
// what file (if any) receives the yes/no logging?
- logfiles map[string]writeSyncer
- HTMLWriter *HTMLWriter // html writer, for debugging
- DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
+ logfiles map[string]writeSyncer
+ HTMLWriter *HTMLWriter // html writer, for debugging
+ DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
+ PrintOrHtmlSSA bool // true if GOSSAFUNC matches, true even if fe.Log() (spew phase results to stdout) is false.
scheduled bool // Values in Blocks are in final order
NoSplit bool // true if function is marked as nosplit. Used by schedule check pass.
From 835f983da6866deec1c6550555c96de729c8848c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?=
Date: Fri, 28 Sep 2018 15:57:27 +0200
Subject: [PATCH 092/240] os: add AIX operating system
This commit adds AIX operating system to os package for ppc64
architecture.
Updates: #25893
Change-Id: Ieb9a2b3ac5b9abd3b5ab68eb732c17b6256d624d
Reviewed-on: https://go-review.googlesource.com/c/138725
Reviewed-by: Brad Fitzpatrick
Run-TryBot: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/os/dir_unix.go | 2 +-
src/os/env_unix_test.go | 2 +-
src/os/error_posix.go | 2 +-
src/os/error_unix.go | 2 +-
src/os/error_unix_test.go | 2 +-
src/os/exec/exec_posix_test.go | 2 +-
src/os/exec/lp_unix.go | 2 +-
src/os/exec/lp_unix_test.go | 2 +-
src/os/exec_posix.go | 2 +-
src/os/exec_unix.go | 2 +-
src/os/executable_path.go | 2 +-
src/os/file_posix.go | 2 +-
src/os/file_unix.go | 2 +-
src/os/os_unix_test.go | 2 +-
src/os/path_unix.go | 2 +-
src/os/pipe_bsd.go | 2 +-
src/os/signal/internal/pty/pty.go | 2 +-
src/os/signal/signal_test.go | 2 +-
src/os/signal/signal_unix.go | 2 +-
src/os/stat_aix.go | 51 +++++++++++++++++++++++++++++++
src/os/stat_unix.go | 2 +-
src/os/sys_aix.go | 26 ++++++++++++++++
src/os/sys_unix.go | 2 +-
src/os/user/cgo_lookup_unix.go | 2 +-
src/os/user/lookup_stubs.go | 4 +--
src/os/user/lookup_unix.go | 2 +-
src/os/user/lookup_unix_test.go | 2 +-
src/os/wait_unimp.go | 2 +-
28 files changed, 104 insertions(+), 27 deletions(-)
create mode 100644 src/os/stat_aix.go
create mode 100644 src/os/sys_aix.go
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 79d61c783f..7a3ef47ce2 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/env_unix_test.go b/src/os/env_unix_test.go
index f7b67ebbb8..89430b3e20 100644
--- a/src/os/env_unix_test.go
+++ b/src/os/env_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
diff --git a/src/os/error_posix.go b/src/os/error_posix.go
index 3c81b41706..0478ba676a 100644
--- a/src/os/error_posix.go
+++ b/src/os/error_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package os
diff --git a/src/os/error_unix.go b/src/os/error_unix.go
index a9d798b391..bb6bbcc1e6 100644
--- a/src/os/error_unix.go
+++ b/src/os/error_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/error_unix_test.go b/src/os/error_unix_test.go
index 8db98676d1..c47af56332 100644
--- a/src/os/error_unix_test.go
+++ b/src/os/error_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os_test
diff --git a/src/os/exec/exec_posix_test.go b/src/os/exec/exec_posix_test.go
index 865b6c3ced..46799cdbdb 100644
--- a/src/os/exec/exec_posix_test.go
+++ b/src/os/exec/exec_posix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package exec_test
diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go
index e098ff8e1d..799e0b4eeb 100644
--- a/src/os/exec/lp_unix.go
+++ b/src/os/exec/lp_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package exec
diff --git a/src/os/exec/lp_unix_test.go b/src/os/exec/lp_unix_test.go
index d467acf5db..e4656cafb8 100644
--- a/src/os/exec/lp_unix_test.go
+++ b/src/os/exec/lp_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package exec
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go
index e837e1c4d9..1e60365dba 100644
--- a/src/os/exec_posix.go
+++ b/src/os/exec_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package os
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index b07543e550..abae5a2feb 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/executable_path.go b/src/os/executable_path.go
index 057e6a72f4..7b8b83652c 100644
--- a/src/os/executable_path.go
+++ b/src/os/executable_path.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build openbsd
+// +build aix openbsd
package os
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index 7cfafc8fde..544d0ad55d 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package os
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index cb90b70735..0ca34b070d 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 1077d78613..0317f7257e 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index b2e0bca0df..3cb0e3acc4 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/pipe_bsd.go b/src/os/pipe_bsd.go
index 9735988f32..dc4c951a28 100644
--- a/src/os/pipe_bsd.go
+++ b/src/os/pipe_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly js,wasm nacl solaris
+// +build aix darwin dragonfly js,wasm nacl solaris
package os
diff --git a/src/os/signal/internal/pty/pty.go b/src/os/signal/internal/pty/pty.go
index c4c1567fce..c1c7fcffc5 100644
--- a/src/os/signal/internal/pty/pty.go
+++ b/src/os/signal/internal/pty/pty.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux,!android netbsd openbsd
+// +build aix darwin dragonfly freebsd linux,!android netbsd openbsd
// +build cgo
// Package pty is a simple pseudo-terminal package for Unix systems,
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 3d79c7a861..ecb05fd16c 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package signal
diff --git a/src/os/signal/signal_unix.go b/src/os/signal/signal_unix.go
index 28fbb54995..7fa634f15a 100644
--- a/src/os/signal/signal_unix.go
+++ b/src/os/signal/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package signal
diff --git a/src/os/stat_aix.go b/src/os/stat_aix.go
new file mode 100644
index 0000000000..a37c9fdae4
--- /dev/null
+++ b/src/os/stat_aix.go
@@ -0,0 +1,51 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "time"
+)
+
+func fillFileStatFromSys(fs *fileStat, name string) {
+ fs.name = basename(name)
+ fs.size = int64(fs.sys.Size)
+ fs.modTime = stTimespecToTime(fs.sys.Mtim)
+ fs.mode = FileMode(fs.sys.Mode & 0777)
+ switch fs.sys.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if fs.sys.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if fs.sys.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if fs.sys.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+}
+
+func stTimespecToTime(ts syscall.StTimespec_t) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return stTimespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
+}
diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go
index 856b49929f..4f85dcea07 100644
--- a/src/os/stat_unix.go
+++ b/src/os/stat_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/sys_aix.go b/src/os/sys_aix.go
new file mode 100644
index 0000000000..53a40f2677
--- /dev/null
+++ b/src/os/sys_aix.go
@@ -0,0 +1,26 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+// gethostname syscall cannot be used because it also returns the domain.
+// Therefore, hostname is retrieve with uname syscall and the Nodename field.
+
+func hostname() (name string, err error) {
+ var u syscall.Utsname
+ if errno := syscall.Uname(&u); errno != nil {
+ return "", NewSyscallError("uname", errno)
+ }
+ b := make([]byte, len(u.Nodename))
+ i := 0
+ for ; i < len(u.Nodename); i++ {
+ if u.Nodename[i] == 0 {
+ break
+ }
+ b[i] = byte(u.Nodename[i])
+ }
+ return string(b[:i]), nil
+}
diff --git a/src/os/sys_unix.go b/src/os/sys_unix.go
index 3c63c10409..8491bad242 100644
--- a/src/os/sys_unix.go
+++ b/src/os/sys_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package os
diff --git a/src/os/user/cgo_lookup_unix.go b/src/os/user/cgo_lookup_unix.go
index ccb2278246..856ed28de8 100644
--- a/src/os/user/cgo_lookup_unix.go
+++ b/src/os/user/cgo_lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo,!osusergo
package user
diff --git a/src/os/user/lookup_stubs.go b/src/os/user/lookup_stubs.go
index 9fc03c65d9..61bf1dc7a6 100644
--- a/src/os/user/lookup_stubs.go
+++ b/src/os/user/lookup_stubs.go
@@ -65,8 +65,8 @@ func current() (*User, error) {
}
func listGroups(*User) ([]string, error) {
- if runtime.GOOS == "android" {
- return nil, errors.New("user: GroupIds not implemented on Android")
+ if runtime.GOOS == "android" || runtime.GOOS == "aix" {
+ return nil, errors.New(fmt.Sprintf("user: GroupIds not implemented on %s", runtime.GOOS))
}
return nil, errors.New("user: GroupIds requires cgo")
}
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index c4e9ba1e81..be62f4d0c3 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm !android,linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm !android,linux nacl netbsd openbsd solaris
// +build !cgo osusergo
package user
diff --git a/src/os/user/lookup_unix_test.go b/src/os/user/lookup_unix_test.go
index 02c88ab875..65fe0656de 100644
--- a/src/os/user/lookup_unix_test.go
+++ b/src/os/user/lookup_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
// +build !cgo
package user
diff --git a/src/os/wait_unimp.go b/src/os/wait_unimp.go
index 3d8210f5bd..d070604600 100644
--- a/src/os/wait_unimp.go
+++ b/src/os/wait_unimp.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly js,wasm nacl netbsd openbsd solaris
+// +build aix darwin dragonfly js,wasm nacl netbsd openbsd solaris
package os
From 689321e1087180ef8e823bee7befe4609d67b727 Mon Sep 17 00:00:00 2001
From: Florian
Date: Wed, 3 Oct 2018 15:31:35 +0000
Subject: [PATCH 093/240] doc: add link to the Go Discord forum
I've linked the gophers discord. It's a well administered discord which already got many members, but it was never officially linked. For many people it's a quality proof if a discord is linked on the official page. I think there are much more people out there, who would prefer to use discord instead of slack or irc.
The discord already got many users without even being promoted, so it's very likely there are many people who are interested in a discord, but they don't want to use unofficial discords. This discord shouldn't be seen as a competitor for the slack, it's a platform for those, who don't want to use slack.
Change-Id: Ib1ee7173f394b810f5cccf67b498485ecbf8a7db
GitHub-Last-Rev: 286ebad994a52f55b685deeda8a86cfac4a9964b
GitHub-Pull-Request: golang/go#24176
Reviewed-on: https://go-review.googlesource.com/c/97718
Reviewed-by: Andrew Bonventre
Reviewed-by: Brad Fitzpatrick
---
doc/help.html | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/doc/help.html b/doc/help.html
index f668196871..f11e286904 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -27,6 +27,11 @@ The Go Forum is a discussion
forum for Go programmers.
+
+
+Get live support and talk with other gophers on the Go Discord.
+
+
Get live support from other users in the Go slack channel.
From e2d70b8b4b7a9450b66e3516f36e75f46b7fb80f Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Wed, 3 Oct 2018 20:28:47 -0400
Subject: [PATCH 094/240] regexp: simplify BenchmarkCompileOnepass
One benchmark is fine.
Having one per test case is overkill.
Change-Id: Id4ce789484dab1e79026bdd23cbcd63b2eaceb3f
Reviewed-on: https://go-review.googlesource.com/c/139777
Run-TryBot: Russ Cox
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/regexp/onepass_test.go | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go
index b1caa44515..6b622ac356 100644
--- a/src/regexp/onepass_test.go
+++ b/src/regexp/onepass_test.go
@@ -227,21 +227,11 @@ func TestRunOnePass(t *testing.T) {
}
func BenchmarkCompileOnepass(b *testing.B) {
- for _, test := range onePassTests {
- if test.onePass == notOnePass {
- continue
+ b.ReportAllocs()
+ const re = `^a.[l-nA-Cg-j]?e$`
+ for i := 0; i < b.N; i++ {
+ if _, err := Compile(re); err != nil {
+ b.Fatal(err)
}
- name := test.re
- if len(name) > 20 {
- name = name[:20] + "..."
- }
- b.Run(name, func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- if _, err := Compile(test.re); err != nil {
- b.Fatal(err)
- }
- }
- })
}
}
From 872a5479574f11d7ebe78118226f2a423e89c993 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Tue, 2 Oct 2018 09:09:10 -0400
Subject: [PATCH 095/240] regexp: fix BenchmarkMatch_onepass_regex
This benchmark - in contrast to all other benchmarks - was
running the regexp match on 1-byte substrings of the input
instead of the entire input. Worse, it was doing so by preallocating
a slice of slices of every 1-byte substring. Needless to say,
this does not accurately reflect what happens when the regexp
matcher is given a large input.
Change-Id: Icd5b95f0e43f554a6b93164916745941366e03d6
Reviewed-on: https://go-review.googlesource.com/c/139778
Run-TryBot: Russ Cox
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/regexp/exec_test.go | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 5f8e747b17..02258e6e74 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -692,18 +692,12 @@ func BenchmarkMatch_onepass_regex(b *testing.B) {
continue
}
t := makeText(size.n)
- bs := make([][]byte, len(t))
- for i, s := range t {
- bs[i] = []byte{s}
- }
b.Run(size.name, func(b *testing.B) {
b.SetBytes(int64(size.n))
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- for _, byts := range bs {
- if !r.Match(byts) {
- b.Fatal("not match!")
- }
+ if !r.Match(t) {
+ b.Fatal("not match!")
}
}
})
From 76f578459a3db0153237816a7513497092463aae Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 10 Oct 2018 17:19:29 -0700
Subject: [PATCH 096/240] go/types: use correct receiver types for embedded
interface methods
Interface methods don't declare a receiver (it's implicit), but after
type-checking the respective *types.Func objects are marked as methods
by having a receiver. For interface methods, the receiver base type used
to be the interface that declared the method in the first place, even if
the method also appeared in other interfaces via embedding. A change in
the computation of method sets for interfaces for Go1.10 changed that
inadvertently, with the consequence that sometimes a method's receiver
type ended up being an interface into which the method was embedded.
The exact behavior also depended on file type-checking order, and because
files are sometimes sorted by name, the behavior depended on file names.
This didn't matter for type-checking (the typechecker doesn't need the
receiver), but it matters for clients, and for printing of methods.
This change fixes interface method receivers at the end of type-checking
when we have all relevant information.
Fixes #28005.
Change-Id: I96c120fb0e517d7f8a14b8530f0273674569d5ea
Reviewed-on: https://go-review.googlesource.com/c/141358
Reviewed-by: Alan Donovan
---
src/go/types/issues_test.go | 67 +++++++++++++++++++++++++++++++++++++
src/go/types/typexpr.go | 27 +++++++++++++--
2 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 8560bb9b7d..f8810b6734 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -355,3 +355,70 @@ func TestIssue25627(t *testing.T) {
})
}
}
+
+func TestIssue28005(t *testing.T) {
+ // method names must match defining interface name for this test
+ // (see last comment in this function)
+ sources := [...]string{
+ "package p; type A interface{ A() }",
+ "package p; type B interface{ B() }",
+ "package p; type X interface{ A; B }",
+ }
+
+ // compute original file ASTs
+ var orig [len(sources)]*ast.File
+ for i, src := range sources {
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ orig[i] = f
+ }
+
+ // run the test for all order permutations of the incoming files
+ for _, perm := range [][len(sources)]int{
+ {0, 1, 2},
+ {0, 2, 1},
+ {1, 0, 2},
+ {1, 2, 0},
+ {2, 0, 1},
+ {2, 1, 0},
+ } {
+ // create file order permutation
+ files := make([]*ast.File, len(sources))
+ for i := range perm {
+ files[i] = orig[perm[i]]
+ }
+
+ // type-check package with given file order permutation
+ var conf Config
+ info := &Info{Defs: make(map[*ast.Ident]Object)}
+ _, err := conf.Check("", fset, files, info)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // look for interface object X
+ var obj Object
+ for name, def := range info.Defs {
+ if name.Name == "X" {
+ obj = def
+ break
+ }
+ }
+ if obj == nil {
+ t.Fatal("interface not found")
+ }
+ iface := obj.Type().Underlying().(*Interface) // I must be an interface
+
+ // Each iface method m is embedded; and m's receiver base type name
+ // must match the method's name per the choice in the source file.
+ for i := 0; i < iface.NumMethods(); i++ {
+ m := iface.Method(i)
+ recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
+ if recvName != m.Name() {
+ t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
+ }
+ }
+ }
+}
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index 0f23345792..e6d61b7ec7 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -549,6 +549,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
recvTyp = def
}
+ // Correct receiver type for all methods explicitly declared
+ // by this interface after we're done with type-checking at
+ // this level. See comment below for details.
+ check.later(func() {
+ for _, m := range ityp.methods {
+ m.typ.(*Signature).recv.typ = recvTyp
+ }
+ })
+
// collect methods
var sigfix []*methodInfo
for i, minfo := range info.methods {
@@ -562,8 +571,22 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
// its position, and because interface method
// signatures don't get a receiver via regular
// type-checking (there isn't a receiver in the
- // method's AST). Setting the correct receiver
- // type is also important for ptrRecv() (see methodset.go).
+ // method's AST). Setting the receiver type is
+ // also important for ptrRecv() (see methodset.go).
+ //
+ // Note: For embedded methods, the receiver type
+ // should be the type of the interface that declared
+ // the methods in the first place. Since we get the
+ // methods here via methodInfo, which may be computed
+ // before we have all relevant interface types, we use
+ // the current interface's type (recvType). This may be
+ // the type of the interface embedding the interface that
+ // declared the methods. This doesn't matter for type-
+ // checking (we only care about the receiver type for
+ // the ptrRecv predicate, and it's never a pointer recv
+ // for interfaces), but it matters for go/types clients
+ // and for printing. We correct the receiver after type-
+ // checking.
//
// TODO(gri) Consider marking methods signatures
// as incomplete, for better error messages. See
From 7fb60eb1a2aaed7a801ab15bd7aaeaabdbb5e5db Mon Sep 17 00:00:00 2001
From: Ian Davis
Date: Fri, 5 Oct 2018 10:07:29 +0100
Subject: [PATCH 097/240] cmd/vet: detect non-pointer arguments for unmarshal
and decode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Checks usage of Unmarshal and Decode functions in json, gob and
xml packages to detect attempts to decode into non-pointer types.
Fixes #27564
Change-Id: I07bbd5be82d61834ffde9af9937329d7fb1f05d0
Reviewed-on: https://go-review.googlesource.com/c/139997
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
Reviewed-by: Alan Donovan
---
src/cmd/vet/testdata/unmarshal.go | 60 ++++++++++++++++++++++++++
src/cmd/vet/unmarshal.go | 72 +++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+)
create mode 100644 src/cmd/vet/testdata/unmarshal.go
create mode 100644 src/cmd/vet/unmarshal.go
diff --git a/src/cmd/vet/testdata/unmarshal.go b/src/cmd/vet/testdata/unmarshal.go
new file mode 100644
index 0000000000..f541b4a414
--- /dev/null
+++ b/src/cmd/vet/testdata/unmarshal.go
@@ -0,0 +1,60 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the unmarshal checker.
+
+package testdata
+
+import (
+ "bytes"
+ "encoding/gob"
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+)
+
+func _() {
+ type t struct {
+ a int
+ }
+ var v t
+ var r io.Reader
+
+ json.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ json.Unmarshal([]byte{}, &v)
+ json.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
+ json.NewDecoder(r).Decode(&v)
+ gob.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
+ gob.NewDecoder(r).Decode(&v)
+ xml.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ xml.Unmarshal([]byte{}, &v)
+ xml.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
+ xml.NewDecoder(r).Decode(&v)
+
+ var p *t
+ json.Unmarshal([]byte{}, p)
+ json.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ json.NewDecoder(r).Decode(p)
+ json.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
+ gob.NewDecoder(r).Decode(p)
+ gob.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
+ xml.Unmarshal([]byte{}, p)
+ xml.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ xml.NewDecoder(r).Decode(p)
+ xml.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
+
+ var i interface{}
+ json.Unmarshal([]byte{}, i)
+ json.NewDecoder(r).Decode(i)
+
+ json.Unmarshal([]byte{}, nil) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ json.Unmarshal([]byte{}, []t{}) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ json.Unmarshal([]byte{}, map[string]int{}) // ERROR "call of Unmarshal passes non-pointer as second argument"
+ json.NewDecoder(r).Decode(nil) // ERROR "call of Decode passes non-pointer"
+ json.NewDecoder(r).Decode([]t{}) // ERROR "call of Decode passes non-pointer"
+ json.NewDecoder(r).Decode(map[string]int{}) // ERROR "call of Decode passes non-pointer"
+
+ json.Unmarshal(func() ([]byte, interface{}) { return []byte{}, v }())
+}
diff --git a/src/cmd/vet/unmarshal.go b/src/cmd/vet/unmarshal.go
new file mode 100644
index 0000000000..3e4c25b6b9
--- /dev/null
+++ b/src/cmd/vet/unmarshal.go
@@ -0,0 +1,72 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines the check for passing non-pointer or non-interface
+// types to unmarshal and decode functions.
+
+package main
+
+import (
+ "go/ast"
+ "go/types"
+ "strings"
+)
+
+func init() {
+ register("unmarshal",
+ "check for passing non-pointer or non-interface types to unmarshal and decode functions",
+ checkUnmarshalArg,
+ callExpr)
+}
+
+var pointerArgFuncs = map[string]int{
+ "encoding/json.Unmarshal": 1,
+ "(*encoding/json.Decoder).Decode": 0,
+ "(*encoding/gob.Decoder).Decode": 0,
+ "encoding/xml.Unmarshal": 1,
+ "(*encoding/xml.Decoder).Decode": 0,
+}
+
+func checkUnmarshalArg(f *File, n ast.Node) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok {
+ return // not a call statement
+ }
+ fun := unparen(call.Fun)
+
+ if f.pkg.types[fun].IsType() {
+ return // a conversion, not a call
+ }
+
+ info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
+ name := callName(info, call)
+
+ arg, ok := pointerArgFuncs[name]
+ if !ok {
+ return // not a function we are interested in
+ }
+
+ if len(call.Args) < arg+1 {
+ return // not enough arguments, e.g. called with return values of another function
+ }
+
+ typ := f.pkg.types[call.Args[arg]]
+
+ if typ.Type == nil {
+ return // type error prevents further analysis
+ }
+
+ switch typ.Type.Underlying().(type) {
+ case *types.Pointer, *types.Interface:
+ return
+ }
+
+ shortname := name[strings.LastIndexByte(name, '.')+1:]
+ switch arg {
+ case 0:
+ f.Badf(call.Lparen, "call of %s passes non-pointer", shortname)
+ case 1:
+ f.Badf(call.Lparen, "call of %s passes non-pointer as second argument", shortname)
+ }
+}
From f64fd66f24d5c19d26ac58c4027aa9398a935490 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 10 Oct 2018 14:13:49 -0700
Subject: [PATCH 098/240] go/scanner: don't return token.INVALID for ".."
sequence
Per the spec, "...the next token is the longest sequence of characters
that form a valid token." Thus, encountering a ".." sequence should
return two token.PERIOD tokens rather than a single token.ILLEGAL.
Fixes #28112.
Change-Id: Iba5da841f40036e53f48f9be23f933f362e67f5e
Reviewed-on: https://go-review.googlesource.com/c/141337
Reviewed-by: Dmitri Shuralyov
---
src/go/scanner/scanner.go | 20 ++++++++++++++------
src/go/scanner/scanner_test.go | 20 +++++++++++++++++++-
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index 23bbb2885f..e78abf12a2 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -85,6 +85,15 @@ func (s *Scanner) next() {
}
}
+// peek returns the byte following the most recently read character without
+// advancing the scanner. If the scanner is at EOF, peek returns 0.
+func (s *Scanner) peek() byte {
+ if s.rdOffset < len(s.src) {
+ return s.src[s.rdOffset]
+ }
+ return 0
+}
+
// A mode value is a set of flags (or 0).
// They control scanner behavior.
//
@@ -735,14 +744,13 @@ scanAgain:
if '0' <= s.ch && s.ch <= '9' {
insertSemi = true
tok, lit = s.scanNumber(true)
- } else if s.ch == '.' {
- s.next()
- if s.ch == '.' {
- s.next()
- tok = token.ELLIPSIS
- }
} else {
tok = token.PERIOD
+ if s.ch == '.' && s.peek() == '.' {
+ s.next()
+ s.next() // consume last '.'
+ tok = token.ELLIPSIS
+ }
}
case ',':
tok = token.COMMA
diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
index 0aad368099..36c962209c 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -757,6 +757,7 @@ var errors = []struct {
{"\a", token.ILLEGAL, 0, "", "illegal character U+0007"},
{`#`, token.ILLEGAL, 0, "", "illegal character U+0023 '#'"},
{`…`, token.ILLEGAL, 0, "", "illegal character U+2026 '…'"},
+ {"..", token.PERIOD, 0, "", ""}, // two periods, not invalid token (issue #28112)
{`' '`, token.CHAR, 0, `' '`, ""},
{`''`, token.CHAR, 0, `''`, "illegal rune literal"},
{`'12'`, token.CHAR, 0, `'12'`, "illegal rune literal"},
@@ -822,7 +823,7 @@ func TestScanErrors(t *testing.T) {
// Verify that no comments show up as literal values when skipping comments.
func TestIssue10213(t *testing.T) {
- var src = `
+ const src = `
var (
A = 1 // foo
)
@@ -855,6 +856,23 @@ func TestIssue10213(t *testing.T) {
}
}
+func TestIssue28112(t *testing.T) {
+ const src = "... .. 0.. .." // make sure to have stand-alone ".." immediately before EOF to test EOF behavior
+ tokens := []token.Token{token.ELLIPSIS, token.PERIOD, token.PERIOD, token.FLOAT, token.PERIOD, token.PERIOD, token.PERIOD, token.EOF}
+ var s Scanner
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0)
+ for _, want := range tokens {
+ pos, got, lit := s.Scan()
+ if got != want {
+ t.Errorf("%s: got %s, want %s", fset.Position(pos), got, want)
+ }
+ // literals expect to have a (non-empty) literal string and we don't care about other tokens for this test
+ if tokenclass(got) == literal && lit == "" {
+ t.Errorf("%s: for %s got empty literal string", fset.Position(pos), got)
+ }
+ }
+}
+
func BenchmarkScan(b *testing.B) {
b.StopTimer()
fset := token.NewFileSet()
From 28fbbf41119a75498cc5e81d06af5ca1ad0010c9 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Wed, 10 Oct 2018 16:47:47 -0700
Subject: [PATCH 099/240] cmd/compile/internal/gc: remove OCMPIFACE and OCMPSTR
Interface and string comparisons don't need separate Ops any more than
struct or array comparisons do.
Removing them requires shuffling some code around in walk (and a
little in order), but overall allows simplifying things a bit.
Passes toolstash-check.
Change-Id: I084b8a6c089b768dc76d220379f4daed8a35db15
Reviewed-on: https://go-review.googlesource.com/c/141637
Run-TryBot: Matthew Dempsky
Reviewed-by: Brad Fitzpatrick
Reviewed-by: Robert Griesemer
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/gc/const.go | 4 +-
src/cmd/compile/internal/gc/fmt.go | 7 -
src/cmd/compile/internal/gc/iexport.go | 6 -
src/cmd/compile/internal/gc/iimport.go | 3 -
src/cmd/compile/internal/gc/order.go | 31 +-
src/cmd/compile/internal/gc/syntax.go | 8 +-
src/cmd/compile/internal/gc/typecheck.go | 47 +--
src/cmd/compile/internal/gc/walk.go | 395 ++++++++++++-----------
8 files changed, 235 insertions(+), 266 deletions(-)
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index e60e05df04..3c542aafae 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -1058,9 +1058,7 @@ func idealkind(n *Node) Ctype {
OLT,
ONE,
ONOT,
- OOROR,
- OCMPSTR,
- OCMPIFACE:
+ OOROR:
return CTBOOL
// shifts (beware!).
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 28e9b9b6dc..23ed3f7844 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1146,8 +1146,6 @@ var opprec = []int{
OGE: 4,
OGT: 4,
ONE: 4,
- OCMPSTR: 4,
- OCMPIFACE: 4,
OSEND: 3,
OANDAND: 2,
OOROR: 1,
@@ -1507,11 +1505,6 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
n1.exprfmt(s, nprec, mode)
}
- case OCMPSTR, OCMPIFACE:
- n.Left.exprfmt(s, nprec, mode)
- mode.Fprintf(s, " %#v ", n.SubOp())
- n.Right.exprfmt(s, nprec+1, mode)
-
default:
mode.Fprintf(s, "", n.Op)
}
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index d90c97ad92..b141e5fc09 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -1319,12 +1319,6 @@ func (w *exportWriter) expr(n *Node) {
w.pos(n.Pos)
w.exprList(n.List)
- case OCMPSTR, OCMPIFACE:
- w.op(n.SubOp())
- w.pos(n.Pos)
- w.expr(n.Left)
- w.expr(n.Right)
-
case ODCLCONST:
// if exporting, DCLCONST should just be removed as its usage
// has already been replaced with literals
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 6f0fd6b6d2..4fea314263 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -935,9 +935,6 @@ func (r *importReader) node() *Node {
}
return x
- // case OCMPSTR, OCMPIFACE:
- // unreachable - mapped to std comparison operators by exporter
-
// --------------------------------------------------------------------
// statements
case ODCL:
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 1e22ecfcdf..8afb136515 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1010,20 +1010,6 @@ func (o *Order) expr(n, lhs *Node) *Node {
}
}
- case OCMPSTR:
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
-
- // Mark string(byteSlice) arguments to reuse byteSlice backing
- // buffer during conversion. String comparison does not
- // memorize the strings for later use, so it is safe.
- if n.Left.Op == OARRAYBYTESTR {
- n.Left.Op = OARRAYBYTESTRTMP
- }
- if n.Right.Op == OARRAYBYTESTR {
- n.Right.Op = OARRAYBYTESTRTMP
- }
-
// key must be addressable
case OINDEXMAP:
n.Left = o.expr(n.Left, nil)
@@ -1181,11 +1167,24 @@ func (o *Order) expr(n, lhs *Node) *Node {
n.Left = o.expr(n.Left, nil)
n = o.copyExpr(n, n.Type, true)
- case OEQ, ONE:
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
+
t := n.Left.Type
- if t.IsStruct() || t.IsArray() {
+ switch {
+ case t.IsString():
+ // Mark string(byteSlice) arguments to reuse byteSlice backing
+ // buffer during conversion. String comparison does not
+ // memorize the strings for later use, so it is safe.
+ if n.Left.Op == OARRAYBYTESTR {
+ n.Left.Op = OARRAYBYTESTRTMP
+ }
+ if n.Right.Op == OARRAYBYTESTR {
+ n.Right.Op = OARRAYBYTESTRTMP
+ }
+
+ case t.IsStruct() || t.IsArray():
// for complex comparisons, we need both args to be
// addressable so we can pass them to the runtime.
n.Left = o.addrTemp(n.Left)
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index ab65ddebb4..1368d5edb8 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -65,7 +65,7 @@ func (n *Node) ResetAux() {
func (n *Node) SubOp() Op {
switch n.Op {
- case OASOP, OCMPIFACE, OCMPSTR, ONAME:
+ case OASOP, ONAME:
default:
Fatalf("unexpected op: %v", n.Op)
}
@@ -74,7 +74,7 @@ func (n *Node) SubOp() Op {
func (n *Node) SetSubOp(op Op) {
switch n.Op {
- case OASOP, OCMPIFACE, OCMPSTR, ONAME:
+ case OASOP, ONAME:
default:
Fatalf("unexpected op: %v", n.Op)
}
@@ -610,8 +610,8 @@ const (
OCAP // cap(Left)
OCLOSE // close(Left)
OCLOSURE // func Type { Body } (func literal)
- OCMPIFACE // Left Etype Right (interface comparison, x == y or x != y)
- OCMPSTR // Left Etype Right (string comparison, x == y, x < y, etc)
+ _ // toolstash kludge; was OCMPIFACE
+ _ // toolstash kludge; was OCMPSTR
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
OMAPLIT // Type{List} (composite literal, Type is map)
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 897dd710b9..cfdd88d45e 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -747,43 +747,22 @@ func typecheck1(n *Node, top int) *Node {
}
}
- if et == TSTRING {
- if iscmp[n.Op] {
- ot := n.Op
- n.Op = OCMPSTR
- n.SetSubOp(ot)
- } else if n.Op == OADD {
- // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
- n.Op = OADDSTR
+ if et == TSTRING && n.Op == OADD {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ n.Op = OADDSTR
- if l.Op == OADDSTR {
- n.List.Set(l.List.Slice())
- } else {
- n.List.Set1(l)
- }
- if r.Op == OADDSTR {
- n.List.AppendNodes(&r.List)
- } else {
- n.List.Append(r)
- }
- n.Left = nil
- n.Right = nil
+ if l.Op == OADDSTR {
+ n.List.Set(l.List.Slice())
+ } else {
+ n.List.Set1(l)
}
- }
-
- if et == TINTER {
- if l.Op == OLITERAL && l.Val().Ctype() == CTNIL {
- // swap for back end
- n.Left = r
-
- n.Right = l
- } else if r.Op == OLITERAL && r.Val().Ctype() == CTNIL {
- } else // leave alone for back end
- if r.Type.IsInterface() == l.Type.IsInterface() {
- ot := n.Op
- n.Op = OCMPIFACE
- n.SetSubOp(ot)
+ if r.Op == OADDSTR {
+ n.List.AppendNodes(&r.List)
+ } else {
+ n.List.Append(r)
}
+ n.Left = nil
+ n.Right = nil
}
if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index c3201c1404..6b9ec51203 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -514,7 +514,7 @@ opswitch:
OIND, OSPTR, OITAB, OIDATA, OADDR:
n.Left = walkexpr(n.Left, init)
- case OEFACE, OAND, OSUB, OMUL, OLT, OLE, OGE, OGT, OADD, OOR, OXOR:
+ case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
@@ -584,19 +584,8 @@ opswitch:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
- case OEQ, ONE:
- n.Left = walkexpr(n.Left, init)
- n.Right = walkexpr(n.Right, init)
-
- // Disable safemode while compiling this code: the code we
- // generate internally can refer to unsafe.Pointer.
- // In this case it can happen if we need to generate an ==
- // for a struct containing a reflect.Value, which itself has
- // an unexported field of type unsafe.Pointer.
- old_safemode := safemode
- safemode = false
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
n = walkcompare(n, init)
- safemode = old_safemode
case OANDAND, OOROR:
n.Left = walkexpr(n.Left, init)
@@ -1218,149 +1207,6 @@ opswitch:
n = callnew(n.Type.Elem())
}
- case OCMPSTR:
- // s + "badgerbadgerbadger" == "badgerbadgerbadger"
- if (n.SubOp() == OEQ || n.SubOp() == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
- r := nod(n.SubOp(), nod(OLEN, n.Left.List.First(), nil), nodintconst(0))
- n = finishcompare(n, r, init)
- break
- }
-
- // Rewrite comparisons to short constant strings as length+byte-wise comparisons.
- var cs, ncs *Node // const string, non-const string
- switch {
- case Isconst(n.Left, CTSTR) && Isconst(n.Right, CTSTR):
- // ignore; will be constant evaluated
- case Isconst(n.Left, CTSTR):
- cs = n.Left
- ncs = n.Right
- case Isconst(n.Right, CTSTR):
- cs = n.Right
- ncs = n.Left
- }
- if cs != nil {
- cmp := n.SubOp()
- // Our comparison below assumes that the non-constant string
- // is on the left hand side, so rewrite "" cmp x to x cmp "".
- // See issue 24817.
- if Isconst(n.Left, CTSTR) {
- cmp = brrev(cmp)
- }
-
- // maxRewriteLen was chosen empirically.
- // It is the value that minimizes cmd/go file size
- // across most architectures.
- // See the commit description for CL 26758 for details.
- maxRewriteLen := 6
- // Some architectures can load unaligned byte sequence as 1 word.
- // So we can cover longer strings with the same amount of code.
- canCombineLoads := canMergeLoads()
- combine64bit := false
- if canCombineLoads {
- // Keep this low enough to generate less code than a function call.
- maxRewriteLen = 2 * thearch.LinkArch.RegSize
- combine64bit = thearch.LinkArch.RegSize >= 8
- }
-
- var and Op
- switch cmp {
- case OEQ:
- and = OANDAND
- case ONE:
- and = OOROR
- default:
- // Don't do byte-wise comparisons for <, <=, etc.
- // They're fairly complicated.
- // Length-only checks are ok, though.
- maxRewriteLen = 0
- }
- if s := cs.Val().U.(string); len(s) <= maxRewriteLen {
- if len(s) > 0 {
- ncs = safeexpr(ncs, init)
- }
- r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s))))
- remains := len(s)
- for i := 0; remains > 0; {
- if remains == 1 || !canCombineLoads {
- cb := nodintconst(int64(s[i]))
- ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
- r = nod(and, r, nod(cmp, ncb, cb))
- remains--
- i++
- continue
- }
- var step int
- var convType *types.Type
- switch {
- case remains >= 8 && combine64bit:
- convType = types.Types[TINT64]
- step = 8
- case remains >= 4:
- convType = types.Types[TUINT32]
- step = 4
- case remains >= 2:
- convType = types.Types[TUINT16]
- step = 2
- }
- ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i)))
- ncsubstr = conv(ncsubstr, convType)
- csubstr := int64(s[i])
- // Calculate large constant from bytes as sequence of shifts and ors.
- // Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
- // ssa will combine this into a single large load.
- for offset := 1; offset < step; offset++ {
- b := nod(OINDEX, ncs, nodintconst(int64(i+offset)))
- b = conv(b, convType)
- b = nod(OLSH, b, nodintconst(int64(8*offset)))
- ncsubstr = nod(OOR, ncsubstr, b)
- csubstr |= int64(s[i+offset]) << uint8(8*offset)
- }
- csubstrPart := nodintconst(csubstr)
- // Compare "step" bytes as once
- r = nod(and, r, nod(cmp, csubstrPart, ncsubstr))
- remains -= step
- i += step
- }
- n = finishcompare(n, r, init)
- break
- }
- }
-
- var r *Node
- if n.SubOp() == OEQ || n.SubOp() == ONE {
- // prepare for rewrite below
- n.Left = cheapexpr(n.Left, init)
- n.Right = cheapexpr(n.Right, init)
-
- lstr := conv(n.Left, types.Types[TSTRING])
- rstr := conv(n.Right, types.Types[TSTRING])
- lptr := nod(OSPTR, lstr, nil)
- rptr := nod(OSPTR, rstr, nil)
- llen := conv(nod(OLEN, lstr, nil), types.Types[TUINTPTR])
- rlen := conv(nod(OLEN, rstr, nil), types.Types[TUINTPTR])
-
- fn := syslook("memequal")
- fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8])
- r = mkcall1(fn, types.Types[TBOOL], init, lptr, rptr, llen)
-
- // quick check of len before full compare for == or !=.
- // memequal then tests equality up to length len.
- if n.SubOp() == OEQ {
- // len(left) == len(right) && memequal(left, right, len)
- r = nod(OANDAND, nod(OEQ, llen, rlen), r)
- } else {
- // len(left) != len(right) || !memequal(left, right, len)
- r = nod(ONOT, r, nil)
- r = nod(OOROR, nod(ONE, llen, rlen), r)
- }
- } else {
- // sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
- r = nod(n.SubOp(), r, nodintconst(0))
- }
-
- n = finishcompare(n, r, init)
-
case OADDSTR:
n = addstr(n, init)
@@ -1658,40 +1504,6 @@ opswitch:
n = mkcall("stringtoslicerune", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
- // ifaceeq(i1 any-1, i2 any-2) (ret bool);
- case OCMPIFACE:
- if !eqtype(n.Left.Type, n.Right.Type) {
- Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
- }
- var fn *Node
- if n.Left.Type.IsEmptyInterface() {
- fn = syslook("efaceeq")
- } else {
- fn = syslook("ifaceeq")
- }
-
- n.Right = cheapexpr(n.Right, init)
- n.Left = cheapexpr(n.Left, init)
- lt := nod(OITAB, n.Left, nil)
- rt := nod(OITAB, n.Right, nil)
- ld := nod(OIDATA, n.Left, nil)
- rd := nod(OIDATA, n.Right, nil)
- ld.Type = types.Types[TUNSAFEPTR]
- rd.Type = types.Types[TUNSAFEPTR]
- ld.SetTypecheck(1)
- rd.SetTypecheck(1)
- call := mkcall1(fn, n.Type, init, lt, ld, rd)
-
- // Check itable/type before full compare.
- // Note: short-circuited because order matters.
- var cmp *Node
- if n.SubOp() == OEQ {
- cmp = nod(OANDAND, nod(OEQ, lt, rt), call)
- } else {
- cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil))
- }
- n = finishcompare(n, cmp, init)
-
case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
if isStaticCompositeLiteral(n) && !canSSAType(n.Type) {
// n can be directly represented in the read-only data section.
@@ -3390,7 +3202,7 @@ func eqfor(t *types.Type) (n *Node, needsize bool) {
// Should only arrive here with large memory or
// a struct/array containing a non-memory field/element.
// Small memory is handled inline, and single non-memory
- // is handled during type check (OCMPSTR etc).
+ // is handled by walkcompare.
switch a, _ := algtype1(t); a {
case AMEM:
n := syslook("memequal")
@@ -3415,6 +3227,28 @@ func eqfor(t *types.Type) (n *Node, needsize bool) {
// The result of walkcompare MUST be assigned back to n, e.g.
// n.Left = walkcompare(n.Left, init)
func walkcompare(n *Node, init *Nodes) *Node {
+ if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != OLITERAL && n.Right.Op != OLITERAL {
+ return walkcompareInterface(n, init)
+ }
+
+ if n.Left.Type.IsString() && n.Right.Type.IsString() {
+ return walkcompareString(n, init)
+ }
+
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+
+ // Disable safemode while compiling this code: the code we
+ // generate internally can refer to unsafe.Pointer.
+ // In this case it can happen if we need to generate an ==
+ // for a struct containing a reflect.Value, which itself has
+ // an unexported field of type unsafe.Pointer.
+ old_safemode := safemode
+ safemode = false
+ defer func() {
+ safemode = old_safemode
+ }()
+
// Given interface value l and concrete value r, rewrite
// l == r
// into types-equal && data-equal.
@@ -3627,6 +3461,183 @@ func walkcompare(n *Node, init *Nodes) *Node {
return n
}
+func walkcompareInterface(n *Node, init *Nodes) *Node {
+ // ifaceeq(i1 any-1, i2 any-2) (ret bool);
+ if !eqtype(n.Left.Type, n.Right.Type) {
+ Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
+ }
+ var fn *Node
+ if n.Left.Type.IsEmptyInterface() {
+ fn = syslook("efaceeq")
+ } else {
+ fn = syslook("ifaceeq")
+ }
+
+ n.Right = cheapexpr(n.Right, init)
+ n.Left = cheapexpr(n.Left, init)
+ lt := nod(OITAB, n.Left, nil)
+ rt := nod(OITAB, n.Right, nil)
+ ld := nod(OIDATA, n.Left, nil)
+ rd := nod(OIDATA, n.Right, nil)
+ ld.Type = types.Types[TUNSAFEPTR]
+ rd.Type = types.Types[TUNSAFEPTR]
+ ld.SetTypecheck(1)
+ rd.SetTypecheck(1)
+ call := mkcall1(fn, n.Type, init, lt, ld, rd)
+
+ // Check itable/type before full compare.
+ // Note: short-circuited because order matters.
+ var cmp *Node
+ if n.Op == OEQ {
+ cmp = nod(OANDAND, nod(OEQ, lt, rt), call)
+ } else {
+ cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil))
+ }
+ return finishcompare(n, cmp, init)
+}
+
+func walkcompareString(n *Node, init *Nodes) *Node {
+ // s + "badgerbadgerbadger" == "badgerbadgerbadger"
+ if (n.Op == OEQ || n.Op == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
+ r := nod(n.Op, nod(OLEN, n.Left.List.First(), nil), nodintconst(0))
+ return finishcompare(n, r, init)
+ }
+
+ // Rewrite comparisons to short constant strings as length+byte-wise comparisons.
+ var cs, ncs *Node // const string, non-const string
+ switch {
+ case Isconst(n.Left, CTSTR) && Isconst(n.Right, CTSTR):
+ // ignore; will be constant evaluated
+ case Isconst(n.Left, CTSTR):
+ cs = n.Left
+ ncs = n.Right
+ case Isconst(n.Right, CTSTR):
+ cs = n.Right
+ ncs = n.Left
+ }
+ if cs != nil {
+ cmp := n.Op
+ // Our comparison below assumes that the non-constant string
+ // is on the left hand side, so rewrite "" cmp x to x cmp "".
+ // See issue 24817.
+ if Isconst(n.Left, CTSTR) {
+ cmp = brrev(cmp)
+ }
+
+ // maxRewriteLen was chosen empirically.
+ // It is the value that minimizes cmd/go file size
+ // across most architectures.
+ // See the commit description for CL 26758 for details.
+ maxRewriteLen := 6
+ // Some architectures can load unaligned byte sequence as 1 word.
+ // So we can cover longer strings with the same amount of code.
+ canCombineLoads := canMergeLoads()
+ combine64bit := false
+ if canCombineLoads {
+ // Keep this low enough to generate less code than a function call.
+ maxRewriteLen = 2 * thearch.LinkArch.RegSize
+ combine64bit = thearch.LinkArch.RegSize >= 8
+ }
+
+ var and Op
+ switch cmp {
+ case OEQ:
+ and = OANDAND
+ case ONE:
+ and = OOROR
+ default:
+ // Don't do byte-wise comparisons for <, <=, etc.
+ // They're fairly complicated.
+ // Length-only checks are ok, though.
+ maxRewriteLen = 0
+ }
+ if s := cs.Val().U.(string); len(s) <= maxRewriteLen {
+ if len(s) > 0 {
+ ncs = safeexpr(ncs, init)
+ }
+ r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s))))
+ remains := len(s)
+ for i := 0; remains > 0; {
+ if remains == 1 || !canCombineLoads {
+ cb := nodintconst(int64(s[i]))
+ ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
+ r = nod(and, r, nod(cmp, ncb, cb))
+ remains--
+ i++
+ continue
+ }
+ var step int
+ var convType *types.Type
+ switch {
+ case remains >= 8 && combine64bit:
+ convType = types.Types[TINT64]
+ step = 8
+ case remains >= 4:
+ convType = types.Types[TUINT32]
+ step = 4
+ case remains >= 2:
+ convType = types.Types[TUINT16]
+ step = 2
+ }
+ ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i)))
+ ncsubstr = conv(ncsubstr, convType)
+ csubstr := int64(s[i])
+ // Calculate large constant from bytes as sequence of shifts and ors.
+ // Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
+ // ssa will combine this into a single large load.
+ for offset := 1; offset < step; offset++ {
+ b := nod(OINDEX, ncs, nodintconst(int64(i+offset)))
+ b = conv(b, convType)
+ b = nod(OLSH, b, nodintconst(int64(8*offset)))
+ ncsubstr = nod(OOR, ncsubstr, b)
+ csubstr |= int64(s[i+offset]) << uint8(8*offset)
+ }
+ csubstrPart := nodintconst(csubstr)
+ // Compare "step" bytes as once
+ r = nod(and, r, nod(cmp, csubstrPart, ncsubstr))
+ remains -= step
+ i += step
+ }
+ return finishcompare(n, r, init)
+ }
+ }
+
+ var r *Node
+ if n.Op == OEQ || n.Op == ONE {
+ // prepare for rewrite below
+ n.Left = cheapexpr(n.Left, init)
+ n.Right = cheapexpr(n.Right, init)
+
+ lstr := conv(n.Left, types.Types[TSTRING])
+ rstr := conv(n.Right, types.Types[TSTRING])
+ lptr := nod(OSPTR, lstr, nil)
+ rptr := nod(OSPTR, rstr, nil)
+ llen := conv(nod(OLEN, lstr, nil), types.Types[TUINTPTR])
+ rlen := conv(nod(OLEN, rstr, nil), types.Types[TUINTPTR])
+
+ fn := syslook("memequal")
+ fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8])
+ r = mkcall1(fn, types.Types[TBOOL], init, lptr, rptr, llen)
+
+ // quick check of len before full compare for == or !=.
+ // memequal then tests equality up to length len.
+ if n.Op == OEQ {
+ // len(left) == len(right) && memequal(left, right, len)
+ r = nod(OANDAND, nod(OEQ, llen, rlen), r)
+ } else {
+ // len(left) != len(right) || !memequal(left, right, len)
+ r = nod(ONOT, r, nil)
+ r = nod(OOROR, nod(ONE, llen, rlen), r)
+ }
+ } else {
+ // sys_cmpstring(s1, s2) :: 0
+ r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
+ r = nod(n.Op, r, nodintconst(0))
+ }
+
+ return finishcompare(n, r, init)
+}
+
// The result of finishcompare MUST be assigned back to n, e.g.
// n.Left = finishcompare(n.Left, x, r, init)
func finishcompare(n, r *Node, init *Nodes) *Node {
@@ -3961,8 +3972,6 @@ func candiscard(n *Node) bool {
OSTRARRAYBYTE,
OSTRARRAYRUNE,
OCAP,
- OCMPIFACE,
- OCMPSTR,
OCOMPLIT,
OMAPLIT,
OSTRUCTLIT,
From a0d6420d8be2ae7164797051ec74fa2a2df466a1 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Thu, 11 Oct 2018 13:00:11 -0700
Subject: [PATCH 100/240] cmd/compile/internal/gc: remove OCMPIFACE/OCMPSTR
placeholders
Change-Id: If05f6146a1fd97f61fc71629c5c29df43220d0c8
Reviewed-on: https://go-review.googlesource.com/c/141638
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/internal/gc/op_string.go | 4 ++--
src/cmd/compile/internal/gc/syntax.go | 2 --
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go
index 90b95d769f..8358854bf2 100644
--- a/src/cmd/compile/internal/gc/op_string.go
+++ b/src/cmd/compile/internal/gc/op_string.go
@@ -4,9 +4,9 @@ package gc
import "strconv"
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECMPIFACECMPSTRCOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 239, 245, 252, 258, 267, 275, 283, 289, 293, 302, 309, 313, 316, 323, 331, 339, 346, 352, 355, 361, 368, 376, 380, 387, 395, 397, 399, 401, 403, 405, 407, 410, 415, 423, 426, 435, 438, 442, 450, 457, 466, 469, 472, 475, 478, 481, 484, 490, 493, 496, 499, 503, 508, 512, 517, 522, 528, 533, 537, 542, 550, 558, 564, 573, 580, 584, 591, 598, 606, 610, 614, 618, 625, 632, 640, 646, 651, 656, 660, 665, 673, 678, 683, 687, 690, 698, 702, 704, 709, 713, 718, 724, 730, 736, 742, 747, 751, 758, 764, 769, 775, 778, 784, 791, 796, 800, 805, 809, 819, 824, 832, 838, 845, 852, 860, 866, 870, 873}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 550, 559, 566, 570, 577, 584, 592, 596, 600, 604, 611, 618, 626, 632, 637, 642, 646, 651, 659, 664, 669, 673, 676, 684, 688, 690, 695, 699, 704, 710, 716, 722, 728, 733, 737, 744, 750, 755, 761, 764, 770, 777, 782, 786, 791, 795, 805, 810, 818, 824, 831, 838, 846, 852, 856, 859}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 1368d5edb8..3ae3976d96 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -610,8 +610,6 @@ const (
OCAP // cap(Left)
OCLOSE // close(Left)
OCLOSURE // func Type { Body } (func literal)
- _ // toolstash kludge; was OCMPIFACE
- _ // toolstash kludge; was OCMPSTR
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
OMAPLIT // Type{List} (composite literal, Type is map)
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
From 93cf82f08af78869a721d4e48fc4fd1ce08cd259 Mon Sep 17 00:00:00 2001
From: Elias Naur
Date: Fri, 12 Oct 2018 11:36:54 +0200
Subject: [PATCH 101/240] os: make UserHomeDir return "/" on iOS
The UserHomeDir test succeeds on the builder, but not when run
manually where HOME is set to the host $HOME.
Change-Id: I1db0f608b04b311b53cc0c8160a3778caaf542f6
Reviewed-on: https://go-review.googlesource.com/c/141798
Run-TryBot: Elias Naur
Reviewed-by: Brad Fitzpatrick
---
src/os/file.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/os/file.go b/src/os/file.go
index 61f37f2489..3e626a023a 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -394,6 +394,11 @@ func UserHomeDir() string {
return Getenv("home")
case "nacl", "android":
return "/"
+ case "darwin":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ return "/"
+ }
+ fallthrough
default:
return Getenv("HOME")
}
From 1f95e0a9d99c8307b24e8bf542ae0e093ee95838 Mon Sep 17 00:00:00 2001
From: Mihai Todor
Date: Fri, 12 Oct 2018 14:35:16 +0000
Subject: [PATCH 102/240] encoding/base64: fix typo in decodeQuantum docs
Change-Id: I643540bcea574d8a70b79237d97097dcc7368766
GitHub-Last-Rev: e2be58d1ab84f91dfbba1067aae7145f24fd650d
GitHub-Pull-Request: golang/go#28125
Reviewed-on: https://go-review.googlesource.com/c/141119
Reviewed-by: Brad Fitzpatrick
---
src/encoding/base64/base64.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index e8afc48859..0bb37b311a 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -270,7 +270,7 @@ func (e CorruptInputError) Error() string {
return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}
-// decodeQuantum decodes up to 4 base64 bytes. It takes for parameters
+// decodeQuantum decodes up to 4 base64 bytes. The received parameters are
// the destination buffer dst, the source buffer src and an index in the
// source buffer si.
// It returns the number of bytes read from src, the number of bytes written
From e19f5754640b0dd6a315edffcaef23c3cf2cefe6 Mon Sep 17 00:00:00 2001
From: Yuval Pavel Zholkover
Date: Wed, 10 Oct 2018 23:32:36 +0300
Subject: [PATCH 103/240] syscall: correctly pad with NUL in FreeBSD
convertFromDirents11
We weren't writing a terminating NUL after dstDirent.Namlen bytes of dstDirent.Name.
And we weren't filling the possible additional bytes until dstDirent.Reclen.
Fixes #28131
Change-Id: Id691c25225795c0dbb0d7004bfca7bb7fc706de9
Reviewed-on: https://go-review.googlesource.com/c/141297
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/syscall/dirent_bsd_test.go | 76 ++++++++++++++++++++++++++++++++++
src/syscall/syscall_freebsd.go | 36 ++++++++--------
2 files changed, 93 insertions(+), 19 deletions(-)
create mode 100644 src/syscall/dirent_bsd_test.go
diff --git a/src/syscall/dirent_bsd_test.go b/src/syscall/dirent_bsd_test.go
new file mode 100644
index 0000000000..e5b8357af7
--- /dev/null
+++ b/src/syscall/dirent_bsd_test.go
@@ -0,0 +1,76 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package syscall_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+func TestDirent(t *testing.T) {
+ const (
+ direntBufSize = 2048
+ filenameMinSize = 11
+ )
+
+ d, err := ioutil.TempDir("", "dirent-test")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+ defer os.RemoveAll(d)
+ t.Logf("tmpdir: %s", d)
+
+ for i, c := range []byte("0123456789") {
+ name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
+ err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
+ if err != nil {
+ t.Fatalf("writefile: %v", err)
+ }
+ }
+
+ buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
+ fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
+ defer syscall.Close(fd)
+ if err != nil {
+ t.Fatalf("syscall.open: %v", err)
+ }
+ n, err := syscall.ReadDirent(fd, buf)
+ if err != nil {
+ t.Fatalf("syscall.readdir: %v", err)
+ }
+ buf = buf[:n]
+
+ names := make([]string, 0, 10)
+ for len(buf) > 0 {
+ var bc int
+ bc, _, names = syscall.ParseDirent(buf, -1, names)
+ buf = buf[bc:]
+ }
+
+ sort.Strings(names)
+ t.Logf("names: %q", names)
+
+ if len(names) != 10 {
+ t.Errorf("got %d names; expected 10", len(names))
+ }
+ for i, name := range names {
+ ord, err := strconv.Atoi(name[:1])
+ if err != nil {
+ t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
+ }
+ if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
+ t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
+ }
+ }
+}
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index e118120048..9ae024131d 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -344,18 +344,17 @@ func (s *Statfs_t) convertFrom(old *statfs_freebsd11_t) {
copy(s.Mntonname[:], old.Mntonname[:n])
}
-func convertFromDirents11(oldBuf []byte, buf []byte) int {
- src := unsafe.Pointer(&oldBuf[0])
- esrc := unsafe.Pointer(uintptr(src) + uintptr(len(oldBuf)))
- dst := unsafe.Pointer(&buf[0])
- edst := unsafe.Pointer(uintptr(dst) + uintptr(len(buf)))
+func convertFromDirents11(old []byte, buf []byte) int {
+ oldFixedSize := int(unsafe.Offsetof((*dirent_freebsd11)(nil).Name))
+ fixedSize := int(unsafe.Offsetof((*Dirent)(nil).Name))
+ srcPos := 0
+ dstPos := 0
+ for dstPos+fixedSize < len(buf) && srcPos+oldFixedSize < len(old) {
+ srcDirent := (*dirent_freebsd11)(unsafe.Pointer(&old[srcPos]))
+ dstDirent := (*Dirent)(unsafe.Pointer(&buf[dstPos]))
- for uintptr(src) < uintptr(esrc) && uintptr(dst) < uintptr(edst) {
- srcDirent := (*dirent_freebsd11)(src)
- dstDirent := (*Dirent)(dst)
-
- reclen := roundup(int(unsafe.Offsetof(dstDirent.Name)+uintptr(srcDirent.Namlen)+1), 8)
- if uintptr(dst)+uintptr(reclen) >= uintptr(edst) {
+ reclen := roundup(fixedSize+int(srcDirent.Namlen)+1, 8)
+ if dstPos+reclen >= len(buf) {
break
}
@@ -367,18 +366,17 @@ func convertFromDirents11(oldBuf []byte, buf []byte) int {
dstDirent.Namlen = uint16(srcDirent.Namlen)
dstDirent.Pad1 = 0
- sl := srcDirent.Name[:]
- n := clen(*(*[]byte)(unsafe.Pointer(&sl)))
- copy(dstDirent.Name[:], srcDirent.Name[:n])
- for i := n; i < int(dstDirent.Namlen); i++ {
- dstDirent.Name[i] = 0
+ copy(dstDirent.Name[:], srcDirent.Name[:srcDirent.Namlen])
+ padding := buf[dstPos+fixedSize+int(dstDirent.Namlen) : dstPos+reclen]
+ for i := range padding {
+ padding[i] = 0
}
- src = unsafe.Pointer(uintptr(src) + uintptr(srcDirent.Reclen))
- dst = unsafe.Pointer(uintptr(dst) + uintptr(reclen))
+ dstPos += int(dstDirent.Reclen)
+ srcPos += int(srcDirent.Reclen)
}
- return int(uintptr(dst) - uintptr(unsafe.Pointer((&buf[0]))))
+ return dstPos
}
/*
From da6c168378b4c1deb2a731356f1f438e4723b8a7 Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick
Date: Tue, 10 Jul 2018 21:39:50 +0000
Subject: [PATCH 104/240] net/http: flesh out Transport's HTTP/1 CONNECT+bidi
support to match HTTP/2
Fixes #17227
Change-Id: I0f8964593d69623b85d5759f6276063ee62b2915
Reviewed-on: https://go-review.googlesource.com/c/123156
Reviewed-by: Brad Fitzpatrick
---
src/net/http/request.go | 3 ++
src/net/http/requestwrite_test.go | 32 +++++++++++++++
src/net/http/transfer.go | 24 +++++++++++-
src/net/http/transport.go | 9 -----
src/net/http/transport_test.go | 65 +++++++++++++++++++++++++++++++
5 files changed, 123 insertions(+), 10 deletions(-)
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 967de7917f..3669f17f66 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -545,6 +545,9 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
} else if r.Method == "CONNECT" && r.URL.Path == "" {
// CONNECT requests normally give just the host and port, not a full URL.
ruri = host
+ if r.URL.Opaque != "" {
+ ruri = r.URL.Opaque
+ }
}
// TODO(bradfitz): escape at least newlines in ruri?
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index eb65b9f736..246fb4e65d 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -512,6 +512,38 @@ var reqWriteTests = []reqWriteTest{
"User-Agent: Go-http-client/1.1\r\n" +
"\r\n",
},
+
+ // CONNECT without Opaque
+ 21: {
+ Req: Request{
+ Method: "CONNECT",
+ URL: &url.URL{
+ Scheme: "https", // of proxy.com
+ Host: "proxy.com",
+ },
+ },
+ // What we used to do, locking that behavior in:
+ WantWrite: "CONNECT proxy.com HTTP/1.1\r\n" +
+ "Host: proxy.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "\r\n",
+ },
+
+ // CONNECT with Opaque
+ 22: {
+ Req: Request{
+ Method: "CONNECT",
+ URL: &url.URL{
+ Scheme: "https", // of proxy.com
+ Host: "proxy.com",
+ Opaque: "backend:443",
+ },
+ },
+ WantWrite: "CONNECT backend:443 HTTP/1.1\r\n" +
+ "Host: proxy.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "\r\n",
+ },
}
func TestRequestWrite(t *testing.T) {
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index a41d034204..f0b43844dd 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -184,6 +184,9 @@ func (t *transferWriter) shouldSendChunkedRequestBody() bool {
if t.ContentLength >= 0 || t.Body == nil { // redundant checks; caller did them
return false
}
+ if t.Method == "CONNECT" {
+ return false
+ }
if requestMethodUsuallyLacksBody(t.Method) {
// Only probe the Request.Body for GET/HEAD/DELETE/etc
// requests, because it's only those types of requests
@@ -357,7 +360,11 @@ func (t *transferWriter) writeBody(w io.Writer) error {
err = cw.Close()
}
} else if t.ContentLength == -1 {
- ncopy, err = io.Copy(w, body)
+ dst := w
+ if t.Method == "CONNECT" {
+ dst = bufioFlushWriter{dst}
+ }
+ ncopy, err = io.Copy(dst, body)
} else {
ncopy, err = io.Copy(w, io.LimitReader(body, t.ContentLength))
if err != nil {
@@ -1050,3 +1057,18 @@ func isKnownInMemoryReader(r io.Reader) bool {
}
return false
}
+
+// bufioFlushWriter is an io.Writer wrapper that flushes all writes
+// on its wrapped writer if it's a *bufio.Writer.
+type bufioFlushWriter struct{ w io.Writer }
+
+func (fw bufioFlushWriter) Write(p []byte) (n int, err error) {
+ n, err = fw.w.Write(p)
+ if bw, ok := fw.w.(*bufio.Writer); n > 0 && ok {
+ ferr := bw.Flush()
+ if ferr != nil && err == nil {
+ err = ferr
+ }
+ }
+ return
+}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index b298ec6d7d..c459092cb8 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -85,15 +85,6 @@ func init() {
// To explicitly enable HTTP/2 on a transport, use golang.org/x/net/http2
// and call ConfigureTransport. See the package docs for more about HTTP/2.
//
-// The Transport will send CONNECT requests to a proxy for its own use
-// when processing HTTPS requests, but Transport should generally not
-// be used to send a CONNECT request. That is, the Request passed to
-// the RoundTrip method should not have a Method of "CONNECT", as Go's
-// HTTP/1.x implementation does not support full-duplex request bodies
-// being written while the response body is streamed. Go's HTTP/2
-// implementation does support full duplex, but many CONNECT proxies speak
-// HTTP/1.x.
-//
// Responses with status codes in the 1xx range are either handled
// automatically (100 expect-continue) or ignored. The one
// exception is HTTP status code 101 (Switching Protocols), which is
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 8c31238c11..211f8cb467 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -4887,3 +4887,68 @@ func TestTransportResponseBodyWritableOnProtocolSwitch(t *testing.T) {
t.Errorf("read %q; want %q", got, want)
}
}
+
+func TestTransportCONNECTBidi(t *testing.T) {
+ defer afterTest(t)
+ const target = "backend:443"
+ cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method != "CONNECT" {
+ t.Errorf("unexpected method %q", r.Method)
+ w.WriteHeader(500)
+ return
+ }
+ if r.RequestURI != target {
+ t.Errorf("unexpected CONNECT target %q", r.RequestURI)
+ w.WriteHeader(500)
+ return
+ }
+ nc, brw, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer nc.Close()
+ nc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
+ // Switch to a little protocol that capitalize its input lines:
+ for {
+ line, err := brw.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ t.Error(err)
+ }
+ return
+ }
+ io.WriteString(brw, strings.ToUpper(line))
+ brw.Flush()
+ }
+ }))
+ defer cst.close()
+ pr, pw := io.Pipe()
+ defer pw.Close()
+ req, err := NewRequest("CONNECT", cst.ts.URL, pr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.URL.Opaque = target
+ res, err := cst.c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ t.Fatalf("status code = %d; want 200", res.StatusCode)
+ }
+ br := bufio.NewReader(res.Body)
+ for _, str := range []string{"foo", "bar", "baz"} {
+ fmt.Fprintf(pw, "%s\n", str)
+ got, err := br.ReadString('\n')
+ if err != nil {
+ t.Fatal(err)
+ }
+ got = strings.TrimSpace(got)
+ want := strings.ToUpper(str)
+ if got != want {
+ t.Fatalf("got %q; want %q", got, want)
+ }
+ }
+}
From a5248acd91dcf0e90a68c1ff88ca389dc034557c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Fri, 12 Oct 2018 16:48:38 +0200
Subject: [PATCH 105/240] internal/cpu: enable support for GODEBUGCPU in
non-experimental builds
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Enabling GODEBUGCPU without the need to set GOEXPERIMENT=debugcpu enables
trybots and builders to run tests for GODEBUGCPU features in upcoming CLs
that will implement the new syntax and features for non-experimental
GODEBUGCPU support from proposal golang.org/issue/27218.
Updates #27218
Change-Id: Icc69e51e736711a86b02b46bd441ffc28423beba
Reviewed-on: https://go-review.googlesource.com/c/141817
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/cmd/internal/objabi/util.go | 2 --
src/internal/cpu/cpu.go | 6 ++----
src/internal/cpu/cpu_test.go | 8 ++++----
src/internal/cpu/cpu_x86_test.go | 2 +-
src/runtime/proc.go | 4 ++--
5 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go
index ffd1c04d39..d1017322f0 100644
--- a/src/cmd/internal/objabi/util.go
+++ b/src/cmd/internal/objabi/util.go
@@ -105,7 +105,6 @@ var (
Fieldtrack_enabled int
Preemptibleloops_enabled int
Clobberdead_enabled int
- DebugCPU_enabled int
)
// Toolchain experiments.
@@ -120,7 +119,6 @@ var exper = []struct {
{"framepointer", &framepointer_enabled},
{"preemptibleloops", &Preemptibleloops_enabled},
{"clobberdead", &Clobberdead_enabled},
- {"debugcpu", &DebugCPU_enabled},
}
var defaultExpstring = Expstring()
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
index bfb016c7f7..54b100b1d4 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -6,8 +6,7 @@
// used by the Go standard library.
package cpu
-// DebugOptions is set to true by the runtime if go was compiled with GOEXPERIMENT=debugcpu
-// and GOOS is Linux or Darwin.
+// DebugOptions is set to true by the runtime if the OS supports GODEBUGCPU.
// This should not be changed after it is initialized.
var DebugOptions bool
@@ -139,8 +138,7 @@ type s390x struct {
// Initialize examines the processor and sets the relevant variables above.
// This is called by the runtime package early in program initialization,
-// before normal init functions are run. env is set by runtime on Linux and Darwin
-// if go was compiled with GOEXPERIMENT=debugcpu.
+// before normal init functions are run. env is set by runtime if the OS supports GODEBUGCPU.
func Initialize(env string) {
doinit()
processOptions(env)
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
index d4115a1b87..04ab9eeecb 100644
--- a/src/internal/cpu/cpu_test.go
+++ b/src/internal/cpu/cpu_test.go
@@ -13,14 +13,14 @@ import (
"testing"
)
-func MustHaveDebugOptionsEnabled(t *testing.T) {
+func MustHaveDebugOptionsSupport(t *testing.T) {
if !DebugOptions {
- t.Skipf("skipping test: cpu feature options not enabled")
+ t.Skipf("skipping test: cpu feature options not supported by OS")
}
}
func runDebugOptionsTest(t *testing.T, test string, options string) {
- MustHaveDebugOptionsEnabled(t)
+ MustHaveDebugOptionsSupport(t)
testenv.MustHaveExec(t)
@@ -42,7 +42,7 @@ func TestDisableAllCapabilities(t *testing.T) {
}
func TestAllCapabilitiesDisabled(t *testing.T) {
- MustHaveDebugOptionsEnabled(t)
+ MustHaveDebugOptionsSupport(t)
if os.Getenv("GODEBUGCPU") != "all=0" {
t.Skipf("skipping test: GODEBUGCPU=all=0 not set")
diff --git a/src/internal/cpu/cpu_x86_test.go b/src/internal/cpu/cpu_x86_test.go
index d03306c907..c3ea7cb590 100644
--- a/src/internal/cpu/cpu_x86_test.go
+++ b/src/internal/cpu/cpu_x86_test.go
@@ -34,7 +34,7 @@ func TestDisableSSE2(t *testing.T) {
}
func TestSSE2DebugOption(t *testing.T) {
- MustHaveDebugOptionsEnabled(t)
+ MustHaveDebugOptionsSupport(t)
if os.Getenv("GODEBUGCPU") != "sse2=0" {
t.Skipf("skipping test: GODEBUGCPU=sse2=0 not set")
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index f536b82aab..86c14997b1 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -478,12 +478,12 @@ const (
)
// cpuinit extracts the environment variable GODEBUGCPU from the environment on
-// Linux and Darwin if the GOEXPERIMENT debugcpu was set and calls internal/cpu.Initialize.
+// Linux and Darwin and calls internal/cpu.Initialize.
func cpuinit() {
const prefix = "GODEBUGCPU="
var env string
- if haveexperiment("debugcpu") && (GOOS == "linux" || GOOS == "darwin") {
+ if GOOS == "linux" || GOOS == "darwin" {
cpu.DebugOptions = true
// Similar to goenv_unix but extracts the environment value for
From d82e51a11973714708ddc7f9f055ae8ea3d509f1 Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Fri, 12 Oct 2018 10:54:06 +0200
Subject: [PATCH 106/240] internal/poll: add FD.Fsync on aix
Follow-up for CL 138717. This fixes the build of the os package on
aix.
Change-Id: I879b9360e71837ab622ae3a7b6144782cf5a9ce7
Reviewed-on: https://go-review.googlesource.com/c/141797
Run-TryBot: Tobias Klauser
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/internal/poll/fd_fsync_posix.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/internal/poll/fd_fsync_posix.go b/src/internal/poll/fd_fsync_posix.go
index 943f59a9ab..30dde0720b 100644
--- a/src/internal/poll/fd_fsync_posix.go
+++ b/src/internal/poll/fd_fsync_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package poll
From 4fb8b1de3cf629c94910c5389220a07963bd44e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Fri, 12 Oct 2018 18:01:50 +0200
Subject: [PATCH 107/240] internal/cpu: use 'off' for disabling cpu
capabilities instead of '0'
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Updates #27218
Change-Id: I4ce20376fd601b5f958d79014af7eaf89e9de613
Reviewed-on: https://go-review.googlesource.com/c/141818
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/internal/cpu/cpu.go | 10 +++++-----
src/internal/cpu/cpu_test.go | 6 +++---
src/internal/cpu/cpu_x86_test.go | 6 +++---
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
index 54b100b1d4..fdda880af4 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -157,11 +157,11 @@ type option struct {
}
// processOptions disables CPU feature values based on the parsed env string.
-// The env string is expected to be of the form feature1=0,feature2=0...
+// The env string is expected to be of the form feature1=off,feature2=off...
// where feature names is one of the architecture specifc list stored in the
-// cpu packages options variable. If env contains all=0 then all capabilities
+// cpu packages options variable. If env contains all=off then all capabilities
// referenced through the options variable are disabled. Other feature
-// names and values other than 0 are silently ignored.
+// names and values other than 'off' are silently ignored.
func processOptions(env string) {
field:
for env != "" {
@@ -178,8 +178,8 @@ field:
}
key, value := field[:i], field[i+1:]
- // Only allow turning off CPU features by specifying '0'.
- if value == "0" {
+ // Only allow turning off CPU features by specifying 'off'.
+ if value == "off" {
if key == "all" {
for _, v := range options {
*v.Feature = false
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
index 04ab9eeecb..6e7375fa7c 100644
--- a/src/internal/cpu/cpu_test.go
+++ b/src/internal/cpu/cpu_test.go
@@ -38,14 +38,14 @@ func runDebugOptionsTest(t *testing.T, test string, options string) {
}
func TestDisableAllCapabilities(t *testing.T) {
- runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "all=0")
+ runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "all=off")
}
func TestAllCapabilitiesDisabled(t *testing.T) {
MustHaveDebugOptionsSupport(t)
- if os.Getenv("GODEBUGCPU") != "all=0" {
- t.Skipf("skipping test: GODEBUGCPU=all=0 not set")
+ if os.Getenv("GODEBUGCPU") != "all=off" {
+ t.Skipf("skipping test: GODEBUGCPU=all=off not set")
}
for _, o := range Options {
diff --git a/src/internal/cpu/cpu_x86_test.go b/src/internal/cpu/cpu_x86_test.go
index c3ea7cb590..59c51770c5 100644
--- a/src/internal/cpu/cpu_x86_test.go
+++ b/src/internal/cpu/cpu_x86_test.go
@@ -30,14 +30,14 @@ func TestX86ifAVX2hasAVX(t *testing.T) {
}
func TestDisableSSE2(t *testing.T) {
- runDebugOptionsTest(t, "TestSSE2DebugOption", "sse2=0")
+ runDebugOptionsTest(t, "TestSSE2DebugOption", "sse2=off")
}
func TestSSE2DebugOption(t *testing.T) {
MustHaveDebugOptionsSupport(t)
- if os.Getenv("GODEBUGCPU") != "sse2=0" {
- t.Skipf("skipping test: GODEBUGCPU=sse2=0 not set")
+ if os.Getenv("GODEBUGCPU") != "sse2=off" {
+ t.Skipf("skipping test: GODEBUGCPU=sse2=off not set")
}
want := runtime.GOARCH != "386" // SSE2 can only be disabled on 386.
From 56131cbd1d61ec446e10dfe72a96f329ed3d952a Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 11 Oct 2018 16:47:41 -0700
Subject: [PATCH 108/240] go/types: remove a test case and update comment
The original need for the extra test case and issue was eliminated
by https://golang.org/cl/116815 which introduced systematic cycle
detection. Now that we correctly report the cycle, we can't say much
about the invalid cast anyway (the type is invalid due to the cycle).
A more sophisticated approach would be able to tell the size of
a function type independent of the details of that type, but the
type-checker is not set up for this kind of lazy type-checking.
Fixes #23127.
Change-Id: Ia8479e66baf630ce96f6f36770c8e1c810c59ddc
Reviewed-on: https://go-review.googlesource.com/c/141640
Run-TryBot: Robert Griesemer
TryBot-Result: Gobot Gobot
Reviewed-by: Alan Donovan
---
src/go/types/testdata/cycles2.src | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src
index a7f4bc60f5..fd0df4bf27 100644
--- a/src/go/types/testdata/cycles2.src
+++ b/src/go/types/testdata/cycles2.src
@@ -88,22 +88,10 @@ type T3 /* ERROR cycle */ interface {
var x3 T3
type T4 /* ERROR cycle */ interface {
- m() [unsafe.Sizeof(cast4(x4.m))]int
+ m() [unsafe.Sizeof(cast4(x4.m))]int // cast is invalid but we have a cycle, so all bets are off
}
var x4 T4
var _ = cast4(x4.m)
type cast4 func()
-
-// This test is symmetric to the T4 case: Here the cast is
-// "correct", but it doesn't work inside the T5 interface.
-
-type T5 /* ERROR cycle */ interface {
- m() [unsafe.Sizeof(cast5(x5.m))]int
-}
-
-var x5 T5
-var _ = cast5(x5.m)
-
-type cast5 func() [0]int
From 8e0aea162b5ed27b444a2a54aa16152022483141 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Tue, 2 Oct 2018 20:45:45 -0400
Subject: [PATCH 109/240] testing: implement -benchtime=100x
When running benchmarks with profilers and trying to
compare one run against another, it is very useful to be
able to force each run to execute exactly the same number
of iterations.
Discussion on the proposal issue #24735 led to the decision
to overload -benchtime, so that instead of saying
-benchtime 10s to run a benchmark for 10 seconds,
you say -benchtime 100x to run a benchmark 100 times.
Fixes #24735.
Change-Id: Id17c5bd18bd09987bb48ed12420d61ae9e200fd7
Reviewed-on: https://go-review.googlesource.com/c/139258
Run-TryBot: Russ Cox
Reviewed-by: Austin Clements
Reviewed-by: Brad Fitzpatrick
---
src/cmd/go/alldocs.go | 2 +
src/cmd/go/internal/test/test.go | 2 +
src/testing/benchmark.go | 75 ++++++++++++++++++++++++--------
src/testing/sub_test.go | 4 +-
4 files changed, 63 insertions(+), 20 deletions(-)
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index f54f000b07..33cb6cd3b3 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -2659,6 +2659,8 @@
// Run enough iterations of each benchmark to take t, specified
// as a time.Duration (for example, -benchtime 1h30s).
// The default is 1 second (1s).
+// The special syntax Nx means to run the benchmark N times
+// (for example, -benchtime 100x).
//
// -count n
// Run each test and benchmark n times (default 1).
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 3295e8ffe2..70deea3643 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -212,6 +212,8 @@ const testFlag2 = `
Run enough iterations of each benchmark to take t, specified
as a time.Duration (for example, -benchtime 1h30s).
The default is 1 second (1s).
+ The special syntax Nx means to run the benchmark N times
+ (for example, -benchtime 100x).
-count n
Run each test and benchmark n times (default 1).
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index 9c7b1be79e..90f86dc373 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -10,15 +10,50 @@ import (
"internal/race"
"os"
"runtime"
+ "strconv"
+ "strings"
"sync"
"sync/atomic"
"time"
)
var matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`")
-var benchTime = flag.Duration("test.benchtime", 1*time.Second, "run each benchmark for duration `d`")
+var benchTime = benchTimeFlag{d: 1 * time.Second}
var benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks")
+func init() {
+ flag.Var(&benchTime, "test.benchtime", "run each benchmark for duration `d`")
+}
+
+type benchTimeFlag struct {
+ d time.Duration
+ n int
+}
+
+func (f *benchTimeFlag) String() string {
+ if f.n > 0 {
+ return fmt.Sprintf("%dx", f.n)
+ }
+ return time.Duration(f.d).String()
+}
+
+func (f *benchTimeFlag) Set(s string) error {
+ if strings.HasSuffix(s, "x") {
+ n, err := strconv.ParseInt(s[:len(s)-1], 10, 0)
+ if err != nil || n <= 0 {
+ return fmt.Errorf("invalid count")
+ }
+ *f = benchTimeFlag{n: int(n)}
+ return nil
+ }
+ d, err := time.ParseDuration(s)
+ if err != nil || d <= 0 {
+ return fmt.Errorf("invalid duration")
+ }
+ *f = benchTimeFlag{d: d}
+ return nil
+}
+
// Global lock to ensure only one benchmark runs at a time.
var benchmarkLock sync.Mutex
@@ -53,7 +88,7 @@ type B struct {
previousN int // number of iterations in the previous run
previousDuration time.Duration // total duration of the previous run
benchFunc func(b *B)
- benchTime time.Duration
+ benchTime benchTimeFlag
bytes int64
missingBytes bool // one of the subbenchmarks does not have bytes set.
timerOn bool
@@ -273,21 +308,25 @@ func (b *B) launch() {
}()
// Run the benchmark for at least the specified amount of time.
- d := b.benchTime
- for n := 1; !b.failed && b.duration < d && n < 1e9; {
- last := n
- // Predict required iterations.
- n = int(d.Nanoseconds())
- if nsop := b.nsPerOp(); nsop != 0 {
- n /= int(nsop)
+ if b.benchTime.n > 0 {
+ b.runN(b.benchTime.n)
+ } else {
+ d := b.benchTime.d
+ for n := 1; !b.failed && b.duration < d && n < 1e9; {
+ last := n
+ // Predict required iterations.
+ n = int(d.Nanoseconds())
+ if nsop := b.nsPerOp(); nsop != 0 {
+ n /= int(nsop)
+ }
+ // Run more iterations than we think we'll need (1.2x).
+ // Don't grow too fast in case we had timing errors previously.
+ // Be sure to run at least one more than last time.
+ n = max(min(n+n/5, 100*last), last+1)
+ // Round up to something easy to read.
+ n = roundUp(n)
+ b.runN(n)
}
- // Run more iterations than we think we'll need (1.2x).
- // Don't grow too fast in case we had timing errors previously.
- // Be sure to run at least one more than last time.
- n = max(min(n+n/5, 100*last), last+1)
- // Round up to something easy to read.
- n = roundUp(n)
- b.runN(n)
}
b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes}
}
@@ -416,7 +455,7 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
b.Run(Benchmark.Name, Benchmark.F)
}
},
- benchTime: *benchTime,
+ benchTime: benchTime,
context: ctx,
}
main.runN(1)
@@ -653,7 +692,7 @@ func Benchmark(f func(b *B)) BenchmarkResult {
w: discard{},
},
benchFunc: f,
- benchTime: *benchTime,
+ benchTime: benchTime,
}
if b.run1() {
b.run()
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index e9b2233520..8c989714a1 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -17,7 +17,7 @@ import (
func init() {
// Make benchmark tests run 10* faster.
- *benchTime = 100 * time.Millisecond
+ benchTime.d = 100 * time.Millisecond
}
func TestTestContext(t *T) {
@@ -593,7 +593,7 @@ func TestBRun(t *T) {
chatty: tc.chatty,
},
benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
- benchTime: time.Microsecond,
+ benchTime: benchTimeFlag{d: 1 * time.Microsecond},
}
root.runN(1)
if ok != !tc.failed {
From 2d4346b319e01b649f49775c26ab2ff1d28fb7b6 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Fri, 28 Sep 2018 16:37:16 -0400
Subject: [PATCH 110/240] regexp: split bit-state execution out of machine
struct
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This allows the bit-state executions to have their
own pool of allocated structures. A step toward
eliminating the per-Regexp machine cache.
Note especially the -92% on MatchParallelShared.
This is real but not a complete story: the other
execution engines still need to be de-shared,
but the benchmark was only using bit-state.
The tiny slowdowns in unrelated code are noise.
name old time/op new time/op delta
Find-12 264ns ± 3% 254ns ± 0% -3.86% (p=0.000 n=10+9)
FindAllNoMatches-12 140ns ± 2% 135ns ± 0% -3.91% (p=0.000 n=10+9)
FindString-12 256ns ± 0% 247ns ± 0% -3.52% (p=0.000 n=8+8)
FindSubmatch-12 339ns ± 1% 334ns ± 0% -1.41% (p=0.000 n=9+10)
FindStringSubmatch-12 322ns ± 0% 321ns ± 0% -0.21% (p=0.005 n=8+9)
Literal-12 100ns ± 2% 92ns ± 0% -8.10% (p=0.000 n=10+9)
NotLiteral-12 1.50µs ± 0% 1.47µs ± 0% -1.91% (p=0.000 n=8+9)
MatchClass-12 2.18µs ± 0% 2.17µs ± 0% -0.20% (p=0.001 n=10+7)
MatchClass_InRange-12 2.12µs ± 0% 2.13µs ± 0% +0.23% (p=0.000 n=10+10)
ReplaceAll-12 1.41µs ± 0% 1.39µs ± 0% -1.30% (p=0.000 n=7+10)
AnchoredLiteralShortNonMatch-12 89.8ns ± 0% 83.2ns ± 0% -7.35% (p=0.000 n=8+8)
AnchoredLiteralLongNonMatch-12 105ns ± 3% 105ns ± 0% ~ (p=0.186 n=10+10)
AnchoredShortMatch-12 141ns ± 0% 131ns ± 0% -7.09% (p=0.000 n=9+10)
AnchoredLongMatch-12 276ns ± 4% 267ns ± 0% -3.23% (p=0.000 n=10+10)
OnePassShortA-12 620ns ± 0% 611ns ± 0% -1.39% (p=0.000 n=10+9)
NotOnePassShortA-12 575ns ± 3% 552ns ± 0% -3.97% (p=0.000 n=10+8)
OnePassShortB-12 493ns ± 0% 491ns ± 0% -0.33% (p=0.000 n=8+8)
NotOnePassShortB-12 423ns ± 0% 412ns ± 0% -2.60% (p=0.000 n=8+9)
OnePassLongPrefix-12 112ns ± 0% 112ns ± 0% ~ (all equal)
OnePassLongNotPrefix-12 405ns ± 0% 410ns ± 0% +1.23% (p=0.000 n=8+9)
MatchParallelShared-12 501ns ± 1% 39ns ± 1% -92.27% (p=0.000 n=10+10)
MatchParallelCopied-12 39.1ns ± 0% 39.2ns ± 3% ~ (p=0.785 n=6+10)
QuoteMetaAll-12 94.6ns ± 0% 94.6ns ± 0% ~ (p=0.439 n=10+8)
QuoteMetaNone-12 52.7ns ± 0% 52.7ns ± 0% ~ (all equal)
Match/Easy0/32-12 79.1ns ± 0% 72.9ns ± 0% -7.85% (p=0.000 n=9+9)
Match/Easy0/1K-12 307ns ± 1% 298ns ± 0% -2.99% (p=0.000 n=10+6)
Match/Easy0/32K-12 4.65µs ± 2% 4.60µs ± 2% ~ (p=0.159 n=10+10)
Match/Easy0/1M-12 234µs ± 0% 235µs ± 0% +0.17% (p=0.003 n=10+10)
Match/Easy0/32M-12 7.98ms ± 1% 7.96ms ± 0% ~ (p=0.278 n=9+10)
Match/Easy0i/32-12 1.13µs ± 1% 1.09µs ± 0% -3.24% (p=0.000 n=9+8)
Match/Easy0i/1K-12 32.5µs ± 0% 31.7µs ± 0% -2.66% (p=0.000 n=9+9)
Match/Easy0i/32K-12 1.59ms ± 0% 1.61ms ± 0% +0.75% (p=0.000 n=9+9)
Match/Easy0i/1M-12 51.0ms ± 0% 51.4ms ± 0% +0.77% (p=0.000 n=10+8)
Match/Easy0i/32M-12 1.63s ± 0% 1.65s ± 1% +1.24% (p=0.000 n=7+9)
Match/Easy1/32-12 75.1ns ± 1% 67.9ns ± 0% -9.54% (p=0.000 n=8+8)
Match/Easy1/1K-12 861ns ± 0% 884ns ± 0% +2.71% (p=0.000 n=8+9)
Match/Easy1/32K-12 39.2µs ± 1% 39.2µs ± 0% ~ (p=0.090 n=10+9)
Match/Easy1/1M-12 1.38ms ± 0% 1.39ms ± 0% ~ (p=0.095 n=10+9)
Match/Easy1/32M-12 44.2ms ± 1% 44.2ms ± 1% ~ (p=0.218 n=10+10)
Match/Medium/32-12 1.04µs ± 1% 1.05µs ± 0% +1.05% (p=0.000 n=9+8)
Match/Medium/1K-12 31.3µs ± 0% 31.3µs ± 0% -0.14% (p=0.004 n=9+9)
Match/Medium/32K-12 1.44ms ± 0% 1.45ms ± 0% +0.18% (p=0.001 n=8+8)
Match/Medium/1M-12 46.1ms ± 0% 46.2ms ± 0% +0.13% (p=0.003 n=6+9)
Match/Medium/32M-12 1.48s ± 0% 1.48s ± 0% +0.20% (p=0.002 n=9+8)
Match/Hard/32-12 1.54µs ± 1% 1.49µs ± 0% -3.60% (p=0.000 n=9+10)
Match/Hard/1K-12 46.4µs ± 1% 45.1µs ± 1% -2.78% (p=0.000 n=9+10)
Match/Hard/32K-12 2.19ms ± 0% 2.18ms ± 1% -0.51% (p=0.006 n=8+9)
Match/Hard/1M-12 70.1ms ± 0% 69.7ms ± 1% -0.52% (p=0.006 n=8+9)
Match/Hard/32M-12 2.24s ± 0% 2.23s ± 1% -0.42% (p=0.046 n=8+9)
Match/Hard1/32-12 8.17µs ± 1% 7.89µs ± 0% -3.42% (p=0.000 n=8+9)
Match/Hard1/1K-12 254µs ± 2% 244µs ± 0% -3.91% (p=0.000 n=9+9)
Match/Hard1/32K-12 9.58ms ± 1% 10.35ms ± 0% +8.00% (p=0.000 n=10+10)
Match/Hard1/1M-12 306ms ± 1% 331ms ± 0% +8.27% (p=0.000 n=9+8)
Match/Hard1/32M-12 9.79s ± 1% 10.60s ± 0% +8.29% (p=0.000 n=9+8)
Match_onepass_regex/32-12 808ns ± 0% 812ns ± 0% +0.47% (p=0.000 n=8+10)
Match_onepass_regex/1K-12 27.8µs ± 0% 28.5µs ± 0% +2.32% (p=0.000 n=8+10)
Match_onepass_regex/32K-12 925µs ± 0% 936µs ± 0% +1.24% (p=0.000 n=9+10)
Match_onepass_regex/1M-12 29.5ms ± 0% 30.2ms ± 0% +2.38% (p=0.000 n=10+10)
Match_onepass_regex/32M-12 945ms ± 0% 970ms ± 0% +2.60% (p=0.000 n=9+10)
CompileOnepass-12 4.67µs ± 0% 4.63µs ± 1% -0.84% (p=0.000 n=10+10)
[Geo mean] 24.5µs 23.3µs -5.04%
https://perf.golang.org/search?q=upload:20181004.1
Change-Id: Idbc2b76223718265657819ff38be2d9aba1c54b4
Reviewed-on: https://go-review.googlesource.com/c/139779
Run-TryBot: Russ Cox
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/regexp/backtrack.go | 176 ++++++++++++++++++++++------------------
src/regexp/exec.go | 107 +++++++++++++-----------
src/regexp/regexp.go | 18 ++--
3 files changed, 162 insertions(+), 139 deletions(-)
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
index 440bf7ffc5..239abc3a57 100644
--- a/src/regexp/backtrack.go
+++ b/src/regexp/backtrack.go
@@ -14,7 +14,10 @@
package regexp
-import "regexp/syntax"
+import (
+ "regexp/syntax"
+ "sync"
+)
// A job is an entry on the backtracker's job stack. It holds
// the instruction pc and the position in the input.
@@ -32,15 +35,29 @@ const (
// bitState holds state for the backtracker.
type bitState struct {
- prog *syntax.Prog
+ end int
+ cap []int
+ matchcap []int
+ jobs []job
+ visited []uint32
- end int
- cap []int
- jobs []job
- visited []uint32
+ inputs inputs
}
-var notBacktrack *bitState = nil
+var bitStatePool sync.Pool
+
+func newBitState() *bitState {
+ b, ok := bitStatePool.Get().(*bitState)
+ if !ok {
+ b = new(bitState)
+ }
+ return b
+}
+
+func freeBitState(b *bitState) {
+ b.inputs.clear()
+ bitStatePool.Put(b)
+}
// maxBitStateLen returns the maximum length of a string to search with
// the backtracker using prog.
@@ -51,18 +68,6 @@ func maxBitStateLen(prog *syntax.Prog) int {
return maxBacktrackVector / len(prog.Inst)
}
-// newBitState returns a new bitState for the given prog,
-// or notBacktrack if the size of the prog exceeds the maximum size that
-// the backtracker will be run for.
-func newBitState(prog *syntax.Prog) *bitState {
- if !shouldBacktrack(prog) {
- return notBacktrack
- }
- return &bitState{
- prog: prog,
- }
-}
-
// shouldBacktrack reports whether the program is too
// long for the backtracker to run.
func shouldBacktrack(prog *syntax.Prog) bool {
@@ -72,7 +77,7 @@ func shouldBacktrack(prog *syntax.Prog) bool {
// reset resets the state of the backtracker.
// end is the end position in the input.
// ncap is the number of captures.
-func (b *bitState) reset(end int, ncap int) {
+func (b *bitState) reset(prog *syntax.Prog, end int, ncap int) {
b.end = end
if cap(b.jobs) == 0 {
@@ -81,7 +86,7 @@ func (b *bitState) reset(end int, ncap int) {
b.jobs = b.jobs[:0]
}
- visitedSize := (len(b.prog.Inst)*(end+1) + visitedBits - 1) / visitedBits
+ visitedSize := (len(prog.Inst)*(end+1) + visitedBits - 1) / visitedBits
if cap(b.visited) < visitedSize {
b.visited = make([]uint32, visitedSize, maxBacktrackVector/visitedBits)
} else {
@@ -99,6 +104,15 @@ func (b *bitState) reset(end int, ncap int) {
for i := range b.cap {
b.cap[i] = -1
}
+
+ if cap(b.matchcap) < ncap {
+ b.matchcap = make([]int, ncap)
+ } else {
+ b.matchcap = b.matchcap[:ncap]
+ }
+ for i := range b.matchcap {
+ b.matchcap[i] = -1
+ }
}
// shouldVisit reports whether the combination of (pc, pos) has not
@@ -114,20 +128,19 @@ func (b *bitState) shouldVisit(pc uint32, pos int) bool {
// push pushes (pc, pos, arg) onto the job stack if it should be
// visited.
-func (b *bitState) push(pc uint32, pos int, arg bool) {
+func (b *bitState) push(re *Regexp, pc uint32, pos int, arg bool) {
// Only check shouldVisit when arg is false.
// When arg is true, we are continuing a previous visit.
- if b.prog.Inst[pc].Op != syntax.InstFail && (arg || b.shouldVisit(pc, pos)) {
+ if re.prog.Inst[pc].Op != syntax.InstFail && (arg || b.shouldVisit(pc, pos)) {
b.jobs = append(b.jobs, job{pc: pc, arg: arg, pos: pos})
}
}
// tryBacktrack runs a backtracking search starting at pos.
-func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
- longest := m.re.longest
- m.matched = false
+func (re *Regexp) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
+ longest := re.longest
- b.push(pc, pos, false)
+ b.push(re, pc, pos, false)
for len(b.jobs) > 0 {
l := len(b.jobs) - 1
// Pop job off the stack.
@@ -150,7 +163,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
}
Skip:
- inst := b.prog.Inst[pc]
+ inst := re.prog.Inst[pc]
switch inst.Op {
default:
@@ -172,23 +185,23 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
pc = inst.Arg
goto CheckAndLoop
} else {
- b.push(pc, pos, true)
+ b.push(re, pc, pos, true)
pc = inst.Out
goto CheckAndLoop
}
case syntax.InstAltMatch:
// One opcode consumes runes; the other leads to match.
- switch b.prog.Inst[inst.Out].Op {
+ switch re.prog.Inst[inst.Out].Op {
case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
// inst.Arg is the match.
- b.push(inst.Arg, pos, false)
+ b.push(re, inst.Arg, pos, false)
pc = inst.Arg
pos = b.end
goto CheckAndLoop
}
// inst.Out is the match - non-greedy
- b.push(inst.Out, b.end, false)
+ b.push(re, inst.Out, b.end, false)
pc = inst.Out
goto CheckAndLoop
@@ -236,7 +249,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
} else {
if 0 <= inst.Arg && inst.Arg < uint32(len(b.cap)) {
// Capture pos to register, but save old value.
- b.push(pc, b.cap[inst.Arg], true) // come back when we're done.
+ b.push(re, pc, b.cap[inst.Arg], true) // come back when we're done.
b.cap[inst.Arg] = pos
}
pc = inst.Out
@@ -258,8 +271,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
// We found a match. If the caller doesn't care
// where the match is, no point going further.
if len(b.cap) == 0 {
- m.matched = true
- return m.matched
+ return true
}
// Record best match so far.
@@ -268,19 +280,18 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
if len(b.cap) > 1 {
b.cap[1] = pos
}
- if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) {
- copy(m.matchcap, b.cap)
+ if old := b.matchcap[1]; old == -1 || (longest && pos > 0 && pos > old) {
+ copy(b.matchcap, b.cap)
}
- m.matched = true
// If going for first match, we're done.
if !longest {
- return m.matched
+ return true
}
// If we used the entire text, no longer match is possible.
if pos == b.end {
- return m.matched
+ return true
}
// Otherwise, continue on in hope of a longer match.
@@ -288,65 +299,68 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
}
}
- return m.matched
+ return longest && len(b.matchcap) > 1 && b.matchcap[1] >= 0
}
// backtrack runs a backtracking search of prog on the input starting at pos.
-func (m *machine) backtrack(i input, pos int, end int, ncap int) bool {
- if !i.canCheckPrefix() {
- panic("backtrack called for a RuneReader")
- }
-
- startCond := m.re.cond
+func (re *Regexp) backtrack(ib []byte, is string, pos int, ncap int, dstCap []int) []int {
+ startCond := re.cond
if startCond == ^syntax.EmptyOp(0) { // impossible
- return false
+ return nil
}
if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
// Anchored match, past beginning of text.
- return false
+ return nil
}
- b := m.b
- b.reset(end, ncap)
-
- m.matchcap = m.matchcap[:ncap]
- for i := range m.matchcap {
- m.matchcap[i] = -1
- }
+ b := newBitState()
+ i, end := b.inputs.init(nil, ib, is)
+ b.reset(re.prog, end, ncap)
// Anchored search must start at the beginning of the input
if startCond&syntax.EmptyBeginText != 0 {
if len(b.cap) > 0 {
b.cap[0] = pos
}
- return m.tryBacktrack(b, i, uint32(m.p.Start), pos)
- }
+ if !re.tryBacktrack(b, i, uint32(re.prog.Start), pos) {
+ freeBitState(b)
+ return nil
+ }
+ } else {
- // Unanchored search, starting from each possible text position.
- // Notice that we have to try the empty string at the end of
- // the text, so the loop condition is pos <= end, not pos < end.
- // This looks like it's quadratic in the size of the text,
- // but we are not clearing visited between calls to TrySearch,
- // so no work is duplicated and it ends up still being linear.
- width := -1
- for ; pos <= end && width != 0; pos += width {
- if len(m.re.prefix) > 0 {
- // Match requires literal prefix; fast search for it.
- advance := i.index(m.re, pos)
- if advance < 0 {
- return false
+ // Unanchored search, starting from each possible text position.
+ // Notice that we have to try the empty string at the end of
+ // the text, so the loop condition is pos <= end, not pos < end.
+ // This looks like it's quadratic in the size of the text,
+ // but we are not clearing visited between calls to TrySearch,
+ // so no work is duplicated and it ends up still being linear.
+ width := -1
+ for ; pos <= end && width != 0; pos += width {
+ if len(re.prefix) > 0 {
+ // Match requires literal prefix; fast search for it.
+ advance := i.index(re, pos)
+ if advance < 0 {
+ freeBitState(b)
+ return nil
+ }
+ pos += advance
}
- pos += advance
- }
- if len(b.cap) > 0 {
- b.cap[0] = pos
+ if len(b.cap) > 0 {
+ b.cap[0] = pos
+ }
+ if re.tryBacktrack(b, i, uint32(re.prog.Start), pos) {
+ // Match must be leftmost; done.
+ goto Match
+ }
+ _, width = i.step(pos)
}
- if m.tryBacktrack(b, i, uint32(m.p.Start), pos) {
- // Match must be leftmost; done.
- return true
- }
- _, width = i.step(pos)
+ freeBitState(b)
+ return nil
}
- return false
+
+Match:
+ dstCap = append(dstCap, b.matchcap...)
+ freeBitState(b)
+ return dstCap
}
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 1c7b02d1cd..271174670e 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -35,37 +35,61 @@ type thread struct {
// A machine holds all the state during an NFA simulation for p.
type machine struct {
- re *Regexp // corresponding Regexp
- p *syntax.Prog // compiled program
- op *onePassProg // compiled onepass program, or notOnePass
- maxBitStateLen int // max length of string to search with bitstate
- b *bitState // state for backtracker, allocated lazily
- q0, q1 queue // two queues for runq, nextq
- pool []*thread // pool of available threads
- matched bool // whether a match was found
- matchcap []int // capture information for the match
+ re *Regexp // corresponding Regexp
+ p *syntax.Prog // compiled program
+ op *onePassProg // compiled onepass program, or notOnePass
+ q0, q1 queue // two queues for runq, nextq
+ pool []*thread // pool of available threads
+ matched bool // whether a match was found
+ matchcap []int // capture information for the match
+ inputs inputs
+}
+
+type inputs struct {
// cached inputs, to avoid allocation
- inputBytes inputBytes
- inputString inputString
- inputReader inputReader
+ bytes inputBytes
+ string inputString
+ reader inputReader
}
-func (m *machine) newInputBytes(b []byte) input {
- m.inputBytes.str = b
- return &m.inputBytes
+func (i *inputs) newBytes(b []byte) input {
+ i.bytes.str = b
+ return &i.bytes
}
-func (m *machine) newInputString(s string) input {
- m.inputString.str = s
- return &m.inputString
+func (i *inputs) newString(s string) input {
+ i.string.str = s
+ return &i.string
}
-func (m *machine) newInputReader(r io.RuneReader) input {
- m.inputReader.r = r
- m.inputReader.atEOT = false
- m.inputReader.pos = 0
- return &m.inputReader
+func (i *inputs) newReader(r io.RuneReader) input {
+ i.reader.r = r
+ i.reader.atEOT = false
+ i.reader.pos = 0
+ return &i.reader
+}
+
+func (i *inputs) clear() {
+ // We need to clear 1 of these.
+ // Avoid the expense of clearing the others (pointer write barrier).
+ if i.bytes.str != nil {
+ i.bytes.str = nil
+ } else if i.reader.r != nil {
+ i.reader.r = nil
+ } else {
+ i.string.str = ""
+ }
+}
+
+func (i *inputs) init(r io.RuneReader, b []byte, s string) (input, int) {
+ if r != nil {
+ return i.newReader(r), 0
+ }
+ if b != nil {
+ return i.newBytes(b), len(b)
+ }
+ return i.newString(s), len(s)
}
// progMachine returns a new machine running the prog p.
@@ -78,9 +102,6 @@ func progMachine(p *syntax.Prog, op *onePassProg) *machine {
if ncap < 2 {
ncap = 2
}
- if op == notOnePass {
- m.maxBitStateLen = maxBitStateLen(p)
- }
m.matchcap = make([]int, ncap)
return m
}
@@ -416,31 +437,23 @@ func (re *Regexp) doMatch(r io.RuneReader, b []byte, s string) bool {
//
// nil is returned if no matches are found and non-nil if matches are found.
func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int, dstCap []int) []int {
- m := re.get()
- var i input
- var size int
- if r != nil {
- i = m.newInputReader(r)
- } else if b != nil {
- i = m.newInputBytes(b)
- size = len(b)
- } else {
- i = m.newInputString(s)
- size = len(s)
+ if dstCap == nil {
+ // Make sure 'return dstCap' is non-nil.
+ dstCap = arrayNoInts[:0:0]
}
+
+ if re.onepass == notOnePass && r == nil && len(b)+len(s) < re.maxBitStateLen {
+ return re.backtrack(b, s, pos, ncap, dstCap)
+ }
+
+ m := re.get()
+ i, _ := m.inputs.init(r, b, s)
+
if m.op != notOnePass {
if !m.onepass(i, pos, ncap) {
re.put(m)
return nil
}
- } else if size < m.maxBitStateLen && r == nil {
- if m.b == nil {
- m.b = newBitState(m.p)
- }
- if !m.backtrack(i, pos, size, ncap) {
- re.put(m)
- return nil
- }
} else {
m.init(ncap)
if !m.match(i, pos) {
@@ -449,10 +462,6 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
}
}
dstCap = append(dstCap, m.matchcap...)
- if dstCap == nil {
- // Keep the promise of returning non-nil value on match.
- dstCap = arrayNoInts[:0]
- }
re.put(m)
return dstCap
}
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 89bb975ac1..dafcfd433d 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -88,17 +88,18 @@ type Regexp struct {
}
type regexpRO struct {
- expr string // as passed to Compile
- prog *syntax.Prog // compiled program
- onepass *onePassProg // onepass program or nil
+ expr string // as passed to Compile
+ prog *syntax.Prog // compiled program
+ onepass *onePassProg // onepass program or nil
+ numSubexp int
+ maxBitStateLen int
+ subexpNames []string
prefix string // required prefix in unanchored matches
prefixBytes []byte // prefix, as a []byte
- prefixComplete bool // prefix is the entire regexp
prefixRune rune // first rune in prefix
prefixEnd uint32 // pc for last rune in prefix
+ prefixComplete bool // prefix is the entire regexp
cond syntax.EmptyOp // empty-width conditions required at start of match
- numSubexp int
- subexpNames []string
longest bool
}
@@ -192,6 +193,7 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
}
if regexp.onepass == notOnePass {
regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ regexp.maxBitStateLen = maxBitStateLen(prog)
} else {
regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog)
}
@@ -227,9 +229,7 @@ func (re *Regexp) get() *machine {
// run using re. (The cache empties when re gets garbage collected.)
func (re *Regexp) put(z *machine) {
// Remove references to input data that we no longer need.
- z.inputBytes.str = nil
- z.inputString.str = ""
- z.inputReader.r = nil
+ z.inputs.clear()
re.mu.Lock()
re.machine = append(re.machine, z)
From 60b297118043eef54eb924d81f940e79c0316433 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Tue, 2 Oct 2018 09:29:47 -0400
Subject: [PATCH 111/240] regexp: split one-pass execution out of machine
struct
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This allows the one-pass executions to have their
own pool of (much smaller) allocated structures.
A step toward eliminating the per-Regexp machine cache.
Not much effect on benchmarks, since there are no
optimizations here, and pools are a tiny bit slower than a
locked data structure for single-threaded code.
name old time/op new time/op delta
Find-12 254ns ± 0% 252ns ± 0% -0.94% (p=0.000 n=9+10)
FindAllNoMatches-12 135ns ± 0% 134ns ± 1% -0.49% (p=0.002 n=9+9)
FindString-12 247ns ± 0% 246ns ± 0% -0.24% (p=0.003 n=8+10)
FindSubmatch-12 334ns ± 0% 333ns ± 2% ~ (p=0.283 n=10+10)
FindStringSubmatch-12 321ns ± 0% 320ns ± 0% -0.51% (p=0.000 n=9+10)
Literal-12 92.2ns ± 0% 91.1ns ± 0% -1.25% (p=0.000 n=9+10)
NotLiteral-12 1.47µs ± 0% 1.45µs ± 0% -0.99% (p=0.000 n=9+10)
MatchClass-12 2.17µs ± 0% 2.19µs ± 0% +0.84% (p=0.000 n=7+9)
MatchClass_InRange-12 2.13µs ± 0% 2.09µs ± 0% -1.70% (p=0.000 n=10+10)
ReplaceAll-12 1.39µs ± 0% 1.39µs ± 0% +0.51% (p=0.000 n=10+10)
AnchoredLiteralShortNonMatch-12 83.2ns ± 0% 82.4ns ± 0% -0.96% (p=0.000 n=8+8)
AnchoredLiteralLongNonMatch-12 105ns ± 0% 106ns ± 1% ~ (p=0.087 n=10+10)
AnchoredShortMatch-12 131ns ± 0% 130ns ± 0% -0.76% (p=0.000 n=10+9)
AnchoredLongMatch-12 267ns ± 0% 272ns ± 0% +2.01% (p=0.000 n=10+8)
OnePassShortA-12 611ns ± 0% 615ns ± 0% +0.61% (p=0.000 n=9+10)
NotOnePassShortA-12 552ns ± 0% 549ns ± 0% -0.46% (p=0.000 n=8+9)
OnePassShortB-12 491ns ± 0% 494ns ± 0% +0.61% (p=0.000 n=8+8)
NotOnePassShortB-12 412ns ± 0% 412ns ± 1% ~ (p=0.151 n=9+10)
OnePassLongPrefix-12 112ns ± 0% 108ns ± 0% -3.57% (p=0.000 n=10+10)
OnePassLongNotPrefix-12 410ns ± 0% 402ns ± 0% -1.95% (p=0.000 n=9+8)
MatchParallelShared-12 38.8ns ± 1% 38.6ns ± 2% ~ (p=0.536 n=10+9)
MatchParallelCopied-12 39.2ns ± 3% 39.4ns ± 7% ~ (p=0.986 n=10+10)
QuoteMetaAll-12 94.6ns ± 0% 94.9ns ± 0% +0.29% (p=0.001 n=8+9)
QuoteMetaNone-12 52.7ns ± 0% 52.7ns ± 0% ~ (all equal)
Match/Easy0/32-12 72.9ns ± 0% 72.1ns ± 0% -1.07% (p=0.000 n=9+9)
Match/Easy0/1K-12 298ns ± 0% 298ns ± 0% ~ (p=0.140 n=6+8)
Match/Easy0/32K-12 4.60µs ± 2% 4.64µs ± 1% ~ (p=0.171 n=10+10)
Match/Easy0/1M-12 235µs ± 0% 234µs ± 0% -0.14% (p=0.004 n=10+10)
Match/Easy0/32M-12 7.96ms ± 0% 7.95ms ± 0% -0.12% (p=0.043 n=10+9)
Match/Easy0i/32-12 1.09µs ± 0% 1.10µs ± 0% +0.15% (p=0.000 n=8+9)
Match/Easy0i/1K-12 31.7µs ± 0% 31.8µs ± 1% ~ (p=0.905 n=9+10)
Match/Easy0i/32K-12 1.61ms ± 0% 1.62ms ± 1% +1.12% (p=0.000 n=9+10)
Match/Easy0i/1M-12 51.4ms ± 0% 51.8ms ± 0% +0.85% (p=0.000 n=8+8)
Match/Easy0i/32M-12 1.65s ± 1% 1.65s ± 0% ~ (p=0.113 n=9+9)
Match/Easy1/32-12 67.9ns ± 0% 67.7ns ± 1% ~ (p=0.232 n=8+10)
Match/Easy1/1K-12 884ns ± 0% 873ns ± 0% -1.29% (p=0.000 n=9+10)
Match/Easy1/32K-12 39.2µs ± 0% 39.4µs ± 0% +0.50% (p=0.000 n=9+10)
Match/Easy1/1M-12 1.39ms ± 0% 1.39ms ± 0% +0.29% (p=0.000 n=9+10)
Match/Easy1/32M-12 44.2ms ± 1% 44.3ms ± 0% +0.21% (p=0.029 n=10+10)
Match/Medium/32-12 1.05µs ± 0% 1.04µs ± 0% -0.27% (p=0.001 n=8+9)
Match/Medium/1K-12 31.3µs ± 0% 31.4µs ± 0% +0.39% (p=0.000 n=9+8)
Match/Medium/32K-12 1.45ms ± 0% 1.45ms ± 0% +0.33% (p=0.000 n=8+9)
Match/Medium/1M-12 46.2ms ± 0% 46.4ms ± 0% +0.35% (p=0.000 n=9+8)
Match/Medium/32M-12 1.48s ± 0% 1.49s ± 1% +0.70% (p=0.000 n=8+10)
Match/Hard/32-12 1.49µs ± 0% 1.48µs ± 0% -0.43% (p=0.000 n=10+9)
Match/Hard/1K-12 45.1µs ± 1% 45.0µs ± 1% ~ (p=0.393 n=10+10)
Match/Hard/32K-12 2.18ms ± 1% 2.24ms ± 0% +2.71% (p=0.000 n=9+8)
Match/Hard/1M-12 69.7ms ± 1% 71.6ms ± 0% +2.76% (p=0.000 n=9+7)
Match/Hard/32M-12 2.23s ± 1% 2.29s ± 0% +2.65% (p=0.000 n=9+9)
Match/Hard1/32-12 7.89µs ± 0% 7.89µs ± 0% ~ (p=0.286 n=9+9)
Match/Hard1/1K-12 244µs ± 0% 244µs ± 0% ~ (p=0.905 n=9+10)
Match/Hard1/32K-12 10.3ms ± 0% 10.3ms ± 0% ~ (p=0.796 n=10+10)
Match/Hard1/1M-12 331ms ± 0% 331ms ± 0% ~ (p=0.167 n=8+9)
Match/Hard1/32M-12 10.6s ± 0% 10.6s ± 0% ~ (p=0.315 n=8+10)
Match_onepass_regex/32-12 812ns ± 0% 830ns ± 0% +2.19% (p=0.000 n=10+9)
Match_onepass_regex/1K-12 28.5µs ± 0% 28.7µs ± 1% +0.97% (p=0.000 n=10+9)
Match_onepass_regex/32K-12 936µs ± 0% 949µs ± 0% +1.43% (p=0.000 n=10+8)
Match_onepass_regex/1M-12 30.2ms ± 0% 30.4ms ± 0% +0.62% (p=0.000 n=10+8)
Match_onepass_regex/32M-12 970ms ± 0% 973ms ± 0% +0.35% (p=0.000 n=10+9)
CompileOnepass-12 4.63µs ± 1% 4.64µs ± 0% ~ (p=0.060 n=10+10)
[Geo mean] 23.3µs 23.3µs +0.12%
https://perf.golang.org/search?q=upload:20181004.2
Change-Id: Iff9e9f9d4a4698162126a2f300e8ed1b1a39361e
Reviewed-on: https://go-review.googlesource.com/c/139780
Run-TryBot: Russ Cox
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/regexp/all_test.go | 4 +-
src/regexp/exec.go | 115 ++++++++++++++++++++++++-------------
src/regexp/exec_test.go | 2 +-
src/regexp/onepass.go | 24 ++++----
src/regexp/onepass_test.go | 86 ++++++++++++++-------------
src/regexp/regexp.go | 4 +-
6 files changed, 132 insertions(+), 103 deletions(-)
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index 0fabeae59f..8cbc2962cb 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -550,8 +550,8 @@ func TestOnePassCutoff(t *testing.T) {
if err != nil {
t.Fatalf("compile: %v", err)
}
- if compileOnePass(p) != notOnePass {
- t.Fatalf("makeOnePass succeeded; wanted notOnePass")
+ if compileOnePass(p) != nil {
+ t.Fatalf("makeOnePass succeeded; wanted nil")
}
}
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 271174670e..23908d22d5 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -7,6 +7,7 @@ package regexp
import (
"io"
"regexp/syntax"
+ "sync"
)
// A queue is a 'sparse array' holding pending threads of execution.
@@ -37,7 +38,6 @@ type thread struct {
type machine struct {
re *Regexp // corresponding Regexp
p *syntax.Prog // compiled program
- op *onePassProg // compiled onepass program, or notOnePass
q0, q1 queue // two queues for runq, nextq
pool []*thread // pool of available threads
matched bool // whether a match was found
@@ -93,8 +93,8 @@ func (i *inputs) init(r io.RuneReader, b []byte, s string) (input, int) {
}
// progMachine returns a new machine running the prog p.
-func progMachine(p *syntax.Prog, op *onePassProg) *machine {
- m := &machine{p: p, op: op}
+func progMachine(p *syntax.Prog) *machine {
+ m := &machine{p: p}
n := len(m.p.Inst)
m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
@@ -327,20 +327,47 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
return t
}
-// onepass runs the machine over the input starting at pos.
-// It reports whether a match was found.
-// If so, m.matchcap holds the submatch information.
-// ncap is the number of captures.
-func (m *machine) onepass(i input, pos, ncap int) bool {
- startCond := m.re.cond
- if startCond == ^syntax.EmptyOp(0) { // impossible
- return false
+type onePassMachine struct {
+ inputs inputs
+ matchcap []int
+}
+
+var onePassPool sync.Pool
+
+func newOnePassMachine() *onePassMachine {
+ m, ok := onePassPool.Get().(*onePassMachine)
+ if !ok {
+ m = new(onePassMachine)
}
- m.matched = false
- m.matchcap = m.matchcap[:ncap]
+ return m
+}
+
+func freeOnePassMachine(m *onePassMachine) {
+ m.inputs.clear()
+ onePassPool.Put(m)
+}
+
+// doOnePass implements r.doExecute using the one-pass execution engine.
+func (re *Regexp) doOnePass(ir io.RuneReader, ib []byte, is string, pos, ncap int, dstCap []int) []int {
+ startCond := re.cond
+ if startCond == ^syntax.EmptyOp(0) { // impossible
+ return nil
+ }
+
+ m := newOnePassMachine()
+ if cap(m.matchcap) < ncap {
+ m.matchcap = make([]int, ncap)
+ } else {
+ m.matchcap = m.matchcap[:ncap]
+ }
+
+ matched := false
for i := range m.matchcap {
m.matchcap[i] = -1
}
+
+ i, _ := m.inputs.init(ir, ib, is)
+
r, r1 := endOfText, endOfText
width, width1 := 0, 0
r, width = i.step(pos)
@@ -353,59 +380,59 @@ func (m *machine) onepass(i input, pos, ncap int) bool {
} else {
flag = i.context(pos)
}
- pc := m.op.Start
- inst := m.op.Inst[pc]
+ pc := re.onepass.Start
+ inst := re.onepass.Inst[pc]
// If there is a simple literal prefix, skip over it.
if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 &&
- len(m.re.prefix) > 0 && i.canCheckPrefix() {
+ len(re.prefix) > 0 && i.canCheckPrefix() {
// Match requires literal prefix; fast search for it.
- if !i.hasPrefix(m.re) {
- return m.matched
+ if !i.hasPrefix(re) {
+ goto Return
}
- pos += len(m.re.prefix)
+ pos += len(re.prefix)
r, width = i.step(pos)
r1, width1 = i.step(pos + width)
flag = i.context(pos)
- pc = int(m.re.prefixEnd)
+ pc = int(re.prefixEnd)
}
for {
- inst = m.op.Inst[pc]
+ inst = re.onepass.Inst[pc]
pc = int(inst.Out)
switch inst.Op {
default:
panic("bad inst")
case syntax.InstMatch:
- m.matched = true
+ matched = true
if len(m.matchcap) > 0 {
m.matchcap[0] = 0
m.matchcap[1] = pos
}
- return m.matched
+ goto Return
case syntax.InstRune:
if !inst.MatchRune(r) {
- return m.matched
+ goto Return
}
case syntax.InstRune1:
if r != inst.Rune[0] {
- return m.matched
+ goto Return
}
case syntax.InstRuneAny:
// Nothing
case syntax.InstRuneAnyNotNL:
if r == '\n' {
- return m.matched
+ goto Return
}
// peek at the input rune to see which branch of the Alt to take
case syntax.InstAlt, syntax.InstAltMatch:
pc = int(onePassNext(&inst, r))
continue
case syntax.InstFail:
- return m.matched
+ goto Return
case syntax.InstNop:
continue
case syntax.InstEmptyWidth:
if syntax.EmptyOp(inst.Arg)&^flag != 0 {
- return m.matched
+ goto Return
}
continue
case syntax.InstCapture:
@@ -424,7 +451,16 @@ func (m *machine) onepass(i input, pos, ncap int) bool {
r1, width1 = i.step(pos + width)
}
}
- return m.matched
+
+Return:
+ if !matched {
+ freeOnePassMachine(m)
+ return nil
+ }
+
+ dstCap = append(dstCap, m.matchcap...)
+ freeOnePassMachine(m)
+ return dstCap
}
// doMatch reports whether either r, b or s match the regexp.
@@ -442,25 +478,22 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
dstCap = arrayNoInts[:0:0]
}
- if re.onepass == notOnePass && r == nil && len(b)+len(s) < re.maxBitStateLen {
+ if re.onepass != nil {
+ return re.doOnePass(r, b, s, pos, ncap, dstCap)
+ }
+ if r == nil && len(b)+len(s) < re.maxBitStateLen {
return re.backtrack(b, s, pos, ncap, dstCap)
}
m := re.get()
i, _ := m.inputs.init(r, b, s)
- if m.op != notOnePass {
- if !m.onepass(i, pos, ncap) {
- re.put(m)
- return nil
- }
- } else {
- m.init(ncap)
- if !m.match(i, pos) {
- re.put(m)
- return nil
- }
+ m.init(ncap)
+ if !m.match(i, pos) {
+ re.put(m)
+ return nil
}
+
dstCap = append(dstCap, m.matchcap...)
re.put(m)
return dstCap
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 02258e6e74..1489219328 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -684,7 +684,7 @@ func BenchmarkMatch(b *testing.B) {
func BenchmarkMatch_onepass_regex(b *testing.B) {
isRaceBuilder := strings.HasSuffix(testenv.Builder(), "-race")
r := MustCompile(`(?s)\A.*\z`)
- if r.get().op == notOnePass {
+ if r.onepass == nil {
b.Fatalf("want onepass regex, but %q is not onepass", r)
}
for _, size := range benchSizes {
diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go
index 125be59a7d..2f3ce6f9f6 100644
--- a/src/regexp/onepass.go
+++ b/src/regexp/onepass.go
@@ -294,12 +294,12 @@ var anyRune = []rune{0, unicode.MaxRune}
// makeOnePass creates a onepass Prog, if possible. It is possible if at any alt,
// the match engine can always tell which branch to take. The routine may modify
// p if it is turned into a onepass Prog. If it isn't possible for this to be a
-// onepass Prog, the Prog notOnePass is returned. makeOnePass is recursive
+// onepass Prog, the Prog nil is returned. makeOnePass is recursive
// to the size of the Prog.
func makeOnePass(p *onePassProg) *onePassProg {
// If the machine is very long, it's not worth the time to check if we can use one pass.
if len(p.Inst) >= 1000 {
- return notOnePass
+ return nil
}
var (
@@ -446,11 +446,11 @@ func makeOnePass(p *onePassProg) *onePassProg {
visitQueue.clear()
pc := instQueue.next()
if !check(pc, m) {
- p = notOnePass
+ p = nil
break
}
}
- if p != notOnePass {
+ if p != nil {
for i := range p.Inst {
p.Inst[i].Rune = onePassRunes[i]
}
@@ -458,20 +458,18 @@ func makeOnePass(p *onePassProg) *onePassProg {
return p
}
-var notOnePass *onePassProg = nil
-
// compileOnePass returns a new *syntax.Prog suitable for onePass execution if the original Prog
-// can be recharacterized as a one-pass regexp program, or syntax.notOnePass if the
+// can be recharacterized as a one-pass regexp program, or syntax.nil if the
// Prog cannot be converted. For a one pass prog, the fundamental condition that must
// be true is: at any InstAlt, there must be no ambiguity about what branch to take.
func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
if prog.Start == 0 {
- return notOnePass
+ return nil
}
// onepass regexp is anchored
if prog.Inst[prog.Start].Op != syntax.InstEmptyWidth ||
syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
- return notOnePass
+ return nil
}
// every instruction leading to InstMatch must be EmptyEndText
for _, inst := range prog.Inst {
@@ -479,18 +477,18 @@ func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
switch inst.Op {
default:
if opOut == syntax.InstMatch {
- return notOnePass
+ return nil
}
case syntax.InstAlt, syntax.InstAltMatch:
if opOut == syntax.InstMatch || prog.Inst[inst.Arg].Op == syntax.InstMatch {
- return notOnePass
+ return nil
}
case syntax.InstEmptyWidth:
if opOut == syntax.InstMatch {
if syntax.EmptyOp(inst.Arg)&syntax.EmptyEndText == syntax.EmptyEndText {
continue
}
- return notOnePass
+ return nil
}
}
}
@@ -501,7 +499,7 @@ func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
// checkAmbiguity on InstAlts, build onepass Prog if possible
p = makeOnePass(p)
- if p != notOnePass {
+ if p != nil {
cleanupOnePass(p, prog)
}
return p
diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go
index 6b622ac356..a0f2e39048 100644
--- a/src/regexp/onepass_test.go
+++ b/src/regexp/onepass_test.go
@@ -134,47 +134,45 @@ func TestMergeRuneSet(t *testing.T) {
}
}
-var onePass = &onePassProg{}
-
var onePassTests = []struct {
- re string
- onePass *onePassProg
+ re string
+ isOnePass bool
}{
- {`^(?:a|(?:a*))$`, notOnePass},
- {`^(?:(a)|(?:a*))$`, notOnePass},
- {`^(?:(?:(?:.(?:$))?))$`, onePass},
- {`^abcd$`, onePass},
- {`^(?:(?:a{0,})*?)$`, onePass},
- {`^(?:(?:a+)*)$`, onePass},
- {`^(?:(?:a|(?:aa)))$`, onePass},
- {`^(?:[^\s\S])$`, onePass},
- {`^(?:(?:a{3,4}){0,})$`, notOnePass},
- {`^(?:(?:(?:a*)+))$`, onePass},
- {`^[a-c]+$`, onePass},
- {`^[a-c]*$`, onePass},
- {`^(?:a*)$`, onePass},
- {`^(?:(?:aa)|a)$`, onePass},
- {`^[a-c]*`, notOnePass},
- {`^...$`, onePass},
- {`^(?:a|(?:aa))$`, onePass},
- {`^a((b))c$`, onePass},
- {`^a.[l-nA-Cg-j]?e$`, onePass},
- {`^a((b))$`, onePass},
- {`^a(?:(b)|(c))c$`, onePass},
- {`^a(?:(b*)|(c))c$`, notOnePass},
- {`^a(?:b|c)$`, onePass},
- {`^a(?:b?|c)$`, onePass},
- {`^a(?:b?|c?)$`, notOnePass},
- {`^a(?:b?|c+)$`, onePass},
- {`^a(?:b+|(bc))d$`, notOnePass},
- {`^a(?:bc)+$`, onePass},
- {`^a(?:[bcd])+$`, onePass},
- {`^a((?:[bcd])+)$`, onePass},
- {`^a(:?b|c)*d$`, onePass},
- {`^.bc(d|e)*$`, onePass},
- {`^(?:(?:aa)|.)$`, notOnePass},
- {`^(?:(?:a{1,2}){1,2})$`, notOnePass},
- {`^l` + strings.Repeat("o", 2<<8) + `ng$`, onePass},
+ {`^(?:a|(?:a*))$`, false},
+ {`^(?:(a)|(?:a*))$`, false},
+ {`^(?:(?:(?:.(?:$))?))$`, true},
+ {`^abcd$`, true},
+ {`^(?:(?:a{0,})*?)$`, true},
+ {`^(?:(?:a+)*)$`, true},
+ {`^(?:(?:a|(?:aa)))$`, true},
+ {`^(?:[^\s\S])$`, true},
+ {`^(?:(?:a{3,4}){0,})$`, false},
+ {`^(?:(?:(?:a*)+))$`, true},
+ {`^[a-c]+$`, true},
+ {`^[a-c]*$`, true},
+ {`^(?:a*)$`, true},
+ {`^(?:(?:aa)|a)$`, true},
+ {`^[a-c]*`, false},
+ {`^...$`, true},
+ {`^(?:a|(?:aa))$`, true},
+ {`^a((b))c$`, true},
+ {`^a.[l-nA-Cg-j]?e$`, true},
+ {`^a((b))$`, true},
+ {`^a(?:(b)|(c))c$`, true},
+ {`^a(?:(b*)|(c))c$`, false},
+ {`^a(?:b|c)$`, true},
+ {`^a(?:b?|c)$`, true},
+ {`^a(?:b?|c?)$`, false},
+ {`^a(?:b?|c+)$`, true},
+ {`^a(?:b+|(bc))d$`, false},
+ {`^a(?:bc)+$`, true},
+ {`^a(?:[bcd])+$`, true},
+ {`^a((?:[bcd])+)$`, true},
+ {`^a(:?b|c)*d$`, true},
+ {`^.bc(d|e)*$`, true},
+ {`^(?:(?:aa)|.)$`, false},
+ {`^(?:(?:a{1,2}){1,2})$`, false},
+ {`^l` + strings.Repeat("o", 2<<8) + `ng$`, true},
}
func TestCompileOnePass(t *testing.T) {
@@ -194,9 +192,9 @@ func TestCompileOnePass(t *testing.T) {
t.Errorf("Compile(%q) got err:%s, want success", test.re, err)
continue
}
- onePass = compileOnePass(p)
- if (onePass == notOnePass) != (test.onePass == notOnePass) {
- t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass)
+ isOnePass := compileOnePass(p) != nil
+ if isOnePass != test.isOnePass {
+ t.Errorf("CompileOnePass(%q) got isOnePass=%v, expected %v", test.re, isOnePass, test.isOnePass)
}
}
}
@@ -216,8 +214,8 @@ func TestRunOnePass(t *testing.T) {
t.Errorf("Compile(%q): got err: %s", test.re, err)
continue
}
- if re.onepass == notOnePass {
- t.Errorf("Compile(%q): got notOnePass, want one-pass", test.re)
+ if re.onepass == nil {
+ t.Errorf("Compile(%q): got nil, want one-pass", test.re)
continue
}
if !re.MatchString(test.match) {
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index dafcfd433d..3730552c13 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -191,7 +191,7 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
longest: longest,
},
}
- if regexp.onepass == notOnePass {
+ if regexp.onepass == nil {
regexp.prefix, regexp.prefixComplete = prog.Prefix()
regexp.maxBitStateLen = maxBitStateLen(prog)
} else {
@@ -218,7 +218,7 @@ func (re *Regexp) get() *machine {
return z
}
re.mu.Unlock()
- z := progMachine(re.prog, re.onepass)
+ z := progMachine(re.prog)
z.re = re
return z
}
From a376435ae54c404a442d1387256caf09e917c550 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Tue, 2 Oct 2018 10:23:58 -0400
Subject: [PATCH 112/240] regexp: use pools for NFA machines
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Now the machine struct is only used for NFA execution.
Use global pools to cache machines instead of per-Regexp lists.
Also eliminate some tail calls in NFA execution, to pay for
the added overhead of sync.Pool.
name old time/op new time/op delta
Find-12 252ns ± 0% 252ns ± 0% ~ (p=1.000 n=10+10)
FindAllNoMatches-12 134ns ± 1% 136ns ± 4% ~ (p=0.443 n=9+10)
FindString-12 246ns ± 0% 246ns ± 0% -0.16% (p=0.046 n=10+8)
FindSubmatch-12 333ns ± 2% 332ns ± 1% ~ (p=0.489 n=10+9)
FindStringSubmatch-12 320ns ± 0% 321ns ± 1% +0.55% (p=0.005 n=10+9)
Literal-12 91.1ns ± 0% 91.6ns ± 0% +0.55% (p=0.000 n=10+9)
NotLiteral-12 1.45µs ± 0% 1.47µs ± 0% +0.82% (p=0.000 n=10+9)
MatchClass-12 2.19µs ± 0% 2.15µs ± 0% -2.01% (p=0.000 n=9+10)
MatchClass_InRange-12 2.09µs ± 0% 2.09µs ± 0% ~ (p=0.082 n=10+9)
ReplaceAll-12 1.39µs ± 0% 1.40µs ± 0% +0.50% (p=0.000 n=10+10)
AnchoredLiteralShortNonMatch-12 82.4ns ± 0% 83.5ns ± 0% +1.36% (p=0.000 n=8+9)
AnchoredLiteralLongNonMatch-12 106ns ± 1% 101ns ± 0% -4.36% (p=0.000 n=10+10)
AnchoredShortMatch-12 130ns ± 0% 131ns ± 0% +0.77% (p=0.000 n=9+10)
AnchoredLongMatch-12 272ns ± 0% 268ns ± 1% -1.46% (p=0.000 n=8+10)
OnePassShortA-12 615ns ± 0% 614ns ± 0% ~ (p=0.094 n=10+6)
NotOnePassShortA-12 549ns ± 0% 552ns ± 0% +0.52% (p=0.000 n=9+10)
OnePassShortB-12 494ns ± 0% 494ns ± 0% ~ (p=0.247 n=8+9)
NotOnePassShortB-12 412ns ± 1% 411ns ± 0% ~ (p=0.625 n=10+9)
OnePassLongPrefix-12 108ns ± 0% 109ns ± 0% +0.93% (p=0.000 n=10+8)
OnePassLongNotPrefix-12 402ns ± 0% 403ns ± 0% +0.14% (p=0.041 n=8+9)
MatchParallelShared-12 38.6ns ± 2% 38.9ns ± 1% ~ (p=0.172 n=9+10)
MatchParallelCopied-12 39.4ns ± 7% 39.2ns ± 1% ~ (p=0.423 n=10+10)
QuoteMetaAll-12 94.9ns ± 0% 94.5ns ± 0% -0.42% (p=0.000 n=9+10)
QuoteMetaNone-12 52.7ns ± 0% 52.7ns ± 0% ~ (all equal)
Match/Easy0/32-12 72.1ns ± 0% 72.2ns ± 0% ~ (p=0.435 n=9+8)
Match/Easy0/1K-12 298ns ± 0% 296ns ± 1% -1.01% (p=0.000 n=8+10)
Match/Easy0/32K-12 4.64µs ± 1% 4.57µs ± 3% -1.39% (p=0.030 n=10+10)
Match/Easy0/1M-12 234µs ± 0% 234µs ± 0% ~ (p=0.971 n=10+10)
Match/Easy0/32M-12 7.95ms ± 0% 7.96ms ± 0% ~ (p=0.278 n=9+10)
Match/Easy0i/32-12 1.10µs ± 0% 1.09µs ± 0% -0.29% (p=0.000 n=9+8)
Match/Easy0i/1K-12 31.8µs ± 1% 31.7µs ± 0% ~ (p=0.704 n=10+9)
Match/Easy0i/32K-12 1.62ms ± 1% 1.61ms ± 0% -1.12% (p=0.000 n=10+8)
Match/Easy0i/1M-12 51.8ms ± 0% 51.4ms ± 0% -0.84% (p=0.000 n=8+8)
Match/Easy0i/32M-12 1.65s ± 0% 1.65s ± 0% -0.46% (p=0.000 n=9+9)
Match/Easy1/32-12 67.7ns ± 1% 67.6ns ± 1% ~ (p=0.723 n=10+10)
Match/Easy1/1K-12 873ns ± 0% 873ns ± 2% ~ (p=0.345 n=10+9)
Match/Easy1/32K-12 39.4µs ± 0% 39.7µs ± 1% +0.66% (p=0.000 n=10+10)
Match/Easy1/1M-12 1.39ms ± 0% 1.41ms ± 1% +1.10% (p=0.000 n=10+10)
Match/Easy1/32M-12 44.3ms ± 0% 44.9ms ± 1% +1.18% (p=0.000 n=10+10)
Match/Medium/32-12 1.04µs ± 0% 1.04µs ± 0% -0.58% (p=0.000 n=9+9)
Match/Medium/1K-12 31.4µs ± 0% 31.2µs ± 0% -0.62% (p=0.000 n=8+8)
Match/Medium/32K-12 1.45ms ± 0% 1.45ms ± 1% ~ (p=0.356 n=9+10)
Match/Medium/1M-12 46.4ms ± 0% 46.4ms ± 0% ~ (p=0.142 n=8+6)
Match/Medium/32M-12 1.49s ± 1% 1.49s ± 1% ~ (p=0.739 n=10+10)
Match/Hard/32-12 1.48µs ± 0% 1.47µs ± 0% -0.53% (p=0.000 n=9+9)
Match/Hard/1K-12 45.0µs ± 1% 44.5µs ± 1% -1.06% (p=0.000 n=10+10)
Match/Hard/32K-12 2.24ms ± 0% 2.09ms ± 0% -6.56% (p=0.000 n=8+8)
Match/Hard/1M-12 71.6ms ± 0% 67.8ms ± 5% -5.36% (p=0.000 n=7+10)
Match/Hard/32M-12 2.29s ± 0% 2.17s ± 5% -5.40% (p=0.000 n=9+10)
Match/Hard1/32-12 7.89µs ± 0% 7.89µs ± 0% ~ (p=0.053 n=9+9)
Match/Hard1/1K-12 244µs ± 0% 246µs ± 0% +0.71% (p=0.000 n=10+9)
Match/Hard1/32K-12 10.3ms ± 0% 8.9ms ± 0% -13.76% (p=0.000 n=10+9)
Match/Hard1/1M-12 331ms ± 0% 286ms ± 0% -13.72% (p=0.000 n=9+9)
Match/Hard1/32M-12 10.6s ± 0% 9.2s ± 0% -13.72% (p=0.000 n=10+9)
Match_onepass_regex/32-12 830ns ± 0% 825ns ± 0% -0.57% (p=0.000 n=9+8)
Match_onepass_regex/1K-12 28.7µs ± 1% 28.7µs ± 1% -0.22% (p=0.040 n=9+9)
Match_onepass_regex/32K-12 949µs ± 0% 950µs ± 1% ~ (p=0.236 n=8+9)
Match_onepass_regex/1M-12 30.4ms ± 0% 30.4ms ± 0% ~ (p=0.059 n=8+9)
Match_onepass_regex/32M-12 973ms ± 0% 974ms ± 1% ~ (p=0.258 n=9+9)
CompileOnepass-12 4.64µs ± 0% 4.60µs ± 0% -0.90% (p=0.000 n=10+8)
[Geo mean] 23.3µs 23.1µs -1.16%
https://perf.golang.org/search?q=upload:20181004.3
Change-Id: I46f3d52ce89c8cd992cf554473c27af81fd81bfd
Reviewed-on: https://go-review.googlesource.com/c/139781
Run-TryBot: Russ Cox
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/regexp/exec.go | 27 ++++-------
src/regexp/regexp.go | 113 ++++++++++++++++++++++++++-----------------
2 files changed, 77 insertions(+), 63 deletions(-)
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 23908d22d5..e1870021f2 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -92,20 +92,6 @@ func (i *inputs) init(r io.RuneReader, b []byte, s string) (input, int) {
return i.newString(s), len(s)
}
-// progMachine returns a new machine running the prog p.
-func progMachine(p *syntax.Prog) *machine {
- m := &machine{p: p}
- n := len(m.p.Inst)
- m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
- m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
- ncap := p.NumCap
- if ncap < 2 {
- ncap = 2
- }
- m.matchcap = make([]int, ncap)
- return m
-}
-
func (m *machine) init(ncap int) {
for _, t := range m.pool {
t.cap = t.cap[:ncap]
@@ -274,6 +260,7 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
// empty-width conditions satisfied by cond. pos gives the current position
// in the input.
func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp, t *thread) *thread {
+Again:
if pc == 0 {
return t
}
@@ -296,13 +283,16 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
// nothing
case syntax.InstAlt, syntax.InstAltMatch:
t = m.add(q, i.Out, pos, cap, cond, t)
- t = m.add(q, i.Arg, pos, cap, cond, t)
+ pc = i.Arg
+ goto Again
case syntax.InstEmptyWidth:
if syntax.EmptyOp(i.Arg)&^cond == 0 {
- t = m.add(q, i.Out, pos, cap, cond, t)
+ pc = i.Out
+ goto Again
}
case syntax.InstNop:
- t = m.add(q, i.Out, pos, cap, cond, t)
+ pc = i.Out
+ goto Again
case syntax.InstCapture:
if int(i.Arg) < len(cap) {
opos := cap[i.Arg]
@@ -310,7 +300,8 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
m.add(q, i.Out, pos, cap, cond, nil)
cap[i.Arg] = opos
} else {
- t = m.add(q, i.Out, pos, cap, cond, t)
+ pc = i.Out
+ goto Again
}
case syntax.InstMatch, syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
if t == nil {
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 3730552c13..98146031c0 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -79,15 +79,6 @@ import (
// A Regexp is safe for concurrent use by multiple goroutines,
// except for configuration methods, such as Longest.
type Regexp struct {
- // read-only after Compile
- regexpRO
-
- // cache of machines for running regexp
- mu sync.Mutex
- machine []*machine
-}
-
-type regexpRO struct {
expr string // as passed to Compile
prog *syntax.Prog // compiled program
onepass *onePassProg // onepass program or nil
@@ -98,9 +89,14 @@ type regexpRO struct {
prefixBytes []byte // prefix, as a []byte
prefixRune rune // first rune in prefix
prefixEnd uint32 // pc for last rune in prefix
+ mpool int // pool for machines
+ matchcap int // size of recorded match lengths
prefixComplete bool // prefix is the entire regexp
cond syntax.EmptyOp // empty-width conditions required at start of match
- longest bool
+
+ // This field can be modified by the Longest method,
+ // but it is otherwise read-only.
+ longest bool // whether regexp prefers leftmost-longest match
}
// String returns the source text used to compile the regular expression.
@@ -113,11 +109,8 @@ func (re *Regexp) String() string {
// When using a Regexp in multiple goroutines, giving each goroutine
// its own copy helps to avoid lock contention.
func (re *Regexp) Copy() *Regexp {
- // It is not safe to copy Regexp by value
- // since it contains a sync.Mutex.
- return &Regexp{
- regexpRO: re.regexpRO,
- }
+ re2 := *re
+ return &re2
}
// Compile parses a regular expression and returns, if successful,
@@ -180,16 +173,19 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
if err != nil {
return nil, err
}
+ matchcap := prog.NumCap
+ if matchcap < 2 {
+ matchcap = 2
+ }
regexp := &Regexp{
- regexpRO: regexpRO{
- expr: expr,
- prog: prog,
- onepass: compileOnePass(prog),
- numSubexp: maxCap,
- subexpNames: capNames,
- cond: prog.StartCond(),
- longest: longest,
- },
+ expr: expr,
+ prog: prog,
+ onepass: compileOnePass(prog),
+ numSubexp: maxCap,
+ subexpNames: capNames,
+ cond: prog.StartCond(),
+ longest: longest,
+ matchcap: matchcap,
}
if regexp.onepass == nil {
regexp.prefix, regexp.prefixComplete = prog.Prefix()
@@ -203,37 +199,64 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
regexp.prefixBytes = []byte(regexp.prefix)
regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix)
}
+
+ n := len(prog.Inst)
+ i := 0
+ for matchSize[i] != 0 && matchSize[i] < n {
+ i++
+ }
+ regexp.mpool = i
+
return regexp, nil
}
+// Pools of *machine for use during (*Regexp).doExecute,
+// split up by the size of the execution queues.
+// matchPool[i] machines have queue size matchSize[i].
+// On a 64-bit system each queue entry is 16 bytes,
+// so matchPool[0] has 16*2*128 = 4kB queues, etc.
+// The final matchPool is a catch-all for very large queues.
+var (
+ matchSize = [...]int{128, 512, 2048, 16384, 0}
+ matchPool [len(matchSize)]sync.Pool
+)
+
// get returns a machine to use for matching re.
// It uses the re's machine cache if possible, to avoid
// unnecessary allocation.
func (re *Regexp) get() *machine {
- re.mu.Lock()
- if n := len(re.machine); n > 0 {
- z := re.machine[n-1]
- re.machine = re.machine[:n-1]
- re.mu.Unlock()
- return z
+ m, ok := matchPool[re.mpool].Get().(*machine)
+ if !ok {
+ m = new(machine)
}
- re.mu.Unlock()
- z := progMachine(re.prog)
- z.re = re
- return z
+ m.re = re
+ m.p = re.prog
+ if cap(m.matchcap) < re.matchcap {
+ m.matchcap = make([]int, re.matchcap)
+ for _, t := range m.pool {
+ t.cap = make([]int, re.matchcap)
+ }
+ }
+
+ // Allocate queues if needed.
+ // Or reallocate, for "large" match pool.
+ n := matchSize[re.mpool]
+ if n == 0 { // large pool
+ n = len(re.prog.Inst)
+ }
+ if len(m.q0.sparse) < n {
+ m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
+ m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
+ }
+ return m
}
-// put returns a machine to the re's machine cache.
-// There is no attempt to limit the size of the cache, so it will
-// grow to the maximum number of simultaneous matches
-// run using re. (The cache empties when re gets garbage collected.)
-func (re *Regexp) put(z *machine) {
- // Remove references to input data that we no longer need.
- z.inputs.clear()
-
- re.mu.Lock()
- re.machine = append(re.machine, z)
- re.mu.Unlock()
+// put returns a machine to the correct machine pool.
+func (re *Regexp) put(m *machine) {
+ m.re = nil
+ m.p = nil
+ m.inputs.clear()
+ matchPool[re.mpool].Put(m)
}
// MustCompile is like Compile but panics if the expression cannot be parsed.
From 3ca1f28e5425254ec8b73fabeb45a6e49200ee08 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Thu, 4 Oct 2018 10:57:15 -0400
Subject: [PATCH 113/240] regexp: evaluate context flags lazily
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There's no point in computing whether we're at the
beginning of the line if the NFA isn't going to ask.
Wait to compute that until asked.
Whatever minor slowdowns were introduced by
the conversion to pools that were not repaid by
other optimizations are taken care of by this one.
name old time/op new time/op delta
Find-12 252ns ± 0% 260ns ± 0% +3.34% (p=0.000 n=10+8)
FindAllNoMatches-12 136ns ± 4% 134ns ± 4% -0.96% (p=0.033 n=10+10)
FindString-12 246ns ± 0% 250ns ± 0% +1.46% (p=0.000 n=8+10)
FindSubmatch-12 332ns ± 1% 332ns ± 0% ~ (p=0.101 n=9+10)
FindStringSubmatch-12 321ns ± 1% 322ns ± 1% ~ (p=0.717 n=9+10)
Literal-12 91.6ns ± 0% 92.3ns ± 0% +0.74% (p=0.000 n=9+9)
NotLiteral-12 1.47µs ± 0% 1.47µs ± 0% +0.38% (p=0.000 n=9+8)
MatchClass-12 2.15µs ± 0% 2.15µs ± 0% +0.39% (p=0.000 n=10+10)
MatchClass_InRange-12 2.09µs ± 0% 2.11µs ± 0% +0.75% (p=0.000 n=9+9)
ReplaceAll-12 1.40µs ± 0% 1.40µs ± 0% ~ (p=0.525 n=10+10)
AnchoredLiteralShortNonMatch-12 83.5ns ± 0% 81.6ns ± 0% -2.28% (p=0.000 n=9+10)
AnchoredLiteralLongNonMatch-12 101ns ± 0% 97ns ± 1% -3.54% (p=0.000 n=10+10)
AnchoredShortMatch-12 131ns ± 0% 128ns ± 0% -2.29% (p=0.000 n=10+9)
AnchoredLongMatch-12 268ns ± 1% 252ns ± 1% -6.04% (p=0.000 n=10+10)
OnePassShortA-12 614ns ± 0% 587ns ± 1% -4.33% (p=0.000 n=6+10)
NotOnePassShortA-12 552ns ± 0% 547ns ± 1% -0.89% (p=0.000 n=10+10)
OnePassShortB-12 494ns ± 0% 455ns ± 0% -7.96% (p=0.000 n=9+9)
NotOnePassShortB-12 411ns ± 0% 406ns ± 0% -1.30% (p=0.000 n=9+9)
OnePassLongPrefix-12 109ns ± 0% 108ns ± 1% ~ (p=0.064 n=8+9)
OnePassLongNotPrefix-12 403ns ± 0% 349ns ± 0% -13.30% (p=0.000 n=9+8)
MatchParallelShared-12 38.9ns ± 1% 37.9ns ± 1% -2.65% (p=0.000 n=10+8)
MatchParallelCopied-12 39.2ns ± 1% 38.3ns ± 2% -2.20% (p=0.001 n=10+10)
QuoteMetaAll-12 94.5ns ± 0% 94.7ns ± 0% +0.18% (p=0.043 n=10+9)
QuoteMetaNone-12 52.7ns ± 0% 52.7ns ± 0% ~ (all equal)
Match/Easy0/32-12 72.2ns ± 0% 71.9ns ± 0% -0.38% (p=0.009 n=8+10)
Match/Easy0/1K-12 296ns ± 1% 297ns ± 0% +0.51% (p=0.001 n=10+9)
Match/Easy0/32K-12 4.57µs ± 3% 4.61µs ± 2% ~ (p=0.280 n=10+10)
Match/Easy0/1M-12 234µs ± 0% 234µs ± 0% ~ (p=0.986 n=10+10)
Match/Easy0/32M-12 7.96ms ± 0% 7.98ms ± 0% +0.22% (p=0.010 n=10+9)
Match/Easy0i/32-12 1.09µs ± 0% 1.10µs ± 0% +0.23% (p=0.000 n=8+9)
Match/Easy0i/1K-12 31.7µs ± 0% 31.7µs ± 0% +0.09% (p=0.003 n=9+8)
Match/Easy0i/32K-12 1.61ms ± 0% 1.27ms ± 1% -21.03% (p=0.000 n=8+10)
Match/Easy0i/1M-12 51.4ms ± 0% 40.4ms ± 0% -21.29% (p=0.000 n=8+8)
Match/Easy0i/32M-12 1.65s ± 0% 1.30s ± 1% -21.22% (p=0.000 n=9+9)
Match/Easy1/32-12 67.6ns ± 1% 67.2ns ± 0% ~ (p=0.085 n=10+9)
Match/Easy1/1K-12 873ns ± 2% 880ns ± 0% +0.78% (p=0.006 n=9+7)
Match/Easy1/32K-12 39.7µs ± 1% 34.3µs ± 3% -13.53% (p=0.000 n=10+10)
Match/Easy1/1M-12 1.41ms ± 1% 1.19ms ± 3% -15.48% (p=0.000 n=10+10)
Match/Easy1/32M-12 44.9ms ± 1% 38.0ms ± 2% -15.21% (p=0.000 n=10+10)
Match/Medium/32-12 1.04µs ± 0% 1.03µs ± 0% -0.57% (p=0.000 n=9+9)
Match/Medium/1K-12 31.2µs ± 0% 31.4µs ± 1% +0.61% (p=0.000 n=8+10)
Match/Medium/32K-12 1.45ms ± 1% 1.20ms ± 0% -17.70% (p=0.000 n=10+8)
Match/Medium/1M-12 46.4ms ± 0% 38.4ms ± 2% -17.32% (p=0.000 n=6+9)
Match/Medium/32M-12 1.49s ± 1% 1.24s ± 1% -16.81% (p=0.000 n=10+10)
Match/Hard/32-12 1.47µs ± 0% 1.47µs ± 0% -0.31% (p=0.000 n=9+10)
Match/Hard/1K-12 44.5µs ± 1% 44.4µs ± 0% ~ (p=0.075 n=10+10)
Match/Hard/32K-12 2.09ms ± 0% 1.78ms ± 7% -14.88% (p=0.000 n=8+10)
Match/Hard/1M-12 67.8ms ± 5% 56.9ms ± 7% -16.05% (p=0.000 n=10+10)
Match/Hard/32M-12 2.17s ± 5% 1.84s ± 6% -15.21% (p=0.000 n=10+10)
Match/Hard1/32-12 7.89µs ± 0% 7.94µs ± 0% +0.61% (p=0.000 n=9+9)
Match/Hard1/1K-12 246µs ± 0% 245µs ± 0% -0.30% (p=0.010 n=9+10)
Match/Hard1/32K-12 8.93ms ± 0% 8.17ms ± 0% -8.44% (p=0.000 n=9+8)
Match/Hard1/1M-12 286ms ± 0% 269ms ± 9% -5.66% (p=0.028 n=9+10)
Match/Hard1/32M-12 9.16s ± 0% 8.61s ± 8% -5.98% (p=0.028 n=9+10)
Match_onepass_regex/32-12 825ns ± 0% 712ns ± 0% -13.75% (p=0.000 n=8+8)
Match_onepass_regex/1K-12 28.7µs ± 1% 19.8µs ± 0% -30.99% (p=0.000 n=9+8)
Match_onepass_regex/32K-12 950µs ± 1% 628µs ± 0% -33.83% (p=0.000 n=9+8)
Match_onepass_regex/1M-12 30.4ms ± 0% 20.1ms ± 0% -33.74% (p=0.000 n=9+8)
Match_onepass_regex/32M-12 974ms ± 1% 646ms ± 0% -33.73% (p=0.000 n=9+8)
CompileOnepass-12 4.60µs ± 0% 4.59µs ± 0% ~ (p=0.063 n=8+9)
[Geo mean] 23.1µs 21.3µs -7.44%
https://perf.golang.org/search?q=upload:20181004.4
Change-Id: I47cdd09f6dcde1d7c317080e9b4df42c7d0a8d24
Reviewed-on: https://go-review.googlesource.com/c/139782
Run-TryBot: Russ Cox
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/regexp/backtrack.go | 3 +-
src/regexp/exec.go | 81 ++++++++++++++++++++++++++++++++++-------
src/regexp/regexp.go | 14 +++----
3 files changed, 77 insertions(+), 21 deletions(-)
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
index 239abc3a57..9fb7d1e493 100644
--- a/src/regexp/backtrack.go
+++ b/src/regexp/backtrack.go
@@ -257,7 +257,8 @@ func (re *Regexp) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
}
case syntax.InstEmptyWidth:
- if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 {
+ flag := i.context(pos)
+ if !flag.match(syntax.EmptyOp(inst.Arg)) {
continue
}
pc = inst.Out
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index e1870021f2..efe764e2dc 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -114,6 +114,61 @@ func (m *machine) alloc(i *syntax.Inst) *thread {
return t
}
+// A lazyFlag is a lazily-evaluated syntax.EmptyOp,
+// for checking zero-width flags like ^ $ \A \z \B \b.
+// It records the pair of relevant runes and does not
+// determine the implied flags until absolutely necessary
+// (most of the time, that means never).
+type lazyFlag uint64
+
+func newLazyFlag(r1, r2 rune) lazyFlag {
+ return lazyFlag(uint64(r1)<<32 | uint64(uint32(r2)))
+}
+
+func (f lazyFlag) match(op syntax.EmptyOp) bool {
+ if op == 0 {
+ return true
+ }
+ r1 := rune(f >> 32)
+ if op&syntax.EmptyBeginLine != 0 {
+ if r1 != '\n' && r1 >= 0 {
+ return false
+ }
+ op &^= syntax.EmptyBeginLine
+ }
+ if op&syntax.EmptyBeginText != 0 {
+ if r1 >= 0 {
+ return false
+ }
+ op &^= syntax.EmptyBeginText
+ }
+ if op == 0 {
+ return true
+ }
+ r2 := rune(f)
+ if op&syntax.EmptyEndLine != 0 {
+ if r2 != '\n' && r2 >= 0 {
+ return false
+ }
+ op &^= syntax.EmptyEndLine
+ }
+ if op&syntax.EmptyEndText != 0 {
+ if r2 >= 0 {
+ return false
+ }
+ op &^= syntax.EmptyEndText
+ }
+ if op == 0 {
+ return true
+ }
+ if syntax.IsWordChar(r1) != syntax.IsWordChar(r2) {
+ op &^= syntax.EmptyWordBoundary
+ } else {
+ op &^= syntax.EmptyNoWordBoundary
+ }
+ return op == 0
+}
+
// match runs the machine over the input starting at pos.
// It reports whether a match was found.
// If so, m.matchcap holds the submatch information.
@@ -133,9 +188,9 @@ func (m *machine) match(i input, pos int) bool {
if r != endOfText {
r1, width1 = i.step(pos + width)
}
- var flag syntax.EmptyOp
+ var flag lazyFlag
if pos == 0 {
- flag = syntax.EmptyOpContext(-1, r)
+ flag = newLazyFlag(-1, r)
} else {
flag = i.context(pos)
}
@@ -164,10 +219,10 @@ func (m *machine) match(i input, pos int) bool {
if len(m.matchcap) > 0 {
m.matchcap[0] = pos
}
- m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag, nil)
+ m.add(runq, uint32(m.p.Start), pos, m.matchcap, &flag, nil)
}
- flag = syntax.EmptyOpContext(r, r1)
- m.step(runq, nextq, pos, pos+width, r, flag)
+ flag = newLazyFlag(r, r1)
+ m.step(runq, nextq, pos, pos+width, r, &flag)
if width == 0 {
break
}
@@ -202,7 +257,7 @@ func (m *machine) clear(q *queue) {
// The step processes the rune c (which may be endOfText),
// which starts at position pos and ends at nextPos.
// nextCond gives the setting for the empty-width flags after c.
-func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond syntax.EmptyOp) {
+func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond *lazyFlag) {
longest := m.re.longest
for j := 0; j < len(runq.dense); j++ {
d := &runq.dense[j]
@@ -259,7 +314,7 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
// It also recursively adds an entry for all instructions reachable from pc by following
// empty-width conditions satisfied by cond. pos gives the current position
// in the input.
-func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp, t *thread) *thread {
+func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond *lazyFlag, t *thread) *thread {
Again:
if pc == 0 {
return t
@@ -286,7 +341,7 @@ Again:
pc = i.Arg
goto Again
case syntax.InstEmptyWidth:
- if syntax.EmptyOp(i.Arg)&^cond == 0 {
+ if cond.match(syntax.EmptyOp(i.Arg)) {
pc = i.Out
goto Again
}
@@ -365,16 +420,16 @@ func (re *Regexp) doOnePass(ir io.RuneReader, ib []byte, is string, pos, ncap in
if r != endOfText {
r1, width1 = i.step(pos + width)
}
- var flag syntax.EmptyOp
+ var flag lazyFlag
if pos == 0 {
- flag = syntax.EmptyOpContext(-1, r)
+ flag = newLazyFlag(-1, r)
} else {
flag = i.context(pos)
}
pc := re.onepass.Start
inst := re.onepass.Inst[pc]
// If there is a simple literal prefix, skip over it.
- if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 &&
+ if pos == 0 && flag.match(syntax.EmptyOp(inst.Arg)) &&
len(re.prefix) > 0 && i.canCheckPrefix() {
// Match requires literal prefix; fast search for it.
if !i.hasPrefix(re) {
@@ -422,7 +477,7 @@ func (re *Regexp) doOnePass(ir io.RuneReader, ib []byte, is string, pos, ncap in
case syntax.InstNop:
continue
case syntax.InstEmptyWidth:
- if syntax.EmptyOp(inst.Arg)&^flag != 0 {
+ if !flag.match(syntax.EmptyOp(inst.Arg)) {
goto Return
}
continue
@@ -435,7 +490,7 @@ func (re *Regexp) doOnePass(ir io.RuneReader, ib []byte, is string, pos, ncap in
if width == 0 {
break
}
- flag = syntax.EmptyOpContext(r, r1)
+ flag = newLazyFlag(r, r1)
pos += width
r, width = r1, width1
if r != endOfText {
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 98146031c0..3586029555 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -311,7 +311,7 @@ type input interface {
canCheckPrefix() bool // can we look ahead without losing info?
hasPrefix(re *Regexp) bool
index(re *Regexp, pos int) int
- context(pos int) syntax.EmptyOp
+ context(pos int) lazyFlag
}
// inputString scans a string.
@@ -342,7 +342,7 @@ func (i *inputString) index(re *Regexp, pos int) int {
return strings.Index(i.str[pos:], re.prefix)
}
-func (i *inputString) context(pos int) syntax.EmptyOp {
+func (i *inputString) context(pos int) lazyFlag {
r1, r2 := endOfText, endOfText
// 0 < pos && pos <= len(i.str)
if uint(pos-1) < uint(len(i.str)) {
@@ -358,7 +358,7 @@ func (i *inputString) context(pos int) syntax.EmptyOp {
r2, _ = utf8.DecodeRuneInString(i.str[pos:])
}
}
- return syntax.EmptyOpContext(r1, r2)
+ return newLazyFlag(r1, r2)
}
// inputBytes scans a byte slice.
@@ -389,7 +389,7 @@ func (i *inputBytes) index(re *Regexp, pos int) int {
return bytes.Index(i.str[pos:], re.prefixBytes)
}
-func (i *inputBytes) context(pos int) syntax.EmptyOp {
+func (i *inputBytes) context(pos int) lazyFlag {
r1, r2 := endOfText, endOfText
// 0 < pos && pos <= len(i.str)
if uint(pos-1) < uint(len(i.str)) {
@@ -405,7 +405,7 @@ func (i *inputBytes) context(pos int) syntax.EmptyOp {
r2, _ = utf8.DecodeRune(i.str[pos:])
}
}
- return syntax.EmptyOpContext(r1, r2)
+ return newLazyFlag(r1, r2)
}
// inputReader scans a RuneReader.
@@ -441,8 +441,8 @@ func (i *inputReader) index(re *Regexp, pos int) int {
return -1
}
-func (i *inputReader) context(pos int) syntax.EmptyOp {
- return 0
+func (i *inputReader) context(pos int) lazyFlag {
+ return 0 // not used
}
// LiteralPrefix returns a literal string that must begin any match
From 5160e0d18cace12a40c9c271bc0072915f3f9295 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Fri, 28 Sep 2018 13:19:27 -0400
Subject: [PATCH 114/240] regexp: add DeepEqual test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This locks in behavior we accidentally broke
and then restored during the Go 1.11 cycle.
See #26219.
It also locks in new behavior that DeepEqual
always works, instead of only usually working.
This CL is the final piece of a series of CLs to make
DeepEqual always work, by eliminating the machine
cache and making other related optimizations.
Overall, this whole sequence of CLs achieves:
name old time/op new time/op delta
Find-12 264ns ± 3% 260ns ± 0% -1.59% (p=0.000 n=10+9)
FindAllNoMatches-12 140ns ± 2% 133ns ± 0% -5.34% (p=0.000 n=10+7)
FindString-12 256ns ± 0% 249ns ± 0% -2.73% (p=0.000 n=8+8)
FindSubmatch-12 339ns ± 1% 333ns ± 1% -1.73% (p=0.000 n=9+10)
FindStringSubmatch-12 322ns ± 0% 322ns ± 1% ~ (p=0.450 n=8+10)
Literal-12 100ns ± 2% 92ns ± 0% -8.13% (p=0.000 n=10+10)
NotLiteral-12 1.50µs ± 0% 1.47µs ± 0% -1.65% (p=0.000 n=8+8)
MatchClass-12 2.18µs ± 0% 2.15µs ± 0% -1.05% (p=0.000 n=10+9)
MatchClass_InRange-12 2.12µs ± 0% 2.11µs ± 0% -0.65% (p=0.000 n=10+9)
ReplaceAll-12 1.41µs ± 0% 1.41µs ± 0% ~ (p=0.254 n=7+10)
AnchoredLiteralShortNonMatch-12 89.8ns ± 0% 81.5ns ± 0% -9.22% (p=0.000 n=8+9)
AnchoredLiteralLongNonMatch-12 105ns ± 3% 97ns ± 0% -7.21% (p=0.000 n=10+10)
AnchoredShortMatch-12 141ns ± 0% 128ns ± 0% -9.22% (p=0.000 n=9+9)
AnchoredLongMatch-12 276ns ± 4% 253ns ± 2% -8.23% (p=0.000 n=10+10)
OnePassShortA-12 620ns ± 0% 587ns ± 0% -5.26% (p=0.000 n=10+6)
NotOnePassShortA-12 575ns ± 3% 547ns ± 1% -4.77% (p=0.000 n=10+10)
OnePassShortB-12 493ns ± 0% 455ns ± 0% -7.62% (p=0.000 n=8+9)
NotOnePassShortB-12 423ns ± 0% 406ns ± 1% -3.95% (p=0.000 n=8+10)
OnePassLongPrefix-12 112ns ± 0% 109ns ± 1% -2.77% (p=0.000 n=9+10)
OnePassLongNotPrefix-12 405ns ± 0% 349ns ± 0% -13.74% (p=0.000 n=8+9)
MatchParallelShared-12 501ns ± 1% 38ns ± 2% -92.42% (p=0.000 n=10+10)
MatchParallelCopied-12 39.1ns ± 0% 38.6ns ± 1% -1.38% (p=0.002 n=6+10)
QuoteMetaAll-12 94.6ns ± 0% 94.8ns ± 0% +0.26% (p=0.001 n=10+9)
QuoteMetaNone-12 52.7ns ± 0% 52.7ns ± 0% ~ (all equal)
Match/Easy0/32-12 79.1ns ± 0% 72.0ns ± 0% -8.95% (p=0.000 n=9+9)
Match/Easy0/1K-12 307ns ± 1% 297ns ± 0% -3.32% (p=0.000 n=10+7)
Match/Easy0/32K-12 4.65µs ± 2% 4.67µs ± 1% ~ (p=0.633 n=10+8)
Match/Easy0/1M-12 234µs ± 0% 234µs ± 0% ~ (p=0.684 n=10+10)
Match/Easy0/32M-12 7.98ms ± 1% 7.96ms ± 0% -0.31% (p=0.014 n=9+9)
Match/Easy0i/32-12 1.13µs ± 1% 1.10µs ± 0% -3.18% (p=0.000 n=9+10)
Match/Easy0i/1K-12 32.5µs ± 0% 31.7µs ± 0% -2.61% (p=0.000 n=9+9)
Match/Easy0i/32K-12 1.59ms ± 0% 1.26ms ± 0% -20.71% (p=0.000 n=9+7)
Match/Easy0i/1M-12 51.0ms ± 0% 40.4ms ± 0% -20.68% (p=0.000 n=10+7)
Match/Easy0i/32M-12 1.63s ± 0% 1.30s ± 0% -20.62% (p=0.001 n=7+7)
Match/Easy1/32-12 75.1ns ± 1% 67.4ns ± 0% -10.24% (p=0.000 n=8+10)
Match/Easy1/1K-12 861ns ± 0% 879ns ± 0% +2.18% (p=0.000 n=8+8)
Match/Easy1/32K-12 39.2µs ± 1% 34.1µs ± 0% -13.01% (p=0.000 n=10+8)
Match/Easy1/1M-12 1.38ms ± 0% 1.17ms ± 0% -15.06% (p=0.000 n=10+8)
Match/Easy1/32M-12 44.2ms ± 1% 37.5ms ± 0% -15.15% (p=0.000 n=10+9)
Match/Medium/32-12 1.04µs ± 1% 1.03µs ± 0% -0.64% (p=0.002 n=9+8)
Match/Medium/1K-12 31.3µs ± 0% 31.2µs ± 0% -0.36% (p=0.000 n=9+9)
Match/Medium/32K-12 1.44ms ± 0% 1.20ms ± 0% -17.02% (p=0.000 n=8+7)
Match/Medium/1M-12 46.1ms ± 0% 38.2ms ± 0% -17.14% (p=0.001 n=6+8)
Match/Medium/32M-12 1.48s ± 0% 1.23s ± 0% -17.10% (p=0.000 n=9+7)
Match/Hard/32-12 1.54µs ± 1% 1.47µs ± 0% -4.64% (p=0.000 n=9+10)
Match/Hard/1K-12 46.4µs ± 1% 44.4µs ± 0% -4.35% (p=0.000 n=9+8)
Match/Hard/32K-12 2.19ms ± 0% 1.78ms ± 7% -18.74% (p=0.000 n=8+10)
Match/Hard/1M-12 70.1ms ± 0% 57.7ms ± 7% -17.62% (p=0.000 n=8+10)
Match/Hard/32M-12 2.24s ± 0% 1.84s ± 8% -17.92% (p=0.000 n=8+10)
Match/Hard1/32-12 8.17µs ± 1% 7.95µs ± 0% -2.72% (p=0.000 n=8+10)
Match/Hard1/1K-12 254µs ± 2% 245µs ± 0% -3.62% (p=0.000 n=9+10)
Match/Hard1/32K-12 9.58ms ± 1% 8.54ms ± 7% -10.87% (p=0.000 n=10+10)
Match/Hard1/1M-12 306ms ± 1% 271ms ± 8% -11.42% (p=0.000 n=9+10)
Match/Hard1/32M-12 9.79s ± 1% 8.58s ± 9% -12.37% (p=0.000 n=9+10)
Match_onepass_regex/32-12 808ns ± 0% 716ns ± 1% -11.39% (p=0.000 n=8+9)
Match_onepass_regex/1K-12 27.8µs ± 0% 19.9µs ± 2% -28.51% (p=0.000 n=8+9)
Match_onepass_regex/32K-12 925µs ± 0% 631µs ± 2% -31.71% (p=0.000 n=9+9)
Match_onepass_regex/1M-12 29.5ms ± 0% 20.2ms ± 2% -31.53% (p=0.000 n=10+9)
Match_onepass_regex/32M-12 945ms ± 0% 648ms ± 2% -31.39% (p=0.000 n=9+9)
CompileOnepass-12 4.67µs ± 0% 4.60µs ± 0% -1.48% (p=0.000 n=10+10)
[Geo mean] 24.5µs 21.4µs -12.94%
https://perf.golang.org/search?q=upload:20181004.5
Change-Id: Icb17b306830dc5489efbb55900937b94ce0eb047
Reviewed-on: https://go-review.googlesource.com/c/139783
Run-TryBot: Russ Cox
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/regexp/all_test.go | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index 8cbc2962cb..623f82df72 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -859,3 +859,26 @@ func BenchmarkQuoteMetaNone(b *testing.B) {
sink = QuoteMeta(s)
}
}
+
+func TestDeepEqual(t *testing.T) {
+ re1 := MustCompile("a.*b.*c.*d")
+ re2 := MustCompile("a.*b.*c.*d")
+ if !reflect.DeepEqual(re1, re2) { // has always been true, since Go 1.
+ t.Errorf("DeepEqual(re1, re2) = false, want true")
+ }
+
+ re1.MatchString("abcdefghijklmn")
+ if !reflect.DeepEqual(re1, re2) {
+ t.Errorf("DeepEqual(re1, re2) = false, want true")
+ }
+
+ re2.MatchString("abcdefghijklmn")
+ if !reflect.DeepEqual(re1, re2) {
+ t.Errorf("DeepEqual(re1, re2) = false, want true")
+ }
+
+ re2.MatchString(strings.Repeat("abcdefghijklmn", 100))
+ if !reflect.DeepEqual(re1, re2) {
+ t.Errorf("DeepEqual(re1, re2) = false, want true")
+ }
+}
From bf68744a122b83f44cc454417d5723be04215091 Mon Sep 17 00:00:00 2001
From: Russ Cox
Date: Fri, 28 Sep 2018 15:17:24 -0400
Subject: [PATCH 115/240] regexp: add partial Deprecation comment to Copy
Change-Id: I21b7817e604a48330f1ee250f7b1b2adc1f16067
Reviewed-on: https://go-review.googlesource.com/c/139784
Run-TryBot: Russ Cox
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/regexp/regexp.go | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 3586029555..38b3c86d9f 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -105,9 +105,13 @@ func (re *Regexp) String() string {
}
// Copy returns a new Regexp object copied from re.
+// Calling Longest on one copy does not affect another.
//
-// When using a Regexp in multiple goroutines, giving each goroutine
-// its own copy helps to avoid lock contention.
+// Deprecated: In earlier releases, when using a Regexp in multiple goroutines,
+// giving each goroutine its own copy helped to avoid lock contention.
+// As of Go 1.12, using Copy is no longer necessary to avoid lock contention.
+// Copy may still be appropriate if the reason for its use is to make
+// two copies with different Longest settings.
func (re *Regexp) Copy() *Regexp {
re2 := *re
return &re2
From 57456527560c63a5baef8b7e99eab5508ca58e63 Mon Sep 17 00:00:00 2001
From: Mak Kolybabi
Date: Fri, 12 Oct 2018 21:43:48 +0000
Subject: [PATCH 116/240] doc: fix spelling of `comp[]hensive` to
`comp[r]ehensive`
Change-Id: Idd93e45fab30e7496105b84fc2fce1884711b580
GitHub-Last-Rev: 43aa04e876655e31fc1c4b2b5ae0702472e49102
GitHub-Pull-Request: golang/go#27983
Reviewed-on: https://go-review.googlesource.com/c/141645
Reviewed-by: Ian Lance Taylor
---
doc/editors.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/editors.html b/doc/editors.html
index 6f787864c6..4ff35a58fc 100644
--- a/doc/editors.html
+++ b/doc/editors.html
@@ -28,7 +28,7 @@ or as a plugin for IntelliJ IDEA Ultimate
-Note that these are only a few top solutions; a more comphensive
+Note that these are only a few top solutions; a more comprehensive
community-maintained list of
IDEs and text editor plugins
is available at the Wiki.
From b4150f76144808bf0015fe23be0e2ade32a14599 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Fri, 12 Oct 2018 14:55:17 -0700
Subject: [PATCH 117/240] cmd/compile: remove ineffectual -i flag
This flag lost its usefulness in CL 34273.
Change-Id: I033c29f105937139b4e359a340906be439f1ed07
Reviewed-on: https://go-review.googlesource.com/c/141646
Run-TryBot: Matthew Dempsky
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/main.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 68f6294724..02aec32685 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -207,7 +207,6 @@ func Main(archInit func(*Arch)) {
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
objabi.Flagcount("f", "debug stack frames", &Debug['f'])
objabi.Flagcount("h", "halt on error", &Debug['h'])
- objabi.Flagcount("i", "debug line number stack", &Debug['i'])
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
From c4f07510a0161c4493a751984e24532a1b189759 Mon Sep 17 00:00:00 2001
From: Ivan Sharavuev
Date: Sat, 13 Oct 2018 13:14:39 +0300
Subject: [PATCH 118/240] strings: Replace s[:] to s where s is a slice.
Change-Id: Ie7ba3f9ece9b0fc0e8a5c92fbae9c3b558815e4c
Reviewed-on: https://go-review.googlesource.com/c/141997
Run-TryBot: Iskander Sharipov
TryBot-Result: Gobot Gobot
Reviewed-by: Iskander Sharipov
---
src/strings/replace.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/strings/replace.go b/src/strings/replace.go
index 9ddf5e1e3f..ace0b8d646 100644
--- a/src/strings/replace.go
+++ b/src/strings/replace.go
@@ -459,7 +459,7 @@ func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) {
buf := make([]byte, bufsize)
for len(s) > 0 {
- ncopy := copy(buf, s[:])
+ ncopy := copy(buf, s)
s = s[ncopy:]
for i, b := range buf[:ncopy] {
buf[i] = r[b]
From e489a236b40febae0c2df0462ae8dd6cffdd3646 Mon Sep 17 00:00:00 2001
From: avsharapov
Date: Sat, 13 Oct 2018 13:31:39 +0300
Subject: [PATCH 119/240] jpeg: simplify 'x = x op ...' to 'x op= ...'
Change-Id: Id431969e42f0d9bd28bbf163d10378a6de2416f2
Reviewed-on: https://go-review.googlesource.com/c/141999
Run-TryBot: Iskander Sharipov
TryBot-Result: Gobot Gobot
Reviewed-by: Iskander Sharipov
---
src/image/jpeg/fdct.go | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/image/jpeg/fdct.go b/src/image/jpeg/fdct.go
index 3f8be4e326..201a5abd0b 100644
--- a/src/image/jpeg/fdct.go
+++ b/src/image/jpeg/fdct.go
@@ -123,14 +123,14 @@ func fdct(b *block) {
tmp13 = tmp1 + tmp3
z1 = (tmp12 + tmp13) * fix_1_175875602
z1 += 1 << (constBits - pass1Bits - 1)
- tmp0 = tmp0 * fix_1_501321110
- tmp1 = tmp1 * fix_3_072711026
- tmp2 = tmp2 * fix_2_053119869
- tmp3 = tmp3 * fix_0_298631336
- tmp10 = tmp10 * -fix_0_899976223
- tmp11 = tmp11 * -fix_2_562915447
- tmp12 = tmp12 * -fix_0_390180644
- tmp13 = tmp13 * -fix_1_961570560
+ tmp0 *= fix_1_501321110
+ tmp1 *= fix_3_072711026
+ tmp2 *= fix_2_053119869
+ tmp3 *= fix_0_298631336
+ tmp10 *= -fix_0_899976223
+ tmp11 *= -fix_2_562915447
+ tmp12 *= -fix_0_390180644
+ tmp13 *= -fix_1_961570560
tmp12 += z1
tmp13 += z1
@@ -171,14 +171,14 @@ func fdct(b *block) {
tmp13 = tmp1 + tmp3
z1 = (tmp12 + tmp13) * fix_1_175875602
z1 += 1 << (constBits + pass1Bits - 1)
- tmp0 = tmp0 * fix_1_501321110
- tmp1 = tmp1 * fix_3_072711026
- tmp2 = tmp2 * fix_2_053119869
- tmp3 = tmp3 * fix_0_298631336
- tmp10 = tmp10 * -fix_0_899976223
- tmp11 = tmp11 * -fix_2_562915447
- tmp12 = tmp12 * -fix_0_390180644
- tmp13 = tmp13 * -fix_1_961570560
+ tmp0 *= fix_1_501321110
+ tmp1 *= fix_3_072711026
+ tmp2 *= fix_2_053119869
+ tmp3 *= fix_0_298631336
+ tmp10 *= -fix_0_899976223
+ tmp11 *= -fix_2_562915447
+ tmp12 *= -fix_0_390180644
+ tmp13 *= -fix_1_961570560
tmp12 += z1
tmp13 += z1
From 4330866385c2edfd56a0a3c6136db1d034e4712a Mon Sep 17 00:00:00 2001
From: OlgaVlPetrova
Date: Sat, 13 Oct 2018 14:06:30 +0300
Subject: [PATCH 120/240] debug/plan9obj: simplify s[:] to s where
Change-Id: Ib2eee1215ba046e4541af8afa3a921c680d2b37e
Reviewed-on: https://go-review.googlesource.com/c/142037
Run-TryBot: Iskander Sharipov
TryBot-Result: Gobot Gobot
Reviewed-by: Iskander Sharipov
---
src/debug/plan9obj/file.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/debug/plan9obj/file.go b/src/debug/plan9obj/file.go
index c78e35d000..314608da61 100644
--- a/src/debug/plan9obj/file.go
+++ b/src/debug/plan9obj/file.go
@@ -274,7 +274,7 @@ func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
ts.Value = s.value
switch s.typ {
default:
- ts.Name = string(s.name[:])
+ ts.Name = string(s.name)
case 'z', 'Z':
for i := 0; i < len(s.name); i += 2 {
eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
From df459d5e6cc14532961875058f5d4ba3d04b5ed4 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Sat, 13 Oct 2018 15:48:17 -0700
Subject: [PATCH 121/240] cmd/compile: emit symbol for constant string before
parallel compiler phase
This CL makes sure we walk the newly generated assignment. Part of
that walk makes sure that all symbols for strings are emitted before
we start referencing them during the parallel compilation
phase. Without this change, those references during the parallel phase
do a create-if-not-exist, which leads to a data race.
I'm not 100% sure this is the fix for the issues below, but optimistically
assuming it is...
Fixes #28170
Fixes #28159
Change-Id: Ic63d5160ad9be5cb23fa6bbb2183e4848776c0ff
Reviewed-on: https://go-review.googlesource.com/c/141648
Run-TryBot: Keith Randall
Reviewed-by: Josh Bleecher Snyder
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/gc/walk.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 6b9ec51203..d33674f221 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -1460,7 +1460,9 @@ opswitch:
as := nod(OAS,
nod(OIND, p, nil),
nod(OIND, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil))
- init.Append(typecheck(as, Etop))
+ as = typecheck(as, Etop)
+ as = walkstmt(as)
+ init.Append(as)
}
// Slice the [n]byte to a []byte.
From 653a4bd8d46a8a329f37e8a9fc909c3bb92b02bc Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Tue, 9 Oct 2018 22:55:36 -0700
Subject: [PATCH 122/240] cmd/compile: optimize loads from readonly globals
into constants
Instead of
MOVB go.string."foo"(SB), AX
do
MOVB $102, AX
When we know the global we're loading from is readonly, we can
do that read at compile time.
I've made this arch-dependent mostly because the cases where this
happens often are memory->memory moves, and those don't get
decomposed until lowering.
Did amd64/386/arm/arm64. Other architectures could follow.
Update #26498
Change-Id: I41b1dc831b2cd0a52dac9b97f4f4457888a46389
Reviewed-on: https://go-review.googlesource.com/c/141118
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Josh Bleecher Snyder
---
src/cmd/compile/internal/ssa/gen/386.rules | 4 +
src/cmd/compile/internal/ssa/gen/AMD64.rules | 11 +-
src/cmd/compile/internal/ssa/gen/ARM.rules | 4 +
src/cmd/compile/internal/ssa/gen/ARM64.rules | 5 +
src/cmd/compile/internal/ssa/rewrite.go | 44 ++++
src/cmd/compile/internal/ssa/rewrite386.go | 54 +++++
src/cmd/compile/internal/ssa/rewriteAMD64.go | 215 ++++++++++++++++---
src/cmd/compile/internal/ssa/rewriteARM.go | 54 +++++
src/cmd/compile/internal/ssa/rewriteARM64.go | 72 +++++++
test/codegen/strings.go | 27 +++
10 files changed, 459 insertions(+), 31 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index 0df8911f39..7a6797bb09 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -1206,3 +1206,7 @@
(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int32(c)),off) -> (CMPLconstload {sym} [makeValAndOff(int64(int32(c)),off)] ptr mem)
(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int16(c)),off) -> (CMPWconstload {sym} [makeValAndOff(int64(int16(c)),off)] ptr mem)
(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int8(c)),off) -> (CMPBconstload {sym} [makeValAndOff(int64(int8(c)),off)] ptr mem)
+
+(MOVBload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVLconst [int64(read8(sym, off))])
+(MOVWload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVLconst [int64(read16(sym, off, config.BigEndian))])
+(MOVLload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVLconst [int64(int32(read32(sym, off, config.BigEndian)))])
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index f9ac5e4dce..fa7f1438d6 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -1073,11 +1073,11 @@
// Fold constants into stores.
(MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) && validValAndOff(c,off) ->
(MOVQstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
-(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+(MOVLstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) && validOff(off) ->
(MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
-(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+(MOVWstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) && validOff(off) ->
(MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
-(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+(MOVBstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) && validOff(off) ->
(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
// Fold address offsets into constant stores.
@@ -2487,3 +2487,8 @@
&& validValAndOff(0,off)
&& clobber(l) ->
@l.Block (CMP(Q|L|W|B)constload {sym} [makeValAndOff(0,off)] ptr mem)
+
+(MOVBload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVLconst [int64(read8(sym, off))])
+(MOVWload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVLconst [int64(read16(sym, off, config.BigEndian))])
+(MOVLload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVQconst [int64(read32(sym, off, config.BigEndian))])
+(MOVQload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVQconst [int64(read64(sym, off, config.BigEndian))])
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index fdf4d1e900..8b0e82f154 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -1544,3 +1544,7 @@
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRAreg x y z) yes no)
+
+(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read8(sym, off))])
+(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read16(sym, off, config.BigEndian))])
+(MOVWload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(int32(read32(sym, off, config.BigEndian)))])
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 659081ec8b..1efce66016 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -2957,3 +2957,8 @@
(FSUBD a (FNMULD x y)) -> (FMADDD a x y)
(FSUBS (FNMULS x y) a) -> (FNMADDS a x y)
(FSUBD (FNMULD x y) a) -> (FNMADDD a x y)
+
+(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVDconst [int64(read8(sym, off))])
+(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVDconst [int64(read16(sym, off, config.BigEndian))])
+(MOVWUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVDconst [int64(read32(sym, off, config.BigEndian))])
+(MOVDload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVDconst [int64(read64(sym, off, config.BigEndian))])
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index fd5f684eda..b93dce2004 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -7,7 +7,9 @@ package ssa
import (
"cmd/compile/internal/types"
"cmd/internal/obj"
+ "cmd/internal/objabi"
"cmd/internal/src"
+ "encoding/binary"
"fmt"
"io"
"math"
@@ -1090,3 +1092,45 @@ func needRaceCleanup(sym interface{}, v *Value) bool {
}
return true
}
+
+// symIsRO reports whether sym is a read-only global.
+func symIsRO(sym interface{}) bool {
+ lsym := sym.(*obj.LSym)
+ return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
+}
+
+// read8 reads one byte from the read-only global sym at offset off.
+func read8(sym interface{}, off int64) uint8 {
+ lsym := sym.(*obj.LSym)
+ return lsym.P[off]
+}
+
+// read16 reads two bytes from the read-only global sym at offset off.
+func read16(sym interface{}, off int64, bigEndian bool) uint16 {
+ lsym := sym.(*obj.LSym)
+ if bigEndian {
+ return binary.BigEndian.Uint16(lsym.P[off:])
+ } else {
+ return binary.LittleEndian.Uint16(lsym.P[off:])
+ }
+}
+
+// read32 reads four bytes from the read-only global sym at offset off.
+func read32(sym interface{}, off int64, bigEndian bool) uint32 {
+ lsym := sym.(*obj.LSym)
+ if bigEndian {
+ return binary.BigEndian.Uint32(lsym.P[off:])
+ } else {
+ return binary.LittleEndian.Uint32(lsym.P[off:])
+ }
+}
+
+// read64 reads eight bytes from the read-only global sym at offset off.
+func read64(sym interface{}, off int64, bigEndian bool) uint64 {
+ lsym := sym.(*obj.LSym)
+ if bigEndian {
+ return binary.BigEndian.Uint64(lsym.P[off:])
+ } else {
+ return binary.LittleEndian.Uint64(lsym.P[off:])
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 3fb820933c..9b2ec74a9d 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -5242,6 +5242,24 @@ func rewriteValue386_Op386MOVBload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVLconst [int64(read8(sym, off))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = int64(read8(sym, off))
+ return true
+ }
return false
}
func rewriteValue386_Op386MOVBloadidx1_0(v *Value) bool {
@@ -6530,6 +6548,24 @@ func rewriteValue386_Op386MOVLload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVLconst [int64(int32(read32(sym, off, config.BigEndian)))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = int64(int32(read32(sym, off, config.BigEndian)))
+ return true
+ }
return false
}
func rewriteValue386_Op386MOVLloadidx1_0(v *Value) bool {
@@ -10259,6 +10295,24 @@ func rewriteValue386_Op386MOVWload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVLconst [int64(read16(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = int64(read16(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValue386_Op386MOVWloadidx1_0(v *Value) bool {
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 89fc6780b9..e89ed9edb6 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -268,7 +268,7 @@ func rewriteValueAMD64(v *Value) bool {
case OpAMD64MOVLi2f:
return rewriteValueAMD64_OpAMD64MOVLi2f_0(v)
case OpAMD64MOVLload:
- return rewriteValueAMD64_OpAMD64MOVLload_0(v)
+ return rewriteValueAMD64_OpAMD64MOVLload_0(v) || rewriteValueAMD64_OpAMD64MOVLload_10(v)
case OpAMD64MOVLloadidx1:
return rewriteValueAMD64_OpAMD64MOVLloadidx1_0(v)
case OpAMD64MOVLloadidx4:
@@ -12446,6 +12446,24 @@ func rewriteValueAMD64_OpAMD64MOVBload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVLconst [int64(read8(sym, off))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = int64(read8(sym, off))
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVBloadidx1_0(v *Value) bool {
@@ -12953,6 +12971,30 @@ func rewriteValueAMD64_OpAMD64MOVBstore_10(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstore [off] {sym} ptr (MOVQconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconst)
+ v.AuxInt = makeValAndOff(int64(int8(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVBstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
@@ -13181,6 +13223,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore_10(v *Value) bool {
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstore_20(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
// match: (MOVBstore [i] {s} p w x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w) x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w) x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w) x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w) x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w) x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w) x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
// cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clobber(x6)
// result: (MOVQstore [i-7] {s} p (BSWAPQ w) mem)
@@ -13372,13 +13421,6 @@ func rewriteValueAMD64_OpAMD64MOVBstore_10(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVBstore_20(v *Value) bool {
- b := v.Block
- _ = b
- typ := &b.Func.Config.Types
- _ = typ
// match: (MOVBstore [i] {s} p (SHRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstore [i-1] {s} p w mem)
@@ -15449,6 +15491,31 @@ func rewriteValueAMD64_OpAMD64MOVLload_0(v *Value) bool {
}
return false
}
+func rewriteValueAMD64_OpAMD64MOVLload_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
+ // match: (MOVLload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVQconst [int64(read32(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = int64(read32(sym, off, config.BigEndian))
+ return true
+ }
+ return false
+}
func rewriteValueAMD64_OpAMD64MOVLloadidx1_0(v *Value) bool {
// match: (MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
// cond:
@@ -15957,6 +16024,30 @@ func rewriteValueAMD64_OpAMD64MOVLstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVLstore [off] {sym} ptr (MOVQconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = makeValAndOff(int64(int32(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVLstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
@@ -16102,6 +16193,13 @@ func rewriteValueAMD64_OpAMD64MOVLstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
// match: (MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVQstore [i-4] {s} p w mem)
@@ -16147,13 +16245,6 @@ func rewriteValueAMD64_OpAMD64MOVLstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
- b := v.Block
- _ = b
- typ := &b.Func.Config.Types
- _ = typ
// match: (MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVQstore [i-4] {s} p w0 mem)
@@ -16519,6 +16610,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstore_20(v *Value) bool {
// match: (MOVLstore {sym} [off] ptr y:(ADDL x l:(MOVLload [off] {sym} ptr mem)) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
// result: (ADDLmodify [off] {sym} ptr x mem)
@@ -16562,9 +16656,6 @@ func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVLstore_20(v *Value) bool {
// match: (MOVLstore {sym} [off] ptr y:(SUBL l:(MOVLload [off] {sym} ptr mem) x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
// result: (SUBLmodify [off] {sym} ptr x mem)
@@ -16952,6 +17043,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore_20(v *Value) bool {
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstore_30(v *Value) bool {
// match: (MOVLstore {sym} [off] ptr y:(BTSL l:(MOVLload [off] {sym} ptr mem) x) mem)
// cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l)
// result: (BTSLmodify [off] {sym} ptr x mem)
@@ -16995,9 +17089,6 @@ func rewriteValueAMD64_OpAMD64MOVLstore_20(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVLstore_30(v *Value) bool {
// match: (MOVLstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem)
// cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) && clobber(l) && clobber(a)
// result: (ADDLconstmodify {sym} [makeValAndOff(c,off)] ptr mem)
@@ -18481,6 +18572,10 @@ func rewriteValueAMD64_OpAMD64MOVQi2f_0(v *Value) bool {
return false
}
func rewriteValueAMD64_OpAMD64MOVQload_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
// match: (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: x
@@ -18713,6 +18808,24 @@ func rewriteValueAMD64_OpAMD64MOVQload_0(v *Value) bool {
v.AddArg(val)
return true
}
+ // match: (MOVQload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVQconst [int64(read64(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = int64(read64(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVQloadidx1_0(v *Value) bool {
@@ -22529,6 +22642,10 @@ func rewriteValueAMD64_OpAMD64MOVWQZX_0(v *Value) bool {
return false
}
func rewriteValueAMD64_OpAMD64MOVWload_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
// result: (MOVWQZX x)
@@ -22733,6 +22850,24 @@ func rewriteValueAMD64_OpAMD64MOVWload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVLconst [int64(read16(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = int64(read16(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64MOVWloadidx1_0(v *Value) bool {
@@ -23114,6 +23249,30 @@ func rewriteValueAMD64_OpAMD64MOVWstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWstore [off] {sym} ptr (MOVQconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = makeValAndOff(int64(int16(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVWstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
@@ -23274,6 +23433,13 @@ func rewriteValueAMD64_OpAMD64MOVWstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstore_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
// match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVLstore [i-2] {s} p w mem)
@@ -23319,13 +23485,6 @@ func rewriteValueAMD64_OpAMD64MOVWstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWstore_10(v *Value) bool {
- b := v.Block
- _ = b
- typ := &b.Func.Config.Types
- _ = typ
// match: (MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVLstore [i-2] {s} p w0 mem)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 966413ab25..4f6f61544e 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -6883,6 +6883,24 @@ func rewriteValueARM_OpARMMOVBUload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBUload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVWconst [int64(read8(sym, off))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(read8(sym, off))
+ return true
+ }
return false
}
func rewriteValueARM_OpARMMOVBUloadidx_0(v *Value) bool {
@@ -7953,6 +7971,24 @@ func rewriteValueARM_OpARMMOVHUload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVHUload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVWconst [int64(read16(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(read16(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueARM_OpARMMOVHUloadidx_0(v *Value) bool {
@@ -8797,6 +8833,24 @@ func rewriteValueARM_OpARMMOVWload_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVWload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVWconst [int64(int32(read32(sym, off, config.BigEndian)))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(read32(sym, off, config.BigEndian)))
+ return true
+ }
return false
}
func rewriteValueARM_OpARMMOVWloadidx_0(v *Value) bool {
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index ba38ae0505..b9bb109b9e 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -8934,6 +8934,24 @@ func rewriteValueARM64_OpARM64MOVBUload_0(v *Value) bool {
v.AuxInt = 0
return true
}
+ // match: (MOVBUload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVDconst [int64(read8(sym, off))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(read8(sym, off))
+ return true
+ }
return false
}
func rewriteValueARM64_OpARM64MOVBUloadidx_0(v *Value) bool {
@@ -12638,6 +12656,24 @@ func rewriteValueARM64_OpARM64MOVDload_0(v *Value) bool {
v.AuxInt = 0
return true
}
+ // match: (MOVDload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVDconst [int64(read64(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(read64(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueARM64_OpARM64MOVDloadidx_0(v *Value) bool {
@@ -13563,6 +13599,24 @@ func rewriteValueARM64_OpARM64MOVHUload_0(v *Value) bool {
v.AuxInt = 0
return true
}
+ // match: (MOVHUload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVDconst [int64(read16(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(read16(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueARM64_OpARM64MOVHUloadidx_0(v *Value) bool {
@@ -16183,6 +16237,24 @@ func rewriteValueARM64_OpARM64MOVWUload_0(v *Value) bool {
v.AuxInt = 0
return true
}
+ // match: (MOVWUload [off] {sym} (SB) _)
+ // cond: symIsRO(sym)
+ // result: (MOVDconst [int64(read32(sym, off, config.BigEndian))])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpSB {
+ break
+ }
+ if !(symIsRO(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(read32(sym, off, config.BigEndian))
+ return true
+ }
return false
}
func rewriteValueARM64_OpARM64MOVWUloadidx_0(v *Value) bool {
diff --git a/test/codegen/strings.go b/test/codegen/strings.go
index f4adfac0cc..39ee2e8b9f 100644
--- a/test/codegen/strings.go
+++ b/test/codegen/strings.go
@@ -20,3 +20,30 @@ func ToByteSlice() []byte { // Issue #24698
// amd64:-`.*runtime.stringtoslicebyte`
return []byte("foo")
}
+
+// Loading from read-only symbols should get transformed into constants.
+func ConstantLoad() {
+ // 12592 = 0x3130
+ // 50 = 0x32
+ // amd64:`MOVW\t\$12592, \(`,`MOVB\t\$50, 2\(`
+ // 386:`MOVW\t\$12592, \(`,`MOVB\t\$50, 2\(`
+ // arm:`MOVW\t\$48`,`MOVW\t\$49`,`MOVW\t\$50`
+ // arm64:`MOVD\t\$12592`,`MOVD\t\$50`
+ bsink = []byte("012")
+
+ // 858927408 = 0x33323130
+ // 13620 = 0x3534
+ // amd64:`MOVL\t\$858927408`,`MOVW\t\$13620, 4\(`
+ // 386:`MOVL\t\$858927408`,`MOVW\t\$13620, 4\(`
+ // arm64:`MOVD\t\$858927408`,`MOVD\t\$13620`
+ bsink = []byte("012345")
+
+ // 3978425819141910832 = 0x3736353433323130
+ // 7306073769690871863 = 0x6564636261393837
+ // amd64:`MOVQ\t\$3978425819141910832`,`MOVQ\t\$7306073769690871863`
+ // 386:`MOVL\t\$858927408, \(`,`DUFFCOPY`
+ // arm64:`MOVD\t\$3978425819141910832`,`MOVD\t\$1650538808`,`MOVD\t\$25699`,`MOVD\t\$101`
+ bsink = []byte("0123456789abcde")
+}
+
+var bsink []byte
From 0e9f8a21f8b6534931f1ab50909161a289a0da3c Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Fri, 14 Sep 2018 10:09:08 -0700
Subject: [PATCH 123/240] runtime,cmd/compile: pass strings and slices to
convT2{E,I} by value
When we pass these types by reference, we usually have to allocate
temporaries on the stack, initialize them, then pass their address
to the conversion functions. It's simpler to pass these types
directly by value.
This particularly applies to conversions needed for fmt.Printf
(to interface{} for constructing a [...]interface{}).
func f(a, b, c string) {
fmt.Printf("%s %s\n", a, b)
fmt.Printf("%s %s\n", b, c)
}
This function's stack frame shrinks from 200 to 136 bytes, and
its code shrinks from 535 to 453 bytes.
The go binary shrinks 0.3%.
Update #24286
Aside: for this function f, we don't really need to allocate
temporaries for the convT2E function. We could use the address
of a, b, and c directly. That might get similar (or maybe better?)
improvements. I investigated a bit, but it seemed complicated
to do it safely. This change was much easier.
Change-Id: I78cbe51b501fb41e1e324ce4203f0de56a1db82d
Reviewed-on: https://go-review.googlesource.com/c/135377
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Josh Bleecher Snyder
---
src/cmd/compile/internal/gc/builtin.go | 8 +--
.../compile/internal/gc/builtin/runtime.go | 8 +--
src/cmd/compile/internal/gc/order.go | 13 +++--
src/cmd/compile/internal/gc/walk.go | 8 +--
src/runtime/iface.go | 58 ++++++-------------
test/fixedbugs/issue20250.go | 4 +-
test/live.go | 8 +--
7 files changed, 45 insertions(+), 62 deletions(-)
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index ec8f1093b6..8051c7d0df 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -55,15 +55,15 @@ var runtimeDecls = [...]struct {
{"convT2E16", funcTag, 52},
{"convT2E32", funcTag, 52},
{"convT2E64", funcTag, 52},
- {"convT2Estring", funcTag, 53},
- {"convT2Eslice", funcTag, 53},
+ {"convT2Estring", funcTag, 52},
+ {"convT2Eslice", funcTag, 52},
{"convT2Enoptr", funcTag, 53},
{"convT2I", funcTag, 53},
{"convT2I16", funcTag, 52},
{"convT2I32", funcTag, 52},
{"convT2I64", funcTag, 52},
- {"convT2Istring", funcTag, 53},
- {"convT2Islice", funcTag, 53},
+ {"convT2Istring", funcTag, 52},
+ {"convT2Islice", funcTag, 52},
{"convT2Inoptr", funcTag, 53},
{"assertE2I", funcTag, 52},
{"assertE2I2", funcTag, 54},
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 140b7f3b2d..028936b875 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -68,16 +68,16 @@ func convT2E(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 convT2Estring(typ *byte, val any) (ret any) // val must be a string
+func convT2Eslice(typ *byte, val any) (ret any) // val must be a slice
func convT2Enoptr(typ *byte, elem *any) (ret any)
func convT2I(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 convT2Istring(tab *byte, val any) (ret any) // val must be a string
+func convT2Islice(tab *byte, val any) (ret any) // val must be a slice
func convT2Inoptr(tab *byte, elem *any) (ret any)
// interface type assertions x.(T)
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 8afb136515..fbc05b95d2 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1042,12 +1042,17 @@ func (o *Order) expr(n, lhs *Node) *Node {
n = o.copyExpr(n, n.Type, false)
}
- // concrete type (not interface) argument must be addressable
- // temporary to pass to runtime.
+ // concrete type (not interface) argument might need an addressable
+ // temporary to pass to the runtime conversion routine.
case OCONVIFACE:
n.Left = o.expr(n.Left, nil)
-
- if !n.Left.Type.IsInterface() {
+ if n.Left.Type.IsInterface() {
+ break
+ }
+ if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || consttype(n.Left) > 0 {
+ // Need a temp if we need to pass the address to the conversion function.
+ // We also process constants here, making a named static global whose
+ // address we can put directly in an interface (see OCONVIFACE case in walk).
n.Left = o.addrTemp(n.Left)
}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index d33674f221..f7676310e9 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -417,9 +417,9 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
return "convT2E64", false
case from.IsString():
- return "convT2Estring", true
+ return "convT2Estring", false
case from.IsSlice():
- return "convT2Eslice", true
+ return "convT2Eslice", false
case !types.Haspointers(from):
return "convT2Enoptr", true
}
@@ -433,9 +433,9 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
return "convT2I64", false
case from.IsString():
- return "convT2Istring", true
+ return "convT2Istring", false
case from.IsSlice():
- return "convT2Islice", true
+ return "convT2Islice", false
case !types.Haspointers(from):
return "convT2Inoptr", true
}
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 7ab731151e..1ef9825a48 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -329,38 +329,27 @@ func convT2E64(t *_type, val uint64) (e eface) {
return
}
-func convT2Estring(t *_type, elem unsafe.Pointer) (e eface) {
- if raceenabled {
- raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Estring))
- }
- if msanenabled {
- msanread(elem, t.size)
- }
+func convT2Estring(t *_type, val string) (e eface) {
var x unsafe.Pointer
- if *(*string)(elem) == "" {
+ if val == "" {
x = unsafe.Pointer(&zeroVal[0])
} else {
- x = mallocgc(t.size, t, true)
- *(*string)(x) = *(*string)(elem)
+ x = mallocgc(unsafe.Sizeof(val), t, true)
+ *(*string)(x) = val
}
e._type = t
e.data = x
return
}
-func convT2Eslice(t *_type, elem unsafe.Pointer) (e eface) {
- if raceenabled {
- raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Eslice))
- }
- if msanenabled {
- msanread(elem, t.size)
- }
+func convT2Eslice(t *_type, val []byte) (e eface) {
+ // Note: this must work for any element type, not just byte.
var x unsafe.Pointer
- if v := *(*slice)(elem); uintptr(v.array) == 0 {
+ if (*slice)(unsafe.Pointer(&val)).array == nil {
x = unsafe.Pointer(&zeroVal[0])
} else {
- x = mallocgc(t.size, t, true)
- *(*slice)(x) = *(*slice)(elem)
+ x = mallocgc(unsafe.Sizeof(val), t, true)
+ *(*[]byte)(x) = val
}
e._type = t
e.data = x
@@ -438,40 +427,29 @@ func convT2I64(tab *itab, val uint64) (i iface) {
return
}
-func convT2Istring(tab *itab, elem unsafe.Pointer) (i iface) {
+func convT2Istring(tab *itab, val string) (i iface) {
t := tab._type
- if raceenabled {
- raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Istring))
- }
- if msanenabled {
- msanread(elem, t.size)
- }
var x unsafe.Pointer
- if *(*string)(elem) == "" {
+ if val == "" {
x = unsafe.Pointer(&zeroVal[0])
} else {
- x = mallocgc(t.size, t, true)
- *(*string)(x) = *(*string)(elem)
+ x = mallocgc(unsafe.Sizeof(val), t, true)
+ *(*string)(x) = val
}
i.tab = tab
i.data = x
return
}
-func convT2Islice(tab *itab, elem unsafe.Pointer) (i iface) {
+func convT2Islice(tab *itab, val []byte) (i iface) {
+ // Note: this must work for any element type, not just byte.
t := tab._type
- if raceenabled {
- raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2Islice))
- }
- if msanenabled {
- msanread(elem, t.size)
- }
var x unsafe.Pointer
- if v := *(*slice)(elem); uintptr(v.array) == 0 {
+ if (*slice)(unsafe.Pointer(&val)).array == nil {
x = unsafe.Pointer(&zeroVal[0])
} else {
- x = mallocgc(t.size, t, true)
- *(*slice)(x) = *(*slice)(elem)
+ x = mallocgc(unsafe.Sizeof(val), t, true)
+ *(*[]byte)(x) = val
}
i.tab = tab
i.data = x
diff --git a/test/fixedbugs/issue20250.go b/test/fixedbugs/issue20250.go
index 47879385d2..c190515274 100644
--- a/test/fixedbugs/issue20250.go
+++ b/test/fixedbugs/issue20250.go
@@ -11,13 +11,13 @@
package p
type T struct {
- s string
+ s [2]string
}
func f(a T) { // ERROR "live at entry to f: a"
var e interface{} // ERROR "stack object e interface \{\}$"
func() { // ERROR "live at entry to f.func1: a &e"
- e = a.s // ERROR "live at call to convT2Estring: &e" "stack object a T$"
+ e = a.s // ERROR "live at call to convT2E: &e" "stack object a T$"
}()
// Before the fix, both a and e were live at the previous line.
_ = e
diff --git a/test/live.go b/test/live.go
index 679562d9bf..ba50f5b779 100644
--- a/test/live.go
+++ b/test/live.go
@@ -141,7 +141,7 @@ var i9 interface{}
func f9() bool {
g8()
x := i9
- y := interface{}(str()) // ERROR "live at call to convT2Estring: x.data$" "live at call to str: x.data$" "stack object .autotmp_[0-9]+ string$"
+ y := interface{}(g18()) // ERROR "live at call to convT2E: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
i9 = y // make y escape so the line above has to call convT2E
return x != y
}
@@ -493,13 +493,13 @@ func f30(b bool) {
func f31(b1, b2, b3 bool) {
if b1 {
- g31(str()) // ERROR "stack object .autotmp_[0-9]+ string$"
+ g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
if b2 {
- h31(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ string$"
+ h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ \[2\]string$"
}
if b3 {
- panic(str()) // ERROR "stack object .autotmp_[0-9]+ string$"
+ panic(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
print(b3)
}
From 389e942745ddd7eef44b71571c463b0dfc3dcac2 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Fri, 5 Oct 2018 08:54:50 -0700
Subject: [PATCH 124/240] cmd/compile: reuse temporaries in order pass
Instead of allocating a new temporary each time one
is needed, keep a list of temporaries which are free
(have already been VARKILLed on every path) and use
one of them.
Should save a lot of stack space. In a function like this:
func main() {
fmt.Printf("%d %d\n", 2, 3)
fmt.Printf("%d %d\n", 4, 5)
fmt.Printf("%d %d\n", 6, 7)
}
The three [2]interface{} arrays used to hold the ... args
all use the same autotmp, instead of 3 different autotmps
as happened previous to this CL.
Change-Id: I2d728e226f81e05ae68ca8247af62014a1b032d3
Reviewed-on: https://go-review.googlesource.com/c/140301
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/cmd/compile/internal/gc/order.go | 60 +++++++++++++++++++++-------
src/cmd/compile/internal/gc/sinit.go | 6 +--
test/live.go | 48 +++++++++++-----------
test/uintptrescapes2.go | 4 +-
4 files changed, 75 insertions(+), 43 deletions(-)
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index fbc05b95d2..519fad4b7e 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -42,8 +42,9 @@ import (
// Order holds state during the ordering process.
type Order struct {
- out []*Node // list of generated statements
- temp []*Node // stack of temporary variables
+ out []*Node // list of generated statements
+ temp []*Node // stack of temporary variables
+ free map[string][]*Node // free list of unused temporaries, by type.LongString().
}
// Order rewrites fn.Nbody to apply the ordering constraints
@@ -54,14 +55,30 @@ func order(fn *Node) {
dumplist(s, fn.Nbody)
}
- orderBlock(&fn.Nbody)
+ orderBlock(&fn.Nbody, map[string][]*Node{})
}
// newTemp allocates a new temporary with the given type,
// pushes it onto the temp stack, and returns it.
// If clear is true, newTemp emits code to zero the temporary.
func (o *Order) newTemp(t *types.Type, clear bool) *Node {
- v := temp(t)
+ var v *Node
+ // Note: LongString is close to the type equality we want,
+ // but not exactly. We still need to double-check with eqtype.
+ key := t.LongString()
+ a := o.free[key]
+ for i, n := range a {
+ if eqtype(t, n.Type) {
+ v = a[i]
+ a[i] = a[len(a)-1]
+ a = a[:len(a)-1]
+ o.free[key] = a
+ break
+ }
+ }
+ if v == nil {
+ v = temp(t)
+ }
if clear {
a := nod(OAS, v, nil)
a = typecheck(a, Etop)
@@ -226,6 +243,16 @@ func (o *Order) markTemp() ordermarker {
// Poptemp pops temporaries off the stack until reaching the mark,
// which must have been returned by marktemp.
func (o *Order) popTemp(mark ordermarker) {
+ for _, n := range o.temp[mark:] {
+ if n.Type.Etype == types.TUINT8 {
+ // Don't recycle temps of this type. TUINT8 is used
+ // as a placeholder for a type to be determined later.
+ // TODO: fix
+ continue
+ }
+ key := n.Type.LongString()
+ o.free[key] = append(o.free[key], n)
+ }
o.temp = o.temp[:mark]
}
@@ -266,8 +293,10 @@ func (o *Order) stmtList(l Nodes) {
// orderBlock orders the block of statements in n into a new slice,
// and then replaces the old slice in n with the new slice.
-func orderBlock(n *Nodes) {
+// free is a map that can be used to obtain temporary variables by type.
+func orderBlock(n *Nodes, free map[string][]*Node) {
var order Order
+ order.free = free
mark := order.markTemp()
order.stmtList(*n)
order.cleanTemp(mark)
@@ -280,6 +309,7 @@ func orderBlock(n *Nodes) {
// n.Left = o.exprInPlace(n.Left)
func (o *Order) exprInPlace(n *Node) *Node {
var order Order
+ order.free = o.free
n = order.expr(n, nil)
n = addinit(n, order.out)
@@ -293,8 +323,10 @@ func (o *Order) exprInPlace(n *Node) *Node {
// and replaces it with the resulting statement list.
// The result of orderStmtInPlace MUST be assigned back to n, e.g.
// n.Left = orderStmtInPlace(n.Left)
-func orderStmtInPlace(n *Node) *Node {
+// free is a map that can be used to obtain temporary variables by type.
+func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
var order Order
+ order.free = free
mark := order.markTemp()
order.stmt(n)
order.cleanTemp(mark)
@@ -643,8 +675,8 @@ func (o *Order) stmt(n *Node) {
t := o.markTemp()
n.Left = o.exprInPlace(n.Left)
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
- orderBlock(&n.Nbody)
- n.Right = orderStmtInPlace(n.Right)
+ orderBlock(&n.Nbody, o.free)
+ n.Right = orderStmtInPlace(n.Right, o.free)
o.out = append(o.out, n)
o.cleanTemp(t)
@@ -656,8 +688,8 @@ func (o *Order) stmt(n *Node) {
n.Nbody.Prepend(o.cleanTempNoPop(t)...)
n.Rlist.Prepend(o.cleanTempNoPop(t)...)
o.popTemp(t)
- orderBlock(&n.Nbody)
- orderBlock(&n.Rlist)
+ orderBlock(&n.Nbody, o.free)
+ orderBlock(&n.Rlist, o.free)
o.out = append(o.out, n)
// Special: argument will be converted to interface using convT2E
@@ -739,7 +771,7 @@ func (o *Order) stmt(n *Node) {
}
o.exprListInPlace(n.List)
if orderBody {
- orderBlock(&n.Nbody)
+ orderBlock(&n.Nbody, o.free)
}
o.out = append(o.out, n)
o.cleanTemp(t)
@@ -857,7 +889,7 @@ func (o *Order) stmt(n *Node) {
tmp2 = typecheck(tmp2, Etop)
n2.Ninit.Append(tmp2)
}
- orderBlock(&n2.Ninit)
+ orderBlock(&n2.Ninit, o.free)
case OSEND:
if r.Ninit.Len() != 0 {
@@ -882,7 +914,7 @@ func (o *Order) stmt(n *Node) {
// Also insert any ninit queued during the previous loop.
// (The temporary cleaning must follow that ninit work.)
for _, n3 := range n.List.Slice() {
- orderBlock(&n3.Nbody)
+ orderBlock(&n3.Nbody, o.free)
n3.Nbody.Prepend(o.cleanTempNoPop(t)...)
// TODO(mdempsky): Is this actually necessary?
@@ -924,7 +956,7 @@ func (o *Order) stmt(n *Node) {
Fatalf("order switch case %v", ncas.Op)
}
o.exprListInPlace(ncas.List)
- orderBlock(&ncas.Nbody)
+ orderBlock(&ncas.Nbody, o.free)
}
o.out = append(o.out, n)
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 9d1114fa43..d520f21e63 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -751,7 +751,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
case initKindStatic:
genAsStatic(a)
case initKindDynamic, initKindLocalCode:
- a = orderStmtInPlace(a)
+ a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
default:
@@ -909,7 +909,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
a = nod(OAS, a, value)
a = typecheck(a, Etop)
- a = orderStmtInPlace(a)
+ a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
}
@@ -918,7 +918,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
a = nod(OAS, var_, nod(OSLICE, vauto, nil))
a = typecheck(a, Etop)
- a = orderStmtInPlace(a)
+ a = orderStmtInPlace(a, map[string][]*Node{})
a = walkstmt(a)
init.Append(a)
}
diff --git a/test/live.go b/test/live.go
index ba50f5b779..6367cab96f 100644
--- a/test/live.go
+++ b/test/live.go
@@ -256,8 +256,8 @@ func f16() {
if b {
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
}
- delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
- delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
+ delete(mi, iface())
+ delete(mi, iface())
}
var m2s map[string]*byte
@@ -302,8 +302,8 @@ func f18() {
if b {
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
- z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
- z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
+ z = m2[g18()]
+ z = m2[g18()]
printbytepointer(z)
}
@@ -319,8 +319,8 @@ func f19() {
if b {
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
}
- z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
- z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$" "live at call to chanrecv1: .autotmp_[0-9]+$"
+ z = <-ch
+ z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
printbytepointer(z)
}
@@ -329,8 +329,8 @@ func f20() {
if b {
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
}
- ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
- ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
+ ch <- byteptr()
+ ch <- byteptr()
}
func f21() {
@@ -339,8 +339,8 @@ func f21() {
if b {
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
- z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
- z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
+ z = m2[[2]string{"x", "y"}]
+ z = m2[[2]string{"x", "y"}]
printbytepointer(z)
}
@@ -351,8 +351,8 @@ func f23() {
if b {
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
- z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
- z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
+ z, ok = m2[[2]string{"x", "y"}]
+ z, ok = m2[[2]string{"x", "y"}]
printbytepointer(z)
print(ok)
}
@@ -363,8 +363,8 @@ func f24() {
if b {
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
- m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
- m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
+ m2[[2]string{"x", "y"}] = nil
+ m2[[2]string{"x", "y"}] = nil
}
// defer should not cause spurious ambiguously live variables
@@ -389,8 +389,8 @@ func f26(b bool) {
if b {
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
}
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
+ print26((*int)(nil), (*int)(nil), (*int)(nil))
+ print26((*int)(nil), (*int)(nil), (*int)(nil))
printnl()
}
@@ -442,8 +442,8 @@ func f28(b bool) {
if b {
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
}
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
+ printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
+ printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
}
// map iterator should die on end of range loop
@@ -454,10 +454,10 @@ func f29(b bool) {
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
- for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
+ for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
- for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
+ for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
@@ -481,10 +481,10 @@ func f30(b bool) {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
}
- for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
+ for _, p := range pstructarr {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
- for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
+ for _, p := range pstructarr {
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
}
}
@@ -496,10 +496,10 @@ func f31(b1, b2, b3 bool) {
g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
}
if b2 {
- h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ \[2\]string$"
+ h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
}
if b3 {
- panic(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
+ panic(g18())
}
print(b3)
}
diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go
index e7b5d721f5..2c8dfd7102 100644
--- a/test/uintptrescapes2.go
+++ b/test/uintptrescapes2.go
@@ -32,12 +32,12 @@ func G() {
var t int // ERROR "moved to heap"
F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
var t2 int // ERROR "moved to heap"
- F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
+ F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap"
}
func H() {
var v int // ERROR "moved to heap"
F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
var v2 int // ERROR "moved to heap"
- F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
+ F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap"
}
From c3208842e138a4dd51499ca84b3bdba99ac4d413 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Mon, 15 Oct 2018 02:25:10 +0000
Subject: [PATCH 125/240] test/codegen: add tests for
multiplication-subtraction
This CL adds tests for armv7's MULS and arm64's MSUBW.
Change-Id: Id0fd5d26fd477e4ed14389b0d33cad930423eb5b
Reviewed-on: https://go-review.googlesource.com/c/141651
Run-TryBot: Ben Shi
Reviewed-by: Cherry Zhang
TryBot-Result: Gobot Gobot
---
test/codegen/arithmetic.go | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index 879aaf285c..b1cdef6eee 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -227,3 +227,16 @@ func MULA(a, b, c uint32) (uint32, uint32, uint32) {
r2 := b*64 + c
return r0, r1, r2
}
+
+func MULS(a, b, c uint32) (uint32, uint32, uint32) {
+ // arm/7:`MULS`,-`MUL\s`
+ // arm64:`MSUBW`,-`MULW`
+ r0 := c - a*b
+ // arm/7:`MULS`-`MUL\s`
+ // arm64:`MSUBW`,-`MULW`
+ r1 := a - c*79
+ // arm/7:`SUB`,-`MULS`-`MUL\s`
+ // arm64:`SUB`,-`MSUBW`,-`MULW`
+ r2 := c - b*64
+ return r0, r1, r2
+}
From 85066acca144625e239294e2ce07bb2cfbc800c2 Mon Sep 17 00:00:00 2001
From: OlgaVlPetrova
Date: Sat, 13 Oct 2018 14:53:45 +0300
Subject: [PATCH 126/240] src/cmd/compile/internal/ssa: replace `s = s + x' =>
's += x'.
Change-Id: I1f399a8a0aa200bfda01f97f920b1345e59956ba
Reviewed-on: https://go-review.googlesource.com/c/142057
Run-TryBot: Iskander Sharipov
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/cmd/compile/internal/ssa/sparsetree.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/sparsetree.go b/src/cmd/compile/internal/ssa/sparsetree.go
index f7af85446b..546da8348d 100644
--- a/src/cmd/compile/internal/ssa/sparsetree.go
+++ b/src/cmd/compile/internal/ssa/sparsetree.go
@@ -98,9 +98,9 @@ func (t SparseTree) treestructure1(b *Block, i int) string {
s := "\n" + strings.Repeat("\t", i) + b.String() + "->["
for i, e := range b.Succs {
if i > 0 {
- s = s + ","
+ s += ","
}
- s = s + e.b.String()
+ s += e.b.String()
}
s += "]"
if c0 := t[b.ID].child; c0 != nil {
From e47c11d8b1bc26ce3283df6bc04f8ca4cf1b074b Mon Sep 17 00:00:00 2001
From: Ivan Sharavuev
Date: Sat, 13 Oct 2018 13:25:20 +0300
Subject: [PATCH 127/240] pprof: replace bits = bits + "..." to bits += "..."
where bits is a string.
Change-Id: Ic77ebbdf2670b7fdf2c381cd1ba768624b07e57c
Reviewed-on: https://go-review.googlesource.com/c/141998
Run-TryBot: Iskander Sharipov
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/runtime/pprof/internal/profile/profile.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/runtime/pprof/internal/profile/profile.go b/src/runtime/pprof/internal/profile/profile.go
index 863bd403a4..84e607e9a8 100644
--- a/src/runtime/pprof/internal/profile/profile.go
+++ b/src/runtime/pprof/internal/profile/profile.go
@@ -415,16 +415,16 @@ func (p *Profile) String() string {
for _, m := range p.Mapping {
bits := ""
if m.HasFunctions {
- bits = bits + "[FN]"
+ bits += "[FN]"
}
if m.HasFilenames {
- bits = bits + "[FL]"
+ bits += "[FL]"
}
if m.HasLineNumbers {
- bits = bits + "[LN]"
+ bits += "[LN]"
}
if m.HasInlineFrames {
- bits = bits + "[IN]"
+ bits += "[IN]"
}
ss = append(ss, fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
m.ID,
From 9322b53396dc8aeb8bdfa825beb4d89f33216d93 Mon Sep 17 00:00:00 2001
From: avsharapov
Date: Sat, 13 Oct 2018 13:51:16 +0300
Subject: [PATCH 128/240] cmd/cgo: simplify switch statement to if statement
Change-Id: Ie7dce45d554fde69d682680f55abba6a7fc55036
Reviewed-on: https://go-review.googlesource.com/c/142017
Reviewed-by: Ian Lance Taylor
---
src/cmd/cgo/gcc.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 019ee64c8e..3058fc5f34 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1026,8 +1026,7 @@ func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
found := false
f.walk(x, ctxExpr,
func(f *File, x interface{}, context astContext) {
- switch x.(type) {
- case *ast.CallExpr:
+ if _, ok := x.(*ast.CallExpr); ok {
found = true
}
})
@@ -1276,8 +1275,7 @@ func (p *Package) rewriteRef(f *File) {
// in case expression being replaced is first on line.
// See golang.org/issue/6563.
pos := (*r.Expr).Pos()
- switch x := expr.(type) {
- case *ast.Ident:
+ if x, ok := expr.(*ast.Ident); ok {
expr = &ast.Ident{NamePos: pos, Name: x.Name}
}
From d6e80069f3007d5bc03750f0a83e213bbac8c86e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Sun, 21 Jan 2018 13:02:27 +0100
Subject: [PATCH 129/240] cmd/compile: simplify as2 method of *Order
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Merge the two for loops that set up the node lists for
temporaries into one for loop.
Passes toolstash -cmp
Change-Id: Ibc739115f38c8869b0dcfbf9819fdc2fc96962e0
Reviewed-on: https://go-review.googlesource.com/c/141819
Reviewed-by: Keith Randall
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/gc/order.go | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 519fad4b7e..f33689298f 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1253,9 +1253,10 @@ func okas(ok, val *Node) *Node {
func (o *Order) as2(n *Node) {
tmplist := []*Node{}
left := []*Node{}
- for _, l := range n.List.Slice() {
+ for ni, l := range n.List.Slice() {
if !l.isBlank() {
tmp := o.newTemp(l.Type, types.Haspointers(l.Type))
+ n.List.SetIndex(ni, tmp)
tmplist = append(tmplist, tmp)
left = append(left, l)
}
@@ -1268,14 +1269,6 @@ func (o *Order) as2(n *Node) {
as.Rlist.Set(tmplist)
as = typecheck(as, Etop)
o.stmt(as)
-
- ti := 0
- for ni, l := range n.List.Slice() {
- if !l.isBlank() {
- n.List.SetIndex(ni, tmplist[ti])
- ti++
- }
- }
}
// okAs2 orders OAS2 with ok.
From bb3bf5bb538df67d3939974854c99608be21e135 Mon Sep 17 00:00:00 2001
From: Akhil Indurti
Date: Thu, 26 Jul 2018 23:46:38 -0400
Subject: [PATCH 130/240] internal/cpu: expose ARM feature flags for FMA
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This change exposes feature flags needed to implement an FMA intrinsic
on ARM CPUs via auxv's HWCAP bits. Specifically, it exposes HasVFPv4 to
detect if an ARM processor has the fourth version of the vector floating
point unit. The relevant instruction for this CL is VFMA, emitted in Go
as FMULAD.
Updates #26630.
Change-Id: Ibbc04fb24c2b4d994f93762360f1a37bc6d83ff7
Reviewed-on: https://go-review.googlesource.com/c/126315
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Martin Möhrmann
---
src/internal/cpu/cpu.go | 1 +
src/internal/cpu/cpu_arm.go | 3 +++
2 files changed, 4 insertions(+)
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
index fdda880af4..1f3411cc72 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -76,6 +76,7 @@ var ARM arm
// The struct is padded to avoid false sharing.
type arm struct {
_ CacheLinePad
+ HasVFPv4 bool
HasIDIVA bool
_ CacheLinePad
}
diff --git a/src/internal/cpu/cpu_arm.go b/src/internal/cpu/cpu_arm.go
index 6a5b30580c..1c3e529190 100644
--- a/src/internal/cpu/cpu_arm.go
+++ b/src/internal/cpu/cpu_arm.go
@@ -15,15 +15,18 @@ var HWCap2 uint
// HWCAP/HWCAP2 bits. These are exposed by Linux and FreeBSD.
const (
+ hwcap_VFPv4 = 1 << 16
hwcap_IDIVA = 1 << 17
)
func doinit() {
options = []option{
+ {"vfpv4", &ARM.HasVFPv4},
{"idiva", &ARM.HasIDIVA},
}
// HWCAP feature bits
+ ARM.HasVFPv4 = isSet(HWCap, hwcap_VFPv4)
ARM.HasIDIVA = isSet(HWCap, hwcap_IDIVA)
}
From 93e27e01af8bd6ac76c9784165d63b7cafe10a16 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Mon, 15 Oct 2018 05:39:23 +0000
Subject: [PATCH 131/240] test/codegen: add tests of FMA for arm/arm64
This CL adds tests of fused multiplication-accumulation
on arm/arm64.
Change-Id: Ic85d5277c0d6acb7e1e723653372dfaf96824a39
Reviewed-on: https://go-review.googlesource.com/c/141652
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
test/codegen/floats.go | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/test/codegen/floats.go b/test/codegen/floats.go
index 4e4f87d574..847959c42e 100644
--- a/test/codegen/floats.go
+++ b/test/codegen/floats.go
@@ -72,27 +72,43 @@ func indexStore(b0 []float64, b1 float64, idx int) {
func FusedAdd32(x, y, z float32) float32 {
// s390x:"FMADDS\t"
// ppc64le:"FMADDS\t"
+ // arm/7:"MULAF"
+ // arm64:"FMADDS"
return x*y + z
}
-func FusedSub32(x, y, z float32) float32 {
+func FusedSub32_a(x, y, z float32) float32 {
// s390x:"FMSUBS\t"
// ppc64le:"FMSUBS\t"
return x*y - z
}
+func FusedSub32_b(x, y, z float32) float32 {
+ // arm/7:"MULSF"
+ // arm64:"FMSUBS"
+ return z - x*y
+}
+
func FusedAdd64(x, y, z float64) float64 {
// s390x:"FMADD\t"
// ppc64le:"FMADD\t"
+ // arm/7:"MULAD"
+ // arm64:"FMADDD"
return x*y + z
}
-func FusedSub64(x, y, z float64) float64 {
+func FusedSub64_a(x, y, z float64) float64 {
// s390x:"FMSUB\t"
// ppc64le:"FMSUB\t"
return x*y - z
}
+func FusedSub64_b(x, y, z float64) float64 {
+ // arm/7:"MULSD"
+ // arm64:"FMSUBD"
+ return z - x*y
+}
+
// ---------------- //
// Non-floats //
// ---------------- //
From 296b7aeae0b3231f2e943859b37108e5f9e130d3 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Sun, 14 Oct 2018 12:07:45 -0700
Subject: [PATCH 132/240] cmd/compile: fix gdb stepping test
Not sure why this changed behavior, but seems mostly harmless.
Fixes #28198
Change-Id: Ie25c6e1fcb64912a582c7ae7bf92c4c1642e83cb
Reviewed-on: https://go-review.googlesource.com/c/141649
Reviewed-by: David Chase
---
src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts b/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
index 6586f243e2..b2f3216707 100644
--- a/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
+++ b/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
@@ -120,6 +120,7 @@ t = 0
a = 3
n = 0
t = 0
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
@@ -128,6 +129,7 @@ t = 0
a = 3
n = 3
t = 3
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
@@ -141,6 +143,7 @@ t = 9
a = 2
n = 6
t = 9
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
@@ -149,6 +152,7 @@ t = 9
a = 1
n = 8
t = 17
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
From 63e964e1741277c4da004e366111243f9ec942a2 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Sat, 6 Oct 2018 14:31:08 -0700
Subject: [PATCH 133/240] cmd/compile: provide types for all order-allocated
temporaries
Ensure that we correctly type the stack temps for regular closures,
method function closures, and slice literals.
Then we don't need to override the dummy types later.
Furthermore, this allows order to reuse temporaries of these types.
OARRAYLIT doesn't need a temporary as far as I can tell, so I
removed that case from order.
Change-Id: Ic58520fa50c90639393ff78f33d3c831d5c4acb9
Reviewed-on: https://go-review.googlesource.com/c/140306
Reviewed-by: Cherry Zhang
---
src/cmd/compile/internal/gc/closure.go | 72 +++++++++++++++-----------
src/cmd/compile/internal/gc/order.go | 19 +++----
test/live.go | 17 ++++--
3 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 834cdc41eb..dcea567a14 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -337,18 +337,10 @@ func closuredebugruntimecheck(clo *Node) {
}
}
-func walkclosure(clo *Node, init *Nodes) *Node {
- xfunc := clo.Func.Closure
-
- // If no closure vars, don't bother wrapping.
- if hasemptycvars(clo) {
- if Debug_closure > 0 {
- Warnl(clo.Pos, "closure converted to global")
- }
- return xfunc.Func.Nname
- }
- closuredebugruntimecheck(clo)
-
+// closureType returns the struct type used to hold all the information
+// needed in the closure for clo (clo must be a OCLOSURE node).
+// The address of a variable of the returned type can be cast to a func.
+func closureType(clo *Node) *types.Type {
// Create closure in the form of a composite literal.
// supposing the closure captures an int i and a string s
// and has one float64 argument and no results,
@@ -362,11 +354,10 @@ func walkclosure(clo *Node, init *Nodes) *Node {
// The information appears in the binary in the form of type descriptors;
// the struct is unnamed so that closures in multiple packages with the
// same struct type can share the descriptor.
-
fields := []*Node{
namedfield(".F", types.Types[TUINTPTR]),
}
- for _, v := range xfunc.Func.Cvars.Slice() {
+ for _, v := range clo.Func.Closure.Func.Cvars.Slice() {
typ := v.Type
if !v.Name.Byval() {
typ = types.NewPtr(typ)
@@ -375,6 +366,22 @@ func walkclosure(clo *Node, init *Nodes) *Node {
}
typ := tostruct(fields)
typ.SetNoalg(true)
+ return typ
+}
+
+func walkclosure(clo *Node, init *Nodes) *Node {
+ xfunc := clo.Func.Closure
+
+ // If no closure vars, don't bother wrapping.
+ if hasemptycvars(clo) {
+ if Debug_closure > 0 {
+ Warnl(clo.Pos, "closure converted to global")
+ }
+ return xfunc.Func.Nname
+ }
+ closuredebugruntimecheck(clo)
+
+ typ := closureType(clo)
clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil))
clos.Esc = clo.Esc
@@ -389,10 +396,10 @@ func walkclosure(clo *Node, init *Nodes) *Node {
clos.Left.Esc = clo.Esc
// non-escaping temp to use, if any.
- // orderexpr did not compute the type; fill it in now.
if x := prealloc[clo]; x != nil {
- x.Type = clos.Left.Left.Type
- x.Orig.Type = x.Type
+ if !eqtype(typ, x.Type) {
+ panic("closure type does not match order's assigned type")
+ }
clos.Left.Right = x
delete(prealloc, clo)
}
@@ -479,6 +486,18 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
return xfunc
}
+// partialCallType returns the struct type used to hold all the information
+// needed in the closure for n (n must be a OCALLPART node).
+// The address of a variable of the returned type can be cast to a func.
+func partialCallType(n *Node) *types.Type {
+ t := tostruct([]*Node{
+ namedfield("F", types.Types[TUINTPTR]),
+ namedfield("R", n.Left.Type),
+ })
+ t.SetNoalg(true)
+ return t
+}
+
func walkpartialcall(n *Node, init *Nodes) *Node {
// Create closure in the form of a composite literal.
// For x.M with receiver (x) type T, the generated code looks like:
@@ -495,30 +514,25 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
checknil(n.Left, init)
}
- typ := tostruct([]*Node{
- namedfield("F", types.Types[TUINTPTR]),
- namedfield("R", n.Left.Type),
- })
- typ.SetNoalg(true)
+ typ := partialCallType(n)
clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil))
clos.Esc = n.Esc
clos.Right.SetImplicit(true)
- clos.List.Set1(nod(OCFUNC, n.Func.Nname, nil))
- clos.List.Append(n.Left)
+ clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left)
// Force type conversion from *struct to the func type.
clos = convnop(clos, n.Type)
- // typecheck will insert a PTRLIT node under CONVNOP,
- // tag it with escape analysis result.
+ // The typecheck inside convnop will insert a PTRLIT node under CONVNOP.
+ // Tag it with escape analysis result.
clos.Left.Esc = n.Esc
// non-escaping temp to use, if any.
- // orderexpr did not compute the type; fill it in now.
if x := prealloc[n]; x != nil {
- x.Type = clos.Left.Left.Type
- x.Orig.Type = x.Type
+ if !eqtype(typ, x.Type) {
+ panic("partial call type does not match order's assigned type")
+ }
clos.Left.Right = x
delete(prealloc, n)
}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index f33689298f..694f8fbd34 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -244,12 +244,6 @@ func (o *Order) markTemp() ordermarker {
// which must have been returned by marktemp.
func (o *Order) popTemp(mark ordermarker) {
for _, n := range o.temp[mark:] {
- if n.Type.Etype == types.TUINT8 {
- // Don't recycle temps of this type. TUINT8 is used
- // as a placeholder for a type to be determined later.
- // TODO: fix
- continue
- }
key := n.Type.LongString()
o.free[key] = append(o.free[key], n)
}
@@ -1170,16 +1164,23 @@ func (o *Order) expr(n, lhs *Node) *Node {
case OCLOSURE:
if n.Noescape() && n.Func.Closure.Func.Cvars.Len() > 0 {
- prealloc[n] = o.newTemp(types.Types[TUINT8], false) // walk will fill in correct type
+ prealloc[n] = o.newTemp(closureType(n), false)
}
- case OARRAYLIT, OSLICELIT, OCALLPART:
+ case OSLICELIT, OCALLPART:
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil)
o.exprList(n.List)
o.exprList(n.Rlist)
if n.Noescape() {
- prealloc[n] = o.newTemp(types.Types[TUINT8], false) // walk will fill in correct type
+ var t *types.Type
+ switch n.Op {
+ case OSLICELIT:
+ t = types.NewArray(n.Type.Elem(), n.Right.Int64())
+ case OCALLPART:
+ t = partialCallType(n)
+ }
+ prealloc[n] = o.newTemp(t, false)
}
case ODDDARG:
diff --git a/test/live.go b/test/live.go
index 6367cab96f..a508947afc 100644
--- a/test/live.go
+++ b/test/live.go
@@ -404,8 +404,8 @@ func f27(b bool) {
if b {
call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
}
- call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
- call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
+ call27(func() { x++ })
+ call27(func() { x++ })
printnl()
}
@@ -521,8 +521,8 @@ func f32(b bool) {
if b {
call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
}
- call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
- call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
+ call32(t32.Inc)
+ call32(t32.Inc)
}
//go:noescape
@@ -694,3 +694,12 @@ func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
r = q
return // ERROR "live at call to deferreturn: r$"
}
+
+func f42() {
+ var p, q, r int
+ f43([]*int{&p,&q,&r}) // ERROR "stack object .autotmp_[0-9]+ \[3\]\*int$"
+ f43([]*int{&p,&r,&q})
+ f43([]*int{&q,&p,&r})
+}
+//go:noescape
+func f43(a []*int)
From a55f3ee46dda090131afba3018856e19bd0f426d Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Sun, 27 May 2018 09:03:45 -0700
Subject: [PATCH 134/240] cmd/compile: fuse before branchelim
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The branchelim pass works better after fuse.
Running fuse before branchelim also increases
the stability of generated code amidst other compiler changes,
which was the original motivation behind this change.
The fuse pass is not cheap enough to run in its entirety
before branchelim, but the most important half of it is.
This change makes it possible to run "plain fuse" independently
and does so before branchelim.
During make.bash, elimIf occurrences increase from 4244 to 4288 (1%),
and elimIfElse occurrences increase from 989 to 1079 (9%).
Toolspeed impact is marginal; plain fuse pays for itself.
name old time/op new time/op delta
Template 189ms ± 2% 189ms ± 2% ~ (p=0.890 n=45+46)
Unicode 93.2ms ± 5% 93.4ms ± 7% ~ (p=0.790 n=48+48)
GoTypes 662ms ± 4% 660ms ± 4% ~ (p=0.186 n=48+49)
Compiler 2.89s ± 4% 2.91s ± 3% +0.89% (p=0.050 n=49+44)
SSA 8.23s ± 2% 8.21s ± 1% ~ (p=0.165 n=46+44)
Flate 123ms ± 4% 123ms ± 3% +0.58% (p=0.031 n=47+49)
GoParser 154ms ± 4% 154ms ± 4% ~ (p=0.492 n=49+48)
Reflect 430ms ± 4% 429ms ± 4% ~ (p=1.000 n=48+48)
Tar 171ms ± 3% 170ms ± 4% ~ (p=0.122 n=48+48)
XML 232ms ± 3% 232ms ± 2% ~ (p=0.850 n=46+49)
[Geo mean] 394ms 394ms +0.02%
name old user-time/op new user-time/op delta
Template 236ms ± 5% 236ms ± 4% ~ (p=0.934 n=50+50)
Unicode 132ms ± 7% 130ms ± 9% ~ (p=0.087 n=50+50)
GoTypes 861ms ± 3% 867ms ± 4% ~ (p=0.124 n=48+50)
Compiler 3.93s ± 4% 3.94s ± 3% ~ (p=0.584 n=49+44)
SSA 12.2s ± 2% 12.3s ± 1% ~ (p=0.610 n=46+45)
Flate 149ms ± 4% 150ms ± 4% ~ (p=0.194 n=48+49)
GoParser 193ms ± 5% 191ms ± 6% ~ (p=0.239 n=49+50)
Reflect 553ms ± 5% 556ms ± 5% ~ (p=0.091 n=49+49)
Tar 218ms ± 5% 218ms ± 5% ~ (p=0.359 n=49+50)
XML 299ms ± 5% 298ms ± 4% ~ (p=0.482 n=50+49)
[Geo mean] 516ms 516ms -0.01%
name old alloc/op new alloc/op delta
Template 36.3MB ± 0% 36.3MB ± 0% -0.02% (p=0.000 n=49+49)
Unicode 29.7MB ± 0% 29.7MB ± 0% ~ (p=0.270 n=50+50)
GoTypes 126MB ± 0% 126MB ± 0% -0.34% (p=0.000 n=50+49)
Compiler 534MB ± 0% 531MB ± 0% -0.50% (p=0.000 n=50+50)
SSA 1.98GB ± 0% 1.98GB ± 0% -0.06% (p=0.000 n=49+49)
Flate 24.6MB ± 0% 24.6MB ± 0% -0.29% (p=0.000 n=50+50)
GoParser 29.5MB ± 0% 29.4MB ± 0% -0.15% (p=0.000 n=49+50)
Reflect 87.3MB ± 0% 87.2MB ± 0% -0.13% (p=0.000 n=49+50)
Tar 35.6MB ± 0% 35.5MB ± 0% -0.17% (p=0.000 n=50+50)
XML 48.2MB ± 0% 48.0MB ± 0% -0.30% (p=0.000 n=48+50)
[Geo mean] 83.1MB 82.9MB -0.20%
name old allocs/op new allocs/op delta
Template 352k ± 0% 352k ± 0% -0.01% (p=0.004 n=49+49)
Unicode 341k ± 0% 341k ± 0% ~ (p=0.341 n=48+50)
GoTypes 1.28M ± 0% 1.28M ± 0% -0.03% (p=0.000 n=50+49)
Compiler 4.96M ± 0% 4.96M ± 0% -0.05% (p=0.000 n=50+49)
SSA 15.5M ± 0% 15.5M ± 0% -0.01% (p=0.000 n=50+49)
Flate 233k ± 0% 233k ± 0% +0.01% (p=0.032 n=49+49)
GoParser 294k ± 0% 294k ± 0% ~ (p=0.052 n=46+48)
Reflect 1.04M ± 0% 1.04M ± 0% ~ (p=0.171 n=50+47)
Tar 343k ± 0% 343k ± 0% -0.03% (p=0.000 n=50+50)
XML 429k ± 0% 429k ± 0% -0.04% (p=0.000 n=50+50)
[Geo mean] 812k 812k -0.02%
Object files grow slightly; branchelim often increases binary size, at least on amd64.
name old object-bytes new object-bytes delta
Template 509kB ± 0% 509kB ± 0% -0.01% (p=0.008 n=5+5)
Unicode 224kB ± 0% 224kB ± 0% ~ (all equal)
GoTypes 1.84MB ± 0% 1.84MB ± 0% +0.00% (p=0.008 n=5+5)
Compiler 6.71MB ± 0% 6.71MB ± 0% +0.01% (p=0.008 n=5+5)
SSA 21.2MB ± 0% 21.2MB ± 0% +0.01% (p=0.008 n=5+5)
Flate 324kB ± 0% 324kB ± 0% -0.00% (p=0.008 n=5+5)
GoParser 404kB ± 0% 404kB ± 0% -0.02% (p=0.008 n=5+5)
Reflect 1.40MB ± 0% 1.40MB ± 0% +0.09% (p=0.008 n=5+5)
Tar 452kB ± 0% 452kB ± 0% +0.06% (p=0.008 n=5+5)
XML 596kB ± 0% 596kB ± 0% +0.00% (p=0.008 n=5+5)
[Geo mean] 1.04MB 1.04MB +0.01%
Change-Id: I535c711b85380ff657fc0f022bebd9cb14ddd07f
Reviewed-on: https://go-review.googlesource.com/c/129378
Run-TryBot: Josh Bleecher Snyder
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/compile.go | 3 ++-
src/cmd/compile/internal/ssa/fuse.go | 24 ++++++++++++++++---
src/cmd/compile/internal/ssa/fuse_test.go | 10 ++++----
src/cmd/compile/internal/ssa/nilcheck_test.go | 18 +++++++-------
4 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 8b5d6d94e8..7f933cb66e 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -373,6 +373,7 @@ var passes = [...]pass{
{name: "phiopt", fn: phiopt},
{name: "nilcheckelim", fn: nilcheckelim},
{name: "prove", fn: prove},
+ {name: "fuse plain", fn: fusePlain},
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
{name: "softfloat", fn: softfloat, required: true},
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
@@ -380,7 +381,7 @@ var passes = [...]pass{
{name: "generic deadcode", fn: deadcode, required: true}, // remove dead stores, which otherwise mess up store chain
{name: "check bce", fn: checkbce},
{name: "branchelim", fn: branchelim},
- {name: "fuse", fn: fuse},
+ {name: "fuse", fn: fuseAll},
{name: "dse", fn: dse},
{name: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
{name: "insert resched checks", fn: insertLoopReschedChecks,
diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
index 4f9a2ad9ca..c451904124 100644
--- a/src/cmd/compile/internal/ssa/fuse.go
+++ b/src/cmd/compile/internal/ssa/fuse.go
@@ -8,15 +8,33 @@ import (
"cmd/internal/src"
)
+// fusePlain runs fuse(f, fuseTypePlain).
+func fusePlain(f *Func) { fuse(f, fuseTypePlain) }
+
+// fuseAll runs fuse(f, fuseTypeAll).
+func fuseAll(f *Func) { fuse(f, fuseTypeAll) }
+
+type fuseType uint8
+
+const (
+ fuseTypePlain fuseType = 1 << iota
+ fuseTypeIf
+ fuseTypeAll = fuseTypePlain | fuseTypeIf
+)
+
// fuse simplifies control flow by joining basic blocks.
-func fuse(f *Func) {
+func fuse(f *Func, typ fuseType) {
for changed := true; changed; {
changed = false
// Fuse from end to beginning, to avoid quadratic behavior in fuseBlockPlain. See issue 13554.
for i := len(f.Blocks) - 1; i >= 0; i-- {
b := f.Blocks[i]
- changed = fuseBlockIf(b) || changed
- changed = fuseBlockPlain(b) || changed
+ if typ&fuseTypeIf != 0 {
+ changed = fuseBlockIf(b) || changed
+ }
+ if typ&fuseTypePlain != 0 {
+ changed = fuseBlockPlain(b) || changed
+ }
}
}
}
diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go
index bba92f805e..c3e25a80c4 100644
--- a/src/cmd/compile/internal/ssa/fuse_test.go
+++ b/src/cmd/compile/internal/ssa/fuse_test.go
@@ -26,7 +26,7 @@ func TestFuseEliminatesOneBranch(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- fuse(fun.f)
+ fuseAll(fun.f)
for _, b := range fun.f.Blocks {
if b == fun.blocks["then"] && b.Kind != BlockInvalid {
@@ -56,7 +56,7 @@ func TestFuseEliminatesBothBranches(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- fuse(fun.f)
+ fuseAll(fun.f)
for _, b := range fun.f.Blocks {
if b == fun.blocks["then"] && b.Kind != BlockInvalid {
@@ -90,7 +90,7 @@ func TestFuseHandlesPhis(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- fuse(fun.f)
+ fuseAll(fun.f)
for _, b := range fun.f.Blocks {
if b == fun.blocks["then"] && b.Kind != BlockInvalid {
@@ -122,7 +122,7 @@ func TestFuseEliminatesEmptyBlocks(t *testing.T) {
))
CheckFunc(fun.f)
- fuse(fun.f)
+ fuseAll(fun.f)
for k, b := range fun.blocks {
if k[:1] == "z" && b.Kind != BlockInvalid {
@@ -162,7 +162,7 @@ func BenchmarkFuse(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
fun := c.Fun("entry", blocks...)
- fuse(fun.f)
+ fuseAll(fun.f)
}
})
}
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go
index 815c4a5047..b2f5cae088 100644
--- a/src/cmd/compile/internal/ssa/nilcheck_test.go
+++ b/src/cmd/compile/internal/ssa/nilcheck_test.go
@@ -87,7 +87,7 @@ func TestNilcheckSimple(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -124,7 +124,7 @@ func TestNilcheckDomOrder(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -157,7 +157,7 @@ func TestNilcheckAddr(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -191,7 +191,7 @@ func TestNilcheckAddPtr(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -235,7 +235,7 @@ func TestNilcheckPhi(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -276,7 +276,7 @@ func TestNilcheckKeepRemove(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -323,7 +323,7 @@ func TestNilcheckInFalseBranch(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -374,7 +374,7 @@ func TestNilcheckUser(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
@@ -418,7 +418,7 @@ func TestNilcheckBug(t *testing.T) {
nilcheckelim(fun.f)
// clean up the removed nil check
- fuse(fun.f)
+ fusePlain(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
From 7c96d87eda45c93bf7218b79bc8ba85a3a21b066 Mon Sep 17 00:00:00 2001
From: Alberto Donizetti
Date: Fri, 12 Oct 2018 20:56:12 +0200
Subject: [PATCH 135/240] test/codegen: test ppc64 TrailingZeros, OnesCount
codegen
This change adds codegen tests for the intrinsification on ppc64 of
the OnesCount{64,32,16,8}, and TrailingZeros{64,32,16,8} math/bits
functions.
Change-Id: Id3364921fbd18316850e15c8c71330c906187fdb
Reviewed-on: https://go-review.googlesource.com/c/141897
Reviewed-by: Lynn Boger
---
test/codegen/mathbits.go | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/test/codegen/mathbits.go b/test/codegen/mathbits.go
index 9bb2254155..89a77d96f9 100644
--- a/test/codegen/mathbits.go
+++ b/test/codegen/mathbits.go
@@ -104,6 +104,7 @@ func OnesCount(n uint) int {
// amd64:"POPCNTQ",".*support_popcnt"
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
+ // ppc64:"POPCNTD"
return bits.OnesCount(n)
}
@@ -111,6 +112,7 @@ func OnesCount64(n uint64) int {
// amd64:"POPCNTQ",".*support_popcnt"
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
+ // ppc64:"POPCNTD"
return bits.OnesCount64(n)
}
@@ -118,6 +120,7 @@ func OnesCount32(n uint32) int {
// amd64:"POPCNTL",".*support_popcnt"
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
+ // ppc64:"POPCNTW"
return bits.OnesCount32(n)
}
@@ -125,11 +128,13 @@ func OnesCount16(n uint16) int {
// amd64:"POPCNTL",".*support_popcnt"
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
+ // ppc64:"POPCNTW"
return bits.OnesCount16(n)
}
func OnesCount8(n uint8) int {
// s390x:"POPCNT"
+ // ppc64:"POPCNTB"
return bits.OnesCount8(n)
}
@@ -224,24 +229,28 @@ func RotateLeftVariable32(n uint32, m int) uint32 {
func TrailingZeros(n uint) int {
// amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
// s390x:"FLOGR"
+ // ppc64:"ANDN","POPCNTD"
return bits.TrailingZeros(n)
}
func TrailingZeros64(n uint64) int {
// amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
// s390x:"FLOGR"
+ // ppc64:"ANDN","POPCNTD"
return bits.TrailingZeros64(n)
}
func TrailingZeros32(n uint32) int {
// amd64:"BTSQ\\t\\$32","BSFQ"
// s390x:"FLOGR","MOVWZ"
+ // ppc64:"ANDN","POPCNTW"
return bits.TrailingZeros32(n)
}
func TrailingZeros16(n uint16) int {
// amd64:"BSFL","BTSL\\t\\$16"
// s390x:"FLOGR","OR\t\\$65536"
+ // ppc64:"POPCNTD","OR\\t\\$65536"
return bits.TrailingZeros16(n)
}
From 240a30da1b3f5d4d60640a09f135275e8fee8b92 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Mon, 15 Oct 2018 09:44:22 -0700
Subject: [PATCH 136/240] cmd/compile: check order temp has correct type
Followon from CL 140306
Change-Id: Ic71033d2301105b15b60645d895a076107f44a2e
Reviewed-on: https://go-review.googlesource.com/c/142178
Run-TryBot: Keith Randall
TryBot-Result: Gobot Gobot
Reviewed-by: Cherry Zhang
---
src/cmd/compile/internal/gc/sinit.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index d520f21e63..f24da70625 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -833,7 +833,9 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
var a *Node
if x := prealloc[n]; x != nil {
// temp allocated during order.go for dddarg
- x.Type = t
+ if !eqtype(t, x.Type) {
+ panic("dotdotdot base type does not match order's assigned type")
+ }
if vstat == nil {
a = nod(OAS, x, nil)
From c9130cae9a9cd59178e842851f3f30b1d97ab0bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Sat, 27 Jan 2018 11:55:34 +0100
Subject: [PATCH 137/240] runtime/internal/math: add multiplication with
overflow check
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This CL adds a new internal math package for use by the runtime.
The new package exports a MulUintptr function with uintptr arguments
a and b and returns uintptr(a*b) and whether the full-width product
x*y does overflow the uintptr value range (uintptr(x*y) != x*y).
Uses of MulUinptr in the runtime and intrinsics for performance
will be added in followup CLs.
Updates #21588
Change-Id: Ia5a02eeabc955249118e4edf68c67d9fc0858058
Reviewed-on: https://go-review.googlesource.com/c/91755
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/gc/inl_test.go | 3 ++
src/cmd/compile/internal/gc/racewalk.go | 10 ++++-
src/go/build/deps_test.go | 3 +-
src/runtime/internal/math/math.go | 19 +++++++++
src/runtime/internal/math/math_test.go | 51 +++++++++++++++++++++++++
5 files changed, 84 insertions(+), 2 deletions(-)
create mode 100644 src/runtime/internal/math/math.go
create mode 100644 src/runtime/internal/math/math_test.go
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
index a452f2ad29..3fc0fbed1d 100644
--- a/src/cmd/compile/internal/gc/inl_test.go
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) {
"(*puintptr).set",
},
"runtime/internal/sys": {},
+ "runtime/internal/math": {
+ "MulUintptr",
+ },
"bytes": {
"(*Buffer).Bytes",
"(*Buffer).Cap",
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index e8c7fb5b14..8a8b436a23 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -32,7 +32,15 @@ import (
// Do not instrument the following packages at all,
// at best instrumentation would cause infinite recursion.
-var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan", "internal/cpu"}
+var omit_pkgs = []string{
+ "runtime/internal/atomic",
+ "runtime/internal/sys",
+ "runtime/internal/math",
+ "runtime",
+ "runtime/race",
+ "runtime/msan",
+ "internal/cpu",
+}
// Only insert racefuncenterfp/racefuncexit into the following packages.
// Memory accesses in the packages are either uninteresting or will cause false positives.
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 91617714f6..904759fe3b 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -36,9 +36,10 @@ var pkgDeps = map[string][]string{
// L0 is the lowest level, core, nearly unavoidable packages.
"errors": {},
"io": {"errors", "sync", "sync/atomic"},
- "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "internal/cpu", "internal/bytealg"},
+ "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"},
"runtime/internal/sys": {},
"runtime/internal/atomic": {"unsafe", "internal/cpu"},
+ "runtime/internal/math": {"runtime/internal/sys"},
"internal/race": {"runtime", "unsafe"},
"sync": {"internal/race", "runtime", "sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"},
diff --git a/src/runtime/internal/math/math.go b/src/runtime/internal/math/math.go
new file mode 100644
index 0000000000..5385f5dd86
--- /dev/null
+++ b/src/runtime/internal/math/math.go
@@ -0,0 +1,19 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+import "runtime/internal/sys"
+
+const MaxUintptr = ^uintptr(0)
+
+// MulUintptr returns a * b and whether the multiplication overflowed.
+// On supported platforms this is an intrinsic lowered by the compiler.
+func MulUintptr(a, b uintptr) (uintptr, bool) {
+ if a|b < 1<<(4*sys.PtrSize) || a == 0 {
+ return a * b, false
+ }
+ overflow := b > MaxUintptr/a
+ return a * b, overflow
+}
diff --git a/src/runtime/internal/math/math_test.go b/src/runtime/internal/math/math_test.go
new file mode 100644
index 0000000000..9447bd23f9
--- /dev/null
+++ b/src/runtime/internal/math/math_test.go
@@ -0,0 +1,51 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math_test
+
+import (
+ . "runtime/internal/math"
+ "testing"
+)
+
+const (
+ UintptrSize = 32 << (^uintptr(0) >> 63)
+)
+
+type mulUintptrTest struct {
+ a uintptr
+ b uintptr
+ overflow bool
+}
+
+var mulUintptrTests = []mulUintptrTest{
+ {0, 0, false},
+ {1000, 1000, false},
+ {MaxUintptr, 0, false},
+ {MaxUintptr, 1, false},
+ {MaxUintptr / 2, 2, false},
+ {MaxUintptr / 2, 3, true},
+ {MaxUintptr, 10, true},
+ {MaxUintptr, 100, true},
+ {MaxUintptr / 100, 100, false},
+ {MaxUintptr / 1000, 1001, true},
+ {1<<(UintptrSize/2) - 1, 1<<(UintptrSize/2) - 1, false},
+ {1 << (UintptrSize / 2), 1 << (UintptrSize / 2), true},
+ {MaxUintptr >> 32, MaxUintptr >> 32, false},
+ {MaxUintptr, MaxUintptr, true},
+}
+
+func TestMulUintptr(t *testing.T) {
+ for _, test := range mulUintptrTests {
+ a, b := test.a, test.b
+ for i := 0; i < 2; i++ {
+ mul, overflow := MulUintptr(a, b)
+ if mul != a*b || overflow != test.overflow {
+ t.Errorf("MulUintptr(%v, %v) = %v, %v want %v, %v",
+ a, b, mul, overflow, a*b, test.overflow)
+ }
+ a, b = b, a
+ }
+ }
+}
From 9f66b41beea82cc613cad9138c10a50f2b3ea137 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Sat, 16 Jun 2018 01:22:07 +0200
Subject: [PATCH 138/240] cmd/compile: avoid implicit bounds checks after
explicit checks for append
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The generated code for the append builtin already checks if the appended
to slice is large enough and calls growslice if that is not the case.
Trust that this ensures the slice is large enough and avoid the
implicit bounds check when slicing the slice to its new size.
Removes 365 panicslice calls (-14%) from the go binary which
reduces the binary size by ~12kbyte.
Change-Id: I1b88418675ff409bc0b956853c9e95241274d5a6
Reviewed-on: https://go-review.googlesource.com/c/119315
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/gc/ssa.go | 22 ++++++++++++----------
src/cmd/compile/internal/gc/walk.go | 3 +++
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 4a4461948c..ca1c7df9a0 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -2332,7 +2332,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if max != nil {
k = s.extendIndex(s.expr(max), panicslice)
}
- p, l, c := s.slice(n.Left.Type, v, i, j, k)
+ p, l, c := s.slice(n.Left.Type, v, i, j, k, n.Bounded())
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
case OSLICESTR:
@@ -2345,7 +2345,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if high != nil {
j = s.extendIndex(s.expr(high), panicslice)
}
- p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
+ p, l, _ := s.slice(n.Left.Type, v, i, j, nil, n.Bounded())
return s.newValue2(ssa.OpStringMake, n.Type, p, l)
case OCALLFUNC:
@@ -4175,7 +4175,7 @@ func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
// i,j,k may be nil, in which case they are set to their default value.
// t is a slice, ptr to array, or string type.
-func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
+func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
var elemtype *types.Type
var ptrtype *types.Type
var ptr *ssa.Value
@@ -4220,13 +4220,15 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value)
k = cap
}
- // Panic if slice indices are not in bounds.
- s.sliceBoundsCheck(i, j)
- if j != k {
- s.sliceBoundsCheck(j, k)
- }
- if k != cap {
- s.sliceBoundsCheck(k, cap)
+ if !bounded {
+ // Panic if slice indices are not in bounds.
+ s.sliceBoundsCheck(i, j)
+ if j != k {
+ s.sliceBoundsCheck(j, k)
+ }
+ if k != cap {
+ s.sliceBoundsCheck(k, cap)
+ }
}
// Generate the following code assuming that indexes are in bounds.
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index f7676310e9..9868a33ba9 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -2818,6 +2818,7 @@ func appendslice(n *Node, init *Nodes) *Node {
// s = s[:n]
nt := nod(OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
+ nt.SetBounded(true)
nodes.Append(nod(OAS, s, nt))
var ncopy *Node
@@ -2987,6 +2988,7 @@ func extendslice(n *Node, init *Nodes) *Node {
// s = s[:n]
nt := nod(OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
+ nt.SetBounded(true)
nodes = append(nodes, nod(OAS, s, nt))
// lptr := &l1[0]
@@ -3109,6 +3111,7 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
nx = nod(OSLICE, ns, nil) // ...s[:n+argc]
nx.SetSliceBounds(nil, nod(OADD, nn, na), nil)
+ nx.SetBounded(true)
l = append(l, nod(OAS, ns, nx)) // s = s[:n+argc]
ls = n.List.Slice()[1:]
From a1ca4893ff755d6b0b3bf4b026196d55251ea846 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Sat, 27 Jan 2018 11:55:34 +0100
Subject: [PATCH 139/240] cmd/compile: add intrinsics for runtime/internal/math
on 386 and amd64
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add generic, 386 and amd64 specific ops and SSA rules for multiplication
with overflow and branching based on overflow flags. Use these to intrinsify
runtime/internal/math.MulUinptr.
On amd64
mul, overflow := math.MulUintptr(a, b)
if overflow {
is lowered to two instructions:
MULQ SI
JO 0x10ee35c
No codegen tests as codegen can not currently test unexported internal runtime
functions.
amd64:
name old time/op new time/op delta
MulUintptr/small 1.16ns ± 5% 0.88ns ± 6% -24.36% (p=0.000 n=19+20)
MulUintptr/large 10.7ns ± 1% 1.1ns ± 1% -89.28% (p=0.000 n=17+19)
Change-Id: If60739a86f820e5044d677276c21df90d3c7a86a
Reviewed-on: https://go-review.googlesource.com/c/141820
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/amd64/ssa.go | 13 +-
src/cmd/compile/internal/gc/ssa.go | 8 +
src/cmd/compile/internal/ssa/gen/386.rules | 5 +
src/cmd/compile/internal/ssa/gen/386Ops.go | 5 +
src/cmd/compile/internal/ssa/gen/AMD64.rules | 6 +
src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 6 +
.../compile/internal/ssa/gen/genericOps.go | 3 +
src/cmd/compile/internal/ssa/opGen.go | 101 ++++++++++++
src/cmd/compile/internal/ssa/rewrite386.go | 123 ++++++++++++++
src/cmd/compile/internal/ssa/rewriteAMD64.go | 150 ++++++++++++++++++
src/cmd/compile/internal/x86/ssa.go | 13 +-
src/runtime/internal/math/math_test.go | 28 ++++
12 files changed, 459 insertions(+), 2 deletions(-)
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index f12e4cb5ec..5b776170d7 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -315,6 +315,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
m.To.Reg = x86.REG_DX
}
+ case ssa.OpAMD64MULQU, ssa.OpAMD64MULLU:
+ // Arg[0] is already in AX as it's the only register we allow
+ // results lo in AX
+ p := s.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+
case ssa.OpAMD64MULQU2:
// Arg[0] is already in AX as it's the only register we allow
// results hi in DX, lo in AX
@@ -979,7 +986,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
- ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
+ ssa.OpAMD64SETA, ssa.OpAMD64SETAE,
+ ssa.OpAMD64SETO:
p := s.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
@@ -1122,6 +1130,8 @@ var blockJump = [...]struct {
ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
+ ssa.BlockAMD64OS: {x86.AJOS, x86.AJOC},
+ ssa.BlockAMD64OC: {x86.AJOC, x86.AJOS},
ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
@@ -1183,6 +1193,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
ssa.BlockAMD64LT, ssa.BlockAMD64GE,
ssa.BlockAMD64LE, ssa.BlockAMD64GT,
+ ssa.BlockAMD64OS, ssa.BlockAMD64OC,
ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
jmp := blockJump[b.Kind]
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index ca1c7df9a0..d3a30879db 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -2913,6 +2913,14 @@ func init() {
},
all...)
}
+ addF("runtime/internal/math", "MulUintptr",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ return s.newValue2(ssa.OpMul32uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ }
+ return s.newValue2(ssa.OpMul64uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ },
+ sys.AMD64, sys.I386)
add("runtime", "KeepAlive",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index 7a6797bb09..e8d19cf3c9 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -17,6 +17,9 @@
(Mul(32|64)F x y) -> (MULS(S|D) x y)
(Mul32uhilo x y) -> (MULLQU x y)
+(Select0 (Mul32uover x y)) -> (Select0 (MULLU x y))
+(Select1 (Mul32uover x y)) -> (SETO (Select1 (MULLU x y)))
+
(Avg32u x y) -> (AVGLU x y)
(Div32F x y) -> (DIVSS x y)
@@ -369,6 +372,7 @@
(If (SETBE cmp) yes no) -> (ULE cmp yes no)
(If (SETA cmp) yes no) -> (UGT cmp yes no)
(If (SETAE cmp) yes no) -> (UGE cmp yes no)
+(If (SETO cmp) yes no) -> (OS cmp yes no)
// Special case for floating point - LF/LEF not generated
(If (SETGF cmp) yes no) -> (UGT cmp yes no)
@@ -398,6 +402,7 @@
(NE (TESTB (SETBE cmp) (SETBE cmp)) yes no) -> (ULE cmp yes no)
(NE (TESTB (SETA cmp) (SETA cmp)) yes no) -> (UGT cmp yes no)
(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
+(NE (TESTB (SETO cmp) (SETO cmp)) yes no) -> (OS cmp yes no)
// Special case for floating point - LF/LEF not generated
(NE (TESTB (SETGF cmp) (SETGF cmp)) yes no) -> (UGT cmp yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
index f7e5f939ab..cb2919567f 100644
--- a/src/cmd/compile/internal/ssa/gen/386Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -207,6 +207,8 @@ func init() {
{name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1
{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true}, // arg0 * auxint
+ {name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, 0}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true}, // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
+
{name: "HMULL", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
{name: "HMULLU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULL", clobberFlags: true}, // (arg0 * arg1) >> width
@@ -326,6 +328,7 @@ func init() {
{name: "SETBE", argLength: 1, reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
{name: "SETA", argLength: 1, reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
{name: "SETAE", argLength: 1, reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
+ {name: "SETO", argLength: 1, reg: readflags, asm: "SETOS"}, // extract if overflow flag is set from arg0
// Need different opcodes for floating point conditions because
// any comparison involving a NaN is always FALSE and thus
// the patterns for inverting conditions cannot be used.
@@ -553,6 +556,8 @@ func init() {
{name: "LE"},
{name: "GT"},
{name: "GE"},
+ {name: "OS"},
+ {name: "OC"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index fa7f1438d6..adb94c3bfe 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -16,6 +16,10 @@
(Mul(64|32|16|8) x y) -> (MUL(Q|L|L|L) x y)
(Mul(32|64)F x y) -> (MULS(S|D) x y)
+(Select0 (Mul64uover x y)) -> (Select0 (MULQU x y))
+(Select0 (Mul32uover x y)) -> (Select0 (MULLU x y))
+(Select1 (Mul(64|32)uover x y)) -> (SETO (Select1 (MUL(Q|L)U x y)))
+
(Hmul(64|32) x y) -> (HMUL(Q|L) x y)
(Hmul(64|32)u x y) -> (HMUL(Q|L)U x y)
@@ -480,6 +484,7 @@
(If (SETBE cmp) yes no) -> (ULE cmp yes no)
(If (SETA cmp) yes no) -> (UGT cmp yes no)
(If (SETAE cmp) yes no) -> (UGE cmp yes no)
+(If (SETO cmp) yes no) -> (OS cmp yes no)
// Special case for floating point - LF/LEF not generated
(If (SETGF cmp) yes no) -> (UGT cmp yes no)
@@ -542,6 +547,7 @@
(NE (TESTB (SETBE cmp) (SETBE cmp)) yes no) -> (ULE cmp yes no)
(NE (TESTB (SETA cmp) (SETA cmp)) yes no) -> (UGT cmp yes no)
(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
+(NE (TESTB (SETO cmp) (SETO cmp)) yes no) -> (OS cmp yes no)
// Recognize bit tests: a&(1<64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
+ {name: "MULQU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, 0}, clobbers: dx}, typ: "(UInt64,Flags)", asm: "MULQ", commutative: true, clobberFlags: true}, // Let x = arg0*arg1 (full 64x64->128 unsigned multiply). Returns uint64(x), and flags set to overflow if uint64(x) != x.
+
{name: "HMULQ", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULQ", clobberFlags: true}, // (arg0 * arg1) >> width
{name: "HMULL", argLength: 2, reg: gp21hmul, commutative: true, asm: "IMULL", clobberFlags: true}, // (arg0 * arg1) >> width
{name: "HMULQU", argLength: 2, reg: gp21hmul, commutative: true, asm: "MULQ", clobberFlags: true}, // (arg0 * arg1) >> width
@@ -468,6 +471,7 @@ func init() {
{name: "SETBE", argLength: 1, reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
{name: "SETA", argLength: 1, reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
{name: "SETAE", argLength: 1, reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
+ {name: "SETO", argLength: 1, reg: readflags, asm: "SETOS"}, // extract if overflow flag is set from arg0
// Variants that store result to memory
{name: "SETEQstore", argLength: 3, reg: gpstoreconst, asm: "SETEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // extract == condition from arg1 to arg0+auxint+aux, arg2=mem
{name: "SETNEstore", argLength: 3, reg: gpstoreconst, asm: "SETNE", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // extract != condition from arg1 to arg0+auxint+aux, arg2=mem
@@ -754,6 +758,8 @@ func init() {
{name: "LE"},
{name: "GT"},
{name: "GE"},
+ {name: "OS"},
+ {name: "OC"},
{name: "ULT"},
{name: "ULE"},
{name: "UGT"},
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index ee9c6fa0f6..58f1b5bf79 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -55,6 +55,9 @@ var genericOps = []opData{
{name: "Mul32uhilo", argLength: 2, typ: "(UInt32,UInt32)", commutative: true}, // arg0 * arg1, returns (hi, lo)
{name: "Mul64uhilo", argLength: 2, typ: "(UInt64,UInt64)", commutative: true}, // arg0 * arg1, returns (hi, lo)
+ {name: "Mul32uover", argLength: 2, typ: "(UInt32,Bool)", commutative: true}, // Let x = arg0*arg1 (full 32x32-> 64 unsigned multiply), returns (uint32(x), (uint32(x) != x))
+ {name: "Mul64uover", argLength: 2, typ: "(UInt64,Bool)", commutative: true}, // Let x = arg0*arg1 (full 64x64->128 unsigned multiply), returns (uint64(x), (uint64(x) != x))
+
// Weird special instructions for use in the strength reduction of divides.
// These ops compute unsigned (arg0 + arg1) / 2, correct to all
// 32/64 bits, even when the intermediate result of the add has 33/65 bits.
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index ae04e25798..082b6e1ba7 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -22,6 +22,8 @@ const (
Block386LE
Block386GT
Block386GE
+ Block386OS
+ Block386OC
Block386ULT
Block386ULE
Block386UGT
@@ -37,6 +39,8 @@ const (
BlockAMD64LE
BlockAMD64GT
BlockAMD64GE
+ BlockAMD64OS
+ BlockAMD64OC
BlockAMD64ULT
BlockAMD64ULE
BlockAMD64UGT
@@ -130,6 +134,8 @@ var blockString = [...]string{
Block386LE: "LE",
Block386GT: "GT",
Block386GE: "GE",
+ Block386OS: "OS",
+ Block386OC: "OC",
Block386ULT: "ULT",
Block386ULE: "ULE",
Block386UGT: "UGT",
@@ -145,6 +151,8 @@ var blockString = [...]string{
BlockAMD64LE: "LE",
BlockAMD64GT: "GT",
BlockAMD64GE: "GE",
+ BlockAMD64OS: "OS",
+ BlockAMD64OC: "OC",
BlockAMD64ULT: "ULT",
BlockAMD64ULE: "ULE",
BlockAMD64UGT: "UGT",
@@ -278,6 +286,7 @@ const (
Op386SBBLconst
Op386MULL
Op386MULLconst
+ Op386MULLU
Op386HMULL
Op386HMULLU
Op386MULLQU
@@ -364,6 +373,7 @@ const (
Op386SETBE
Op386SETA
Op386SETAE
+ Op386SETO
Op386SETEQF
Op386SETNEF
Op386SETORD
@@ -500,6 +510,8 @@ const (
OpAMD64MULL
OpAMD64MULQconst
OpAMD64MULLconst
+ OpAMD64MULLU
+ OpAMD64MULQU
OpAMD64HMULQ
OpAMD64HMULL
OpAMD64HMULQU
@@ -705,6 +717,7 @@ const (
OpAMD64SETBE
OpAMD64SETA
OpAMD64SETAE
+ OpAMD64SETO
OpAMD64SETEQstore
OpAMD64SETNEstore
OpAMD64SETLstore
@@ -2083,6 +2096,8 @@ const (
OpHmul64u
OpMul32uhilo
OpMul64uhilo
+ OpMul32uover
+ OpMul64uover
OpAvg32u
OpAvg64u
OpDiv8
@@ -3114,6 +3129,24 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "MULLU",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 1}, // AX
+ },
+ },
+ },
{
name: "HMULL",
argLen: 2,
@@ -4378,6 +4411,16 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "SETO",
+ argLen: 1,
+ asm: x86.ASETOS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
{
name: "SETEQF",
argLen: 1,
@@ -6271,6 +6314,42 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "MULLU",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 1}, // AX
+ },
+ },
+ },
+ {
+ name: "MULQU",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AMULQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 1}, // AX
+ },
+ },
+ },
{
name: "HMULQ",
argLen: 2,
@@ -9293,6 +9372,16 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "SETO",
+ argLen: 1,
+ asm: x86.ASETOS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
{
name: "SETEQstore",
auxType: auxSymOff,
@@ -27899,6 +27988,18 @@ var opcodeTable = [...]opInfo{
commutative: true,
generic: true,
},
+ {
+ name: "Mul32uover",
+ argLen: 2,
+ commutative: true,
+ generic: true,
+ },
+ {
+ name: "Mul64uover",
+ argLen: 2,
+ commutative: true,
+ generic: true,
+ },
{
name: "Avg32u",
argLen: 2,
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 9b2ec74a9d..14784bef3a 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -637,6 +637,10 @@ func rewriteValue386(v *Value) bool {
return rewriteValue386_OpRsh8x64_0(v)
case OpRsh8x8:
return rewriteValue386_OpRsh8x8_0(v)
+ case OpSelect0:
+ return rewriteValue386_OpSelect0_0(v)
+ case OpSelect1:
+ return rewriteValue386_OpSelect1_0(v)
case OpSignExt16to32:
return rewriteValue386_OpSignExt16to32_0(v)
case OpSignExt8to16:
@@ -23707,6 +23711,59 @@ func rewriteValue386_OpRsh8x8_0(v *Value) bool {
return true
}
}
+func rewriteValue386_OpSelect0_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Select0 (Mul32uover x y))
+ // cond:
+ // result: (Select0 (MULLU x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul32uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpSelect0)
+ v.Type = typ.UInt32
+ v0 := b.NewValue0(v.Pos, Op386MULLU, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpSelect1_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Select1 (Mul32uover x y))
+ // cond:
+ // result: (SETO (Select1 (MULLU x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul32uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(Op386SETO)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, Op386MULLU, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
func rewriteValue386_OpSignExt16to32_0(v *Value) bool {
// match: (SignExt16to32 x)
// cond:
@@ -24845,6 +24902,20 @@ func rewriteBlock386(b *Block) bool {
b.Aux = nil
return true
}
+ // match: (If (SETO cmp) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETO {
+ break
+ }
+ cmp := v.Args[0]
+ b.Kind = Block386OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
// match: (If (SETGF cmp) yes no)
// cond:
// result: (UGT cmp yes no)
@@ -25602,6 +25673,58 @@ func rewriteBlock386(b *Block) bool {
b.Aux = nil
return true
}
+ // match: (NE (TESTB (SETO cmp) (SETO cmp)) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETO {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETO {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
+ b.Kind = Block386OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
+ // match: (NE (TESTB (SETO cmp) (SETO cmp)) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETO {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETO {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
+ b.Kind = Block386OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
// match: (NE (TESTB (SETGF cmp) (SETGF cmp)) yes no)
// cond:
// result: (UGT cmp yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index e89ed9edb6..254c40a4ea 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -64552,6 +64552,46 @@ func rewriteValueAMD64_OpRsh8x8_0(v *Value) bool {
func rewriteValueAMD64_OpSelect0_0(v *Value) bool {
b := v.Block
_ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Select0 (Mul64uover x y))
+ // cond:
+ // result: (Select0 (MULQU x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul64uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpSelect0)
+ v.Type = typ.UInt64
+ v0 := b.NewValue0(v.Pos, OpAMD64MULQU, types.NewTuple(typ.UInt64, types.TypeFlags))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Select0 (Mul32uover x y))
+ // cond:
+ // result: (Select0 (MULLU x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul32uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpSelect0)
+ v.Type = typ.UInt32
+ v0 := b.NewValue0(v.Pos, OpAMD64MULLU, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
// match: (Select0 (AddTupleFirst32 val tuple))
// cond:
// result: (ADDL val (Select0 tuple))
@@ -64593,6 +64633,50 @@ func rewriteValueAMD64_OpSelect0_0(v *Value) bool {
return false
}
func rewriteValueAMD64_OpSelect1_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (Select1 (Mul64uover x y))
+ // cond:
+ // result: (SETO (Select1 (MULQU x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul64uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpAMD64SETO)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64MULQU, types.NewTuple(typ.UInt64, types.TypeFlags))
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Select1 (Mul32uover x y))
+ // cond:
+ // result: (SETO (Select1 (MULLU x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMul32uover {
+ break
+ }
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpAMD64SETO)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64MULLU, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
// match: (Select1 (AddTupleFirst32 _ tuple))
// cond:
// result: (Select1 tuple)
@@ -66757,6 +66841,20 @@ func rewriteBlockAMD64(b *Block) bool {
b.Aux = nil
return true
}
+ // match: (If (SETO cmp) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpAMD64SETO {
+ break
+ }
+ cmp := v.Args[0]
+ b.Kind = BlockAMD64OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
// match: (If (SETGF cmp) yes no)
// cond:
// result: (UGT cmp yes no)
@@ -67514,6 +67612,58 @@ func rewriteBlockAMD64(b *Block) bool {
b.Aux = nil
return true
}
+ // match: (NE (TESTB (SETO cmp) (SETO cmp)) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpAMD64TESTB {
+ break
+ }
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SETO {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETO {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
+ b.Kind = BlockAMD64OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
+ // match: (NE (TESTB (SETO cmp) (SETO cmp)) yes no)
+ // cond:
+ // result: (OS cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpAMD64TESTB {
+ break
+ }
+ _ = v.Args[1]
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SETO {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SETO {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
+ b.Kind = BlockAMD64OS
+ b.SetControl(cmp)
+ b.Aux = nil
+ return true
+ }
// match: (NE (TESTL (SHLL (MOVLconst [1]) x) y))
// cond: !config.nacl
// result: (ULT (BTL x y))
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index e0aebb449c..8a6f015854 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -278,6 +278,13 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
m.To.Reg = x86.REG_DX
}
+ case ssa.Op386MULLU:
+ // Arg[0] is already in AX as it's the only register we allow
+ // results lo in AX
+ p := s.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+
case ssa.Op386MULLQU:
// AX * args[1], high 32 bits in DX (result[0]), low 32 bits in AX (result[1]).
p := s.Prog(v.Op.Asm())
@@ -770,7 +777,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.Op386SETGF, ssa.Op386SETGEF,
ssa.Op386SETB, ssa.Op386SETBE,
ssa.Op386SETORD, ssa.Op386SETNAN,
- ssa.Op386SETA, ssa.Op386SETAE:
+ ssa.Op386SETA, ssa.Op386SETAE,
+ ssa.Op386SETO:
p := s.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
@@ -842,6 +850,8 @@ var blockJump = [...]struct {
ssa.Block386GE: {x86.AJGE, x86.AJLT},
ssa.Block386LE: {x86.AJLE, x86.AJGT},
ssa.Block386GT: {x86.AJGT, x86.AJLE},
+ ssa.Block386OS: {x86.AJOS, x86.AJOC},
+ ssa.Block386OC: {x86.AJOC, x86.AJOS},
ssa.Block386ULT: {x86.AJCS, x86.AJCC},
ssa.Block386UGE: {x86.AJCC, x86.AJCS},
ssa.Block386UGT: {x86.AJHI, x86.AJLS},
@@ -903,6 +913,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
case ssa.Block386EQ, ssa.Block386NE,
ssa.Block386LT, ssa.Block386GE,
ssa.Block386LE, ssa.Block386GT,
+ ssa.Block386OS, ssa.Block386OC,
ssa.Block386ULT, ssa.Block386UGT,
ssa.Block386ULE, ssa.Block386UGE:
jmp := blockJump[b.Kind]
diff --git a/src/runtime/internal/math/math_test.go b/src/runtime/internal/math/math_test.go
index 9447bd23f9..303eb63405 100644
--- a/src/runtime/internal/math/math_test.go
+++ b/src/runtime/internal/math/math_test.go
@@ -49,3 +49,31 @@ func TestMulUintptr(t *testing.T) {
}
}
}
+
+var SinkUintptr uintptr
+var SinkBool bool
+
+var x, y uintptr
+
+func BenchmarkMulUintptr(b *testing.B) {
+ x, y = 1, 2
+ b.Run("small", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var overflow bool
+ SinkUintptr, overflow = MulUintptr(x, y)
+ if overflow {
+ SinkUintptr = 0
+ }
+ }
+ })
+ x, y = MaxUintptr, MaxUintptr-1
+ b.Run("large", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var overflow bool
+ SinkUintptr, overflow = MulUintptr(x, y)
+ if overflow {
+ SinkUintptr = 0
+ }
+ }
+ })
+}
From a0f57c3fd0cff8b92ffb4257a6d1b56467bf30f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Mon, 4 Jun 2018 08:24:11 +0200
Subject: [PATCH 140/240] cmd/compile: avoid string allocations when map key is
struct or array literal
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
x = map[string(byteslice)] is already optimized by the compiler to avoid a
string allocation. This CL generalizes this optimization to:
x = map[T1{ ... Tn{..., string(byteslice), ...} ... }]
where T1 to Tn is a nesting of struct and array literals.
Found in a hot code path that used a struct of strings made from []byte
slices to make a map lookup.
There are no uses of the more generalized optimization in the standard library.
Passes toolstash -cmp.
MapStringConversion/32/simple 21.9ns ± 2% 21.9ns ± 3% ~ (p=0.995 n=17+20)
MapStringConversion/32/struct 28.8ns ± 3% 22.0ns ± 2% -23.80% (p=0.000 n=20+20)
MapStringConversion/32/array 28.5ns ± 2% 21.9ns ± 2% -23.14% (p=0.000 n=19+16)
MapStringConversion/64/simple 21.0ns ± 2% 21.1ns ± 3% ~ (p=0.072 n=19+18)
MapStringConversion/64/struct 72.4ns ± 3% 21.3ns ± 2% -70.53% (p=0.000 n=20+20)
MapStringConversion/64/array 72.8ns ± 1% 21.0ns ± 2% -71.13% (p=0.000 n=17+19)
name old allocs/op new allocs/op delta
MapStringConversion/32/simple 0.00 0.00 ~ (all equal)
MapStringConversion/32/struct 0.00 0.00 ~ (all equal)
MapStringConversion/32/array 0.00 0.00 ~ (all equal)
MapStringConversion/64/simple 0.00 0.00 ~ (all equal)
MapStringConversion/64/struct 1.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
MapStringConversion/64/array 1.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
Change-Id: I483b4d84d8d74b1025b62c954da9a365e79b7a3a
Reviewed-on: https://go-review.googlesource.com/c/116275
Reviewed-by: Matthew Dempsky
Run-TryBot: Matthew Dempsky
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/gc/order.go | 75 ++++++++++++++++++++--------
src/runtime/map_benchmark_test.go | 34 +++++++++++++
src/runtime/string.go | 3 +-
test/codegen/maps.go | 29 +++++++++++
4 files changed, 118 insertions(+), 23 deletions(-)
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 694f8fbd34..e603a39b2a 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -233,6 +233,45 @@ func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node {
return n
}
+// mapKeyReplaceStrConv replaces OARRAYBYTESTR by OARRAYBYTESTRTMP
+// in n to avoid string allocations for keys in map lookups.
+// Returns a bool that signals if a modification was made.
+//
+// For:
+// x = m[string(k)]
+// x = m[T1{... Tn{..., string(k), ...}]
+// where k is []byte, T1 to Tn is a nesting of struct and array literals,
+// the allocation of backing bytes for the string can be avoided
+// by reusing the []byte backing array. These are special cases
+// for avoiding allocations when converting byte slices to strings.
+// It would be nice to handle these generally, but because
+// []byte keys are not allowed in maps, the use of string(k)
+// comes up in important cases in practice. See issue 3512.
+func mapKeyReplaceStrConv(n *Node) bool {
+ var replaced bool
+ switch n.Op {
+ case OARRAYBYTESTR:
+ n.Op = OARRAYBYTESTRTMP
+ replaced = true
+ case OSTRUCTLIT:
+ for _, elem := range n.List.Slice() {
+ if mapKeyReplaceStrConv(elem.Left) {
+ replaced = true
+ }
+ }
+ case OARRAYLIT:
+ for _, elem := range n.List.Slice() {
+ if elem.Op == OKEY {
+ elem = elem.Right
+ }
+ if mapKeyReplaceStrConv(elem) {
+ replaced = true
+ }
+ }
+ }
+ return replaced
+}
+
type ordermarker int
// Marktemp returns the top of the temporary variable stack.
@@ -580,10 +619,9 @@ func (o *Order) stmt(n *Node) {
r.Left = o.expr(r.Left, nil)
r.Right = o.expr(r.Right, nil)
- // See case OINDEXMAP below.
- if r.Right.Op == OARRAYBYTESTR {
- r.Right.Op = OARRAYBYTESTRTMP
- }
+ // See similar conversion for OINDEXMAP below.
+ _ = mapKeyReplaceStrConv(r.Right)
+
r.Right = o.mapKeyTemp(r.Left.Type, r.Right)
o.okAs2(n)
o.cleanTemp(t)
@@ -1042,25 +1080,18 @@ func (o *Order) expr(n, lhs *Node) *Node {
n.Right = o.expr(n.Right, nil)
needCopy := false
- if !n.IndexMapLValue() && instrumenting {
- // Race detector needs the copy so it can
- // call treecopy on the result.
- needCopy = true
- }
+ if !n.IndexMapLValue() {
+ // Enforce that any []byte slices we are not copying
+ // can not be changed before the map index by forcing
+ // the map index to happen immediately following the
+ // conversions. See copyExpr a few lines below.
+ needCopy = mapKeyReplaceStrConv(n.Right)
- // For x = m[string(k)] where k is []byte, the allocation of
- // backing bytes for the string can be avoided by reusing
- // the []byte backing array. This is a special case that it
- // would be nice to handle more generally, but because
- // there are no []byte-keyed maps, this specific case comes
- // up in important cases in practice. See issue 3512.
- // Nothing can change the []byte we are not copying before
- // the map index, because the map access is going to
- // be forced to happen immediately following this
- // conversion (by the ordercopyexpr a few lines below).
- if !n.IndexMapLValue() && n.Right.Op == OARRAYBYTESTR {
- n.Right.Op = OARRAYBYTESTRTMP
- needCopy = true
+ if instrumenting {
+ // Race detector needs the copy so it can
+ // call treecopy on the result.
+ needCopy = true
+ }
}
n.Right = o.mapKeyTemp(n.Left.Type, n.Right)
diff --git a/src/runtime/map_benchmark_test.go b/src/runtime/map_benchmark_test.go
index 025c0398d3..1d9d09c698 100644
--- a/src/runtime/map_benchmark_test.go
+++ b/src/runtime/map_benchmark_test.go
@@ -370,3 +370,37 @@ func BenchmarkGoMapClear(b *testing.B) {
}
})
}
+
+func BenchmarkMapStringConversion(b *testing.B) {
+ for _, length := range []int{32, 64} {
+ b.Run(strconv.Itoa(length), func(b *testing.B) {
+ bytes := make([]byte, length)
+ b.Run("simple", func(b *testing.B) {
+ b.ReportAllocs()
+ m := make(map[string]int)
+ m[string(bytes)] = 0
+ for i := 0; i < b.N; i++ {
+ _ = m[string(bytes)]
+ }
+ })
+ b.Run("struct", func(b *testing.B) {
+ b.ReportAllocs()
+ type stringstruct struct{ s string }
+ m := make(map[stringstruct]int)
+ m[stringstruct{string(bytes)}] = 0
+ for i := 0; i < b.N; i++ {
+ _ = m[stringstruct{string(bytes)}]
+ }
+ })
+ b.Run("array", func(b *testing.B) {
+ b.ReportAllocs()
+ type stringarray [1]string
+ m := make(map[stringarray]int)
+ m[stringarray{string(bytes)}] = 0
+ for i := 0; i < b.N; i++ {
+ _ = m[stringarray{string(bytes)}]
+ }
+ })
+ })
+ }
+}
diff --git a/src/runtime/string.go b/src/runtime/string.go
index d10bd96f43..839e882cdc 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -135,7 +135,8 @@ func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
// and otherwise intrinsified by the compiler.
//
// Some internal compiler optimizations use this function.
-// - Used for m[string(k)] lookup where m is a string-keyed map and k is a []byte.
+// - Used for m[T1{... Tn{..., string(k), ...} ...}] and m[string(k)]
+// where k is []byte, T1 to Tn is a nesting of struct and array literals.
// - Used for "<"+string(b)+">" concatenation where b is []byte.
// - Used for string(b)=="foo" comparison where b is []byte.
func slicebytetostringtmp(b []byte) string {
diff --git a/test/codegen/maps.go b/test/codegen/maps.go
index d167715898..8dd22ed5ca 100644
--- a/test/codegen/maps.go
+++ b/test/codegen/maps.go
@@ -37,6 +37,35 @@ func AccessString2(m map[string]int) bool {
return ok
}
+// ------------------- //
+// String Conversion //
+// ------------------- //
+
+func LookupStringConversionSimple(m map[string]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ return m[string(bytes)]
+}
+
+func LookupStringConversionStructLit(m map[struct{ string }]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ return m[struct{ string }{string(bytes)}]
+}
+
+func LookupStringConversionArrayLit(m map[[2]string]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ return m[[2]string{string(bytes), string(bytes)}]
+}
+
+func LookupStringConversionNestedLit(m map[[1]struct{ s [1]string }]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ return m[[1]struct{ s [1]string }{struct{ s [1]string }{s: [1]string{string(bytes)}}}]
+}
+
+func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ return m[[2]string{0: string(bytes)}]
+}
+
// ------------------- //
// Map Clear //
// ------------------- //
From f81d73e8d57c99d32744e61940dad08c4ec07111 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Sun, 6 May 2018 12:19:25 +0200
Subject: [PATCH 141/240] strconv: add comment explaining bounded shift in
formatBits
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The compiler can generate better code for shifts bounded to be less than 32
and thereby known to be less than any register width.
See https://golang.org/cl/109776.
Change-Id: I0c4c9f0faafa065fce3c10fd328830deb92f9e38
Reviewed-on: https://go-review.googlesource.com/c/111735
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
Reviewed-by: Brad Fitzpatrick
---
src/strconv/itoa.go | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/strconv/itoa.go b/src/strconv/itoa.go
index 8afe7af251..4aaf57830c 100644
--- a/src/strconv/itoa.go
+++ b/src/strconv/itoa.go
@@ -152,10 +152,14 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
}
} else if isPowerOfTwo(base) {
- // It is known that base is a power of two and
- // 2 <= base <= len(digits).
// Use shifts and masks instead of / and %.
- shift := uint(bits.TrailingZeros(uint(base))) & 31
+ // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36.
+ // The largest power of 2 below or equal to 36 is 32, which is 1 << 5;
+ // i.e., the largest possible shift count is 5. By &-ind that value with
+ // the constant 7 we tell the compiler that the shift count is always
+ // less than 8 which is smaller than any register width. This allows
+ // the compiler to generate better code for the shift operation.
+ shift := uint(bits.TrailingZeros(uint(base))) & 7
b := uint64(base)
m := uint(base) - 1 // == 1<= b {
From 3e0227f6a055fff2ceab18ed1ac6bd583a7f94a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20M=C3=B6hrmann?=
Date: Fri, 12 Oct 2018 19:17:21 +0200
Subject: [PATCH 142/240] internal/cpu: add invalid option warnings and support
to enable cpu features
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This CL adds the ability to enable the cpu feature FEATURE by specifying
FEATURE=on in GODEBUGCPU. Syntax support to enable cpu features is useful
in combination with a preceeding all=off to disable all but some specific
cpu features. Example:
GODEBUGCPU=all=off,sse3=on
This CL implements printing of warnings for invalid GODEBUGCPU settings:
- requests enabling features that are not supported with the current CPU
- specifying values different than 'on' or 'off' for a feature
- settings for unkown cpu feature names
Updates #27218
Change-Id: Ic13e5c4c35426a390c50eaa4bd2a408ef2ee21be
Reviewed-on: https://go-review.googlesource.com/c/141800
Run-TryBot: Martin Möhrmann
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/internal/cpu/cpu.go | 70 ++++++++++++++++++++++----------
src/internal/cpu/cpu_arm.go | 4 +-
src/internal/cpu/cpu_arm64.go | 48 +++++++++++-----------
src/internal/cpu/cpu_ppc64x.go | 18 ++++----
src/internal/cpu/cpu_s390x.go | 16 ++++----
src/internal/cpu/cpu_test.go | 5 ++-
src/internal/cpu/cpu_x86.go | 30 +++++++-------
src/internal/cpu/cpu_x86_test.go | 17 ++++++++
8 files changed, 128 insertions(+), 80 deletions(-)
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
index 1f3411cc72..925e4f7f6e 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -153,16 +153,18 @@ var options []option
// Option names should be lower case. e.g. avx instead of AVX.
type option struct {
- Name string
- Feature *bool
+ Name string
+ Feature *bool
+ Specified bool // Stores if feature value was specified in GODEBUGCPU.
+ Enable bool // Stores if feature should be enabled.
}
-// processOptions disables CPU feature values based on the parsed env string.
-// The env string is expected to be of the form feature1=off,feature2=off...
+// processOptions enables or disables CPU feature values based on the parsed env string.
+// The env string is expected to be of the form feature1=value1,feature2=value2...
// where feature names is one of the architecture specifc list stored in the
-// cpu packages options variable. If env contains all=off then all capabilities
-// referenced through the options variable are disabled. Other feature
-// names and values other than 'off' are silently ignored.
+// cpu packages options variable and values are either 'on' or 'off'.
+// If env contains all=off then all cpu features referenced through the options
+// variable are disabled. Other feature names and values result in warning messages.
func processOptions(env string) {
field:
for env != "" {
@@ -175,26 +177,52 @@ field:
}
i = indexByte(field, '=')
if i < 0 {
+ print("GODEBUGCPU: no value specified for \"", field, "\"\n")
continue
}
key, value := field[:i], field[i+1:]
- // Only allow turning off CPU features by specifying 'off'.
- if value == "off" {
- if key == "all" {
- for _, v := range options {
- *v.Feature = false
- }
- return
- } else {
- for _, v := range options {
- if v.Name == key {
- *v.Feature = false
- continue field
- }
- }
+ var enable bool
+ switch value {
+ case "on":
+ enable = true
+ case "off":
+ enable = false
+ default:
+ print("GODEBUGCPU: value \"", value, "\" not supported for option ", key, "\n")
+ continue field
+ }
+
+ if key == "all" {
+ for i := range options {
+ options[i].Specified = true
+ options[i].Enable = enable
+ }
+ continue field
+ }
+
+ for i := range options {
+ if options[i].Name == key {
+ options[i].Specified = true
+ options[i].Enable = enable
+ continue field
}
}
+
+ print("GODEBUGCPU: unknown cpu feature \"", key, "\"\n")
+ }
+
+ for _, o := range options {
+ if !o.Specified {
+ continue
+ }
+
+ if o.Enable && !*o.Feature {
+ print("GODEBUGCPU: can not enable \"", o.Name, "\", missing hardware support\n")
+ continue
+ }
+
+ *o.Feature = o.Enable
}
}
diff --git a/src/internal/cpu/cpu_arm.go b/src/internal/cpu/cpu_arm.go
index 1c3e529190..772b67147c 100644
--- a/src/internal/cpu/cpu_arm.go
+++ b/src/internal/cpu/cpu_arm.go
@@ -21,8 +21,8 @@ const (
func doinit() {
options = []option{
- {"vfpv4", &ARM.HasVFPv4},
- {"idiva", &ARM.HasIDIVA},
+ {Name: "vfpv4", Feature: &ARM.HasVFPv4},
+ {Name: "idiva", Feature: &ARM.HasIDIVA},
}
// HWCAP feature bits
diff --git a/src/internal/cpu/cpu_arm64.go b/src/internal/cpu/cpu_arm64.go
index ad930af005..25482a1f7e 100644
--- a/src/internal/cpu/cpu_arm64.go
+++ b/src/internal/cpu/cpu_arm64.go
@@ -42,32 +42,32 @@ const (
func doinit() {
options = []option{
- {"evtstrm", &ARM64.HasEVTSTRM},
- {"aes", &ARM64.HasAES},
- {"pmull", &ARM64.HasPMULL},
- {"sha1", &ARM64.HasSHA1},
- {"sha2", &ARM64.HasSHA2},
- {"crc32", &ARM64.HasCRC32},
- {"atomics", &ARM64.HasATOMICS},
- {"fphp", &ARM64.HasFPHP},
- {"asimdhp", &ARM64.HasASIMDHP},
- {"cpuid", &ARM64.HasCPUID},
- {"asimdrdm", &ARM64.HasASIMDRDM},
- {"jscvt", &ARM64.HasJSCVT},
- {"fcma", &ARM64.HasFCMA},
- {"lrcpc", &ARM64.HasLRCPC},
- {"dcpop", &ARM64.HasDCPOP},
- {"sha3", &ARM64.HasSHA3},
- {"sm3", &ARM64.HasSM3},
- {"sm4", &ARM64.HasSM4},
- {"asimddp", &ARM64.HasASIMDDP},
- {"sha512", &ARM64.HasSHA512},
- {"sve", &ARM64.HasSVE},
- {"asimdfhm", &ARM64.HasASIMDFHM},
+ {Name: "evtstrm", Feature: &ARM64.HasEVTSTRM},
+ {Name: "aes", Feature: &ARM64.HasAES},
+ {Name: "pmull", Feature: &ARM64.HasPMULL},
+ {Name: "sha1", Feature: &ARM64.HasSHA1},
+ {Name: "sha2", Feature: &ARM64.HasSHA2},
+ {Name: "crc32", Feature: &ARM64.HasCRC32},
+ {Name: "atomics", Feature: &ARM64.HasATOMICS},
+ {Name: "fphp", Feature: &ARM64.HasFPHP},
+ {Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
+ {Name: "cpuid", Feature: &ARM64.HasCPUID},
+ {Name: "asimdrdm", Feature: &ARM64.HasASIMDRDM},
+ {Name: "jscvt", Feature: &ARM64.HasJSCVT},
+ {Name: "fcma", Feature: &ARM64.HasFCMA},
+ {Name: "lrcpc", Feature: &ARM64.HasLRCPC},
+ {Name: "dcpop", Feature: &ARM64.HasDCPOP},
+ {Name: "sha3", Feature: &ARM64.HasSHA3},
+ {Name: "sm3", Feature: &ARM64.HasSM3},
+ {Name: "sm4", Feature: &ARM64.HasSM4},
+ {Name: "asimddp", Feature: &ARM64.HasASIMDDP},
+ {Name: "sha512", Feature: &ARM64.HasSHA512},
+ {Name: "sve", Feature: &ARM64.HasSVE},
+ {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
// These capabilities should always be enabled on arm64:
- // {"fp", &ARM64.HasFP},
- // {"asimd", &ARM64.HasASIMD},
+ // {Name: "fp", Feature: &ARM64.HasFP},
+ // {Name: "asimd", Feature: &ARM64.HasASIMD},
}
// HWCAP feature bits
diff --git a/src/internal/cpu/cpu_ppc64x.go b/src/internal/cpu/cpu_ppc64x.go
index 0195e663c6..b39f5f5bbb 100644
--- a/src/internal/cpu/cpu_ppc64x.go
+++ b/src/internal/cpu/cpu_ppc64x.go
@@ -34,17 +34,17 @@ const (
func doinit() {
options = []option{
- {"htm", &PPC64.HasHTM},
- {"htmnosc", &PPC64.HasHTMNOSC},
- {"darn", &PPC64.HasDARN},
- {"scv", &PPC64.HasSCV},
+ {Name: "htm", Feature: &PPC64.HasHTM},
+ {Name: "htmnosc", Feature: &PPC64.HasHTMNOSC},
+ {Name: "darn", Feature: &PPC64.HasDARN},
+ {Name: "scv", Feature: &PPC64.HasSCV},
// These capabilities should always be enabled on ppc64 and ppc64le:
- // {"vmx", &PPC64.HasVMX},
- // {"dfp", &PPC64.HasDFP},
- // {"vsx", &PPC64.HasVSX},
- // {"isel", &PPC64.HasISEL},
- // {"vcrypto", &PPC64.HasVCRYPTO},
+ // {Name: "vmx", Feature: &PPC64.HasVMX},
+ // {Name: "dfp", Feature: &PPC64.HasDFP},
+ // {Name: "vsx", Feature: &PPC64.HasVSX},
+ // {Name: "isel", Feature: &PPC64.HasISEL},
+ // {Name: "vcrypto", Feature: &PPC64.HasVCRYPTO},
}
// HWCAP feature bits
diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go
index 23484b2950..eab77e6ee5 100644
--- a/src/internal/cpu/cpu_s390x.go
+++ b/src/internal/cpu/cpu_s390x.go
@@ -107,14 +107,14 @@ func klmdQuery() queryResult
func doinit() {
options = []option{
- {"zarch", &S390X.HasZArch},
- {"stfle", &S390X.HasSTFLE},
- {"ldisp", &S390X.HasLDisp},
- {"msa", &S390X.HasMSA},
- {"eimm", &S390X.HasEImm},
- {"dfp", &S390X.HasDFP},
- {"etf3eh", &S390X.HasETF3Enhanced},
- {"vx", &S390X.HasVX},
+ {Name: "zarch", Feature: &S390X.HasZArch},
+ {Name: "stfle", Feature: &S390X.HasSTFLE},
+ {Name: "ldisp", Feature: &S390X.HasLDisp},
+ {Name: "msa", Feature: &S390X.HasMSA},
+ {Name: "eimm", Feature: &S390X.HasEImm},
+ {Name: "dfp", Feature: &S390X.HasDFP},
+ {Name: "etf3eh", Feature: &S390X.HasETF3Enhanced},
+ {Name: "vx", Feature: &S390X.HasVX},
}
aes := []function{aes128, aes192, aes256}
diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go
index 6e7375fa7c..6b4baa1694 100644
--- a/src/internal/cpu/cpu_test.go
+++ b/src/internal/cpu/cpu_test.go
@@ -30,7 +30,10 @@ func runDebugOptionsTest(t *testing.T, test string, options string) {
cmd.Env = append(cmd.Env, env)
output, err := cmd.CombinedOutput()
- got := strings.TrimSpace(string(output))
+ lines := strings.Fields(string(output))
+ lastline := lines[len(lines)-1]
+
+ got := strings.TrimSpace(lastline)
want := "PASS"
if err != nil || got != want {
t.Fatalf("%s with %s: want %s, got %v", test, env, want, got)
diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go
index 0b00779a90..014c8018f3 100644
--- a/src/internal/cpu/cpu_x86.go
+++ b/src/internal/cpu/cpu_x86.go
@@ -40,23 +40,23 @@ const (
func doinit() {
options = []option{
- {"adx", &X86.HasADX},
- {"aes", &X86.HasAES},
- {"avx", &X86.HasAVX},
- {"avx2", &X86.HasAVX2},
- {"bmi1", &X86.HasBMI1},
- {"bmi2", &X86.HasBMI2},
- {"erms", &X86.HasERMS},
- {"fma", &X86.HasFMA},
- {"pclmulqdq", &X86.HasPCLMULQDQ},
- {"popcnt", &X86.HasPOPCNT},
- {"sse3", &X86.HasSSE3},
- {"sse41", &X86.HasSSE41},
- {"sse42", &X86.HasSSE42},
- {"ssse3", &X86.HasSSSE3},
+ {Name: "adx", Feature: &X86.HasADX},
+ {Name: "aes", Feature: &X86.HasAES},
+ {Name: "avx", Feature: &X86.HasAVX},
+ {Name: "avx2", Feature: &X86.HasAVX2},
+ {Name: "bmi1", Feature: &X86.HasBMI1},
+ {Name: "bmi2", Feature: &X86.HasBMI2},
+ {Name: "erms", Feature: &X86.HasERMS},
+ {Name: "fma", Feature: &X86.HasFMA},
+ {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
+ {Name: "popcnt", Feature: &X86.HasPOPCNT},
+ {Name: "sse3", Feature: &X86.HasSSE3},
+ {Name: "sse41", Feature: &X86.HasSSE41},
+ {Name: "sse42", Feature: &X86.HasSSE42},
+ {Name: "ssse3", Feature: &X86.HasSSSE3},
// sse2 set as last element so it can easily be removed again. See code below.
- {"sse2", &X86.HasSSE2},
+ {Name: "sse2", Feature: &X86.HasSSE2},
}
// Remove sse2 from options on amd64(p32) because SSE2 is a mandatory feature for these GOARCHs.
diff --git a/src/internal/cpu/cpu_x86_test.go b/src/internal/cpu/cpu_x86_test.go
index 59c51770c5..a8d0466e06 100644
--- a/src/internal/cpu/cpu_x86_test.go
+++ b/src/internal/cpu/cpu_x86_test.go
@@ -45,3 +45,20 @@ func TestSSE2DebugOption(t *testing.T) {
t.Errorf("X86.HasSSE2 on %s expected %v, got %v", runtime.GOARCH, want, got)
}
}
+
+func TestDisableSSE3(t *testing.T) {
+ runDebugOptionsTest(t, "TestSSE3DebugOption", "sse3=off")
+}
+
+func TestSSE3DebugOption(t *testing.T) {
+ MustHaveDebugOptionsSupport(t)
+
+ if os.Getenv("GODEBUGCPU") != "sse3=off" {
+ t.Skipf("skipping test: GODEBUGCPU=sse3=off not set")
+ }
+
+ want := false
+ if got := X86.HasSSE3; got != want {
+ t.Errorf("X86.HasSSE3 expected %v, got %v", want, got)
+ }
+}
From 7f3313133ee3e40515aa99d3618b8e5eafed42d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=AD?=
Date: Sun, 7 Oct 2018 12:45:56 +0100
Subject: [PATCH 143/240] cmd/compile: don't panic on invalid map key
declarations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In golang.org/cl/75310, the compiler's typechecker was changed so that
map key types were validated at a later stage, to make sure that all the
necessary type information was present.
This still worked for map type declarations, but caused a regression for
top-level map variable declarations. These now caused a fatal panic
instead of a typechecking error.
The cause was that checkMapKeys was run too early, before all
typechecking was done. In particular, top-level map variable
declarations are typechecked as external declarations, much later than
where checkMapKeys was run.
Add a test case for both exported and unexported top-level map
declarations, and add a second call to checkMapKeys at the actual end of
typechecking. Simply moving the one call isn't a good solution either;
the comments expand on that.
Fixes #28058.
Change-Id: Ia5febb01a1d877447cf66ba44fb49a7e0f4f18a5
Reviewed-on: https://go-review.googlesource.com/c/140417
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/gc/main.go | 7 ++++++-
test/fixedbugs/issue28058.go | 13 +++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
create mode 100644 test/fixedbugs/issue28058.go
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 02aec32685..9a226318b9 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -534,7 +534,9 @@ func Main(archInit func(*Arch)) {
fcount++
}
}
- // With all types ckecked, it's now safe to verify map keys.
+ // With all types ckecked, it's now safe to verify map keys. One single
+ // check past phase 9 isn't sufficient, as we may exit with other errors
+ // before then, thus skipping map key errors.
checkMapKeys()
timings.AddEvent(fcount, "funcs")
@@ -678,6 +680,9 @@ func Main(archInit func(*Arch)) {
externdcl[i] = typecheck(externdcl[i], Erv)
}
}
+ // Check the map keys again, since we typechecked the external
+ // declarations.
+ checkMapKeys()
if nerrors+nsavederrors != 0 {
errorexit()
diff --git a/test/fixedbugs/issue28058.go b/test/fixedbugs/issue28058.go
new file mode 100644
index 0000000000..d8206e7357
--- /dev/null
+++ b/test/fixedbugs/issue28058.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 14988: declaring a map with an invalid key type should not cause a
+// fatal panic.
+
+package main
+
+var x map[func()]int // ERROR "invalid map key type"
+var X map[func()]int // ERROR "invalid map key type"
From 3785be3093ef8a8ea3c71ff9608451de1ad85db8 Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Tue, 16 Oct 2018 04:02:03 +0000
Subject: [PATCH 144/240] test/codegen: fix confusing test cases
ARMv7's MULAF/MULSF/MULAD/MULSD are not fused,
this CL fixes the confusing test cases.
Change-Id: I35022e207e2f0d24a23a7f6f188e41ba8eee9886
Reviewed-on: https://go-review.googlesource.com/c/142439
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Akhil Indurti
Reviewed-by: Giovanni Bajo
---
test/codegen/floats.go | 4 ----
1 file changed, 4 deletions(-)
diff --git a/test/codegen/floats.go b/test/codegen/floats.go
index 847959c42e..c20f6984bf 100644
--- a/test/codegen/floats.go
+++ b/test/codegen/floats.go
@@ -72,7 +72,6 @@ func indexStore(b0 []float64, b1 float64, idx int) {
func FusedAdd32(x, y, z float32) float32 {
// s390x:"FMADDS\t"
// ppc64le:"FMADDS\t"
- // arm/7:"MULAF"
// arm64:"FMADDS"
return x*y + z
}
@@ -84,7 +83,6 @@ func FusedSub32_a(x, y, z float32) float32 {
}
func FusedSub32_b(x, y, z float32) float32 {
- // arm/7:"MULSF"
// arm64:"FMSUBS"
return z - x*y
}
@@ -92,7 +90,6 @@ func FusedSub32_b(x, y, z float32) float32 {
func FusedAdd64(x, y, z float64) float64 {
// s390x:"FMADD\t"
// ppc64le:"FMADD\t"
- // arm/7:"MULAD"
// arm64:"FMADDD"
return x*y + z
}
@@ -104,7 +101,6 @@ func FusedSub64_a(x, y, z float64) float64 {
}
func FusedSub64_b(x, y, z float64) float64 {
- // arm/7:"MULSD"
// arm64:"FMSUBD"
return z - x*y
}
From 4b78fe57a81fe4fd9a1c370c65e3a694066ac1ab Mon Sep 17 00:00:00 2001
From: Ben Shi
Date: Mon, 15 Oct 2018 01:19:48 +0000
Subject: [PATCH 145/240] cmd/compile: optimize 386's load/store combination
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This CL adds more combinations of two consequtive MOVBload/MOVBstore
to a unique MOVWload/MOVWstore.
1. The size of the go executable decreases about 4KB, and the total
size of pkg/linux_386 (excluding cmd/compile) decreases about 1.5KB.
2. There is no regression in the go1 benchmark result, excluding noise.
name old time/op new time/op delta
BinaryTree17-4 3.28s ± 2% 3.29s ± 2% ~ (p=0.151 n=40+40)
Fannkuch11-4 3.52s ± 1% 3.51s ± 1% -0.28% (p=0.002 n=40+40)
FmtFprintfEmpty-4 45.4ns ± 4% 45.0ns ± 4% -0.89% (p=0.019 n=40+40)
FmtFprintfString-4 81.9ns ± 7% 81.3ns ± 1% ~ (p=0.660 n=40+25)
FmtFprintfInt-4 91.9ns ± 9% 91.4ns ± 9% ~ (p=0.249 n=40+40)
FmtFprintfIntInt-4 143ns ± 4% 143ns ± 4% ~ (p=0.760 n=40+40)
FmtFprintfPrefixedInt-4 184ns ± 3% 183ns ± 4% ~ (p=0.485 n=40+40)
FmtFprintfFloat-4 408ns ± 3% 409ns ± 3% ~ (p=0.961 n=40+40)
FmtManyArgs-4 597ns ± 4% 602ns ± 3% ~ (p=0.413 n=40+40)
GobDecode-4 7.13ms ± 6% 7.14ms ± 6% ~ (p=0.859 n=40+40)
GobEncode-4 6.86ms ± 9% 6.94ms ± 7% ~ (p=0.162 n=40+40)
Gzip-4 395ms ± 4% 396ms ± 3% ~ (p=0.099 n=40+40)
Gunzip-4 40.9ms ± 4% 41.1ms ± 3% ~ (p=0.064 n=40+40)
HTTPClientServer-4 63.6µs ± 2% 63.6µs ± 3% ~ (p=0.832 n=36+39)
JSONEncode-4 16.1ms ± 3% 15.8ms ± 3% -1.60% (p=0.001 n=40+40)
JSONDecode-4 61.0ms ± 3% 61.5ms ± 4% ~ (p=0.065 n=40+40)
Mandelbrot200-4 5.16ms ± 3% 5.18ms ± 3% ~ (p=0.056 n=40+40)
GoParse-4 3.25ms ± 2% 3.23ms ± 3% ~ (p=0.727 n=40+40)
RegexpMatchEasy0_32-4 90.2ns ± 3% 89.3ns ± 6% -0.98% (p=0.002 n=40+40)
RegexpMatchEasy0_1K-4 812ns ± 3% 815ns ± 3% ~ (p=0.309 n=40+40)
RegexpMatchEasy1_32-4 103ns ± 6% 103ns ± 5% ~ (p=0.680 n=40+40)
RegexpMatchEasy1_1K-4 1.01µs ± 4% 1.02µs ± 3% ~ (p=0.326 n=40+33)
RegexpMatchMedium_32-4 120ns ± 4% 120ns ± 5% ~ (p=0.834 n=40+40)
RegexpMatchMedium_1K-4 40.1µs ± 3% 39.5µs ± 4% -1.35% (p=0.000 n=40+40)
RegexpMatchHard_32-4 2.27µs ± 6% 2.23µs ± 4% -1.67% (p=0.011 n=40+40)
RegexpMatchHard_1K-4 67.2µs ± 3% 67.2µs ± 3% ~ (p=0.149 n=40+40)
Revcomp-4 1.84s ± 2% 1.86s ± 3% +0.70% (p=0.020 n=40+40)
Template-4 69.0ms ± 4% 69.8ms ± 3% +1.20% (p=0.003 n=40+40)
TimeParse-4 438ns ± 3% 439ns ± 4% ~ (p=0.650 n=40+40)
TimeFormat-4 412ns ± 3% 412ns ± 3% ~ (p=0.888 n=40+40)
[Geo mean] 65.2µs 65.2µs -0.04%
name old speed new speed delta
GobDecode-4 108MB/s ± 6% 108MB/s ± 6% ~ (p=0.855 n=40+40)
GobEncode-4 112MB/s ± 9% 111MB/s ± 8% ~ (p=0.159 n=40+40)
Gzip-4 49.2MB/s ± 4% 49.1MB/s ± 3% ~ (p=0.102 n=40+40)
Gunzip-4 474MB/s ± 3% 472MB/s ± 3% ~ (p=0.063 n=40+40)
JSONEncode-4 121MB/s ± 3% 123MB/s ± 3% +1.62% (p=0.001 n=40+40)
JSONDecode-4 31.9MB/s ± 3% 31.6MB/s ± 4% ~ (p=0.070 n=40+40)
GoParse-4 17.9MB/s ± 2% 17.9MB/s ± 3% ~ (p=0.696 n=40+40)
RegexpMatchEasy0_32-4 355MB/s ± 3% 358MB/s ± 5% +0.99% (p=0.002 n=40+40)
RegexpMatchEasy0_1K-4 1.26GB/s ± 3% 1.26GB/s ± 3% ~ (p=0.381 n=40+40)
RegexpMatchEasy1_32-4 310MB/s ± 5% 310MB/s ± 4% ~ (p=0.655 n=40+40)
RegexpMatchEasy1_1K-4 1.01GB/s ± 4% 1.01GB/s ± 3% ~ (p=0.351 n=40+33)
RegexpMatchMedium_32-4 8.32MB/s ± 4% 8.34MB/s ± 5% ~ (p=0.696 n=40+40)
RegexpMatchMedium_1K-4 25.6MB/s ± 3% 25.9MB/s ± 4% +1.36% (p=0.000 n=40+40)
RegexpMatchHard_32-4 14.1MB/s ± 6% 14.3MB/s ± 4% +1.64% (p=0.011 n=40+40)
RegexpMatchHard_1K-4 15.2MB/s ± 3% 15.2MB/s ± 3% ~ (p=0.147 n=40+40)
Revcomp-4 138MB/s ± 2% 137MB/s ± 3% -0.70% (p=0.021 n=40+40)
Template-4 28.1MB/s ± 4% 27.8MB/s ± 3% -1.19% (p=0.003 n=40+40)
[Geo mean] 83.7MB/s 83.7MB/s +0.03%
Change-Id: I2a2b3a942b5c45467491515d201179fd192e65c9
Reviewed-on: https://go-review.googlesource.com/c/141650
Run-TryBot: Ben Shi
TryBot-Result: Gobot Gobot
Reviewed-by: Keith Randall
---
src/cmd/compile/internal/ssa/gen/386.rules | 12 +-
src/cmd/compile/internal/ssa/rewrite386.go | 751 ++++++++++++++++++++-
test/codegen/memcombine.go | 18 +
3 files changed, 774 insertions(+), 7 deletions(-)
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index e8d19cf3c9..3a54a2a206 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -1151,10 +1151,14 @@
-> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLLconst [1] i) mem)
// Combine stores into larger (unaligned) stores.
-(MOVBstore [i] {s} p (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
&& x.Uses == 1
&& clobber(x)
-> (MOVWstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p w x:(MOVBstore {s} [i+1] p (SHR(W|L)const [8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i] {s} p w mem)
(MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
&& x.Uses == 1
&& clobber(x)
@@ -1168,10 +1172,14 @@
&& clobber(x)
-> (MOVLstore [i-2] {s} p w0 mem)
-(MOVBstoreidx1 [i] {s} p idx (SHRLconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+(MOVBstoreidx1 [i] {s} p idx (SHR(L|W)const [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
&& x.Uses == 1
&& clobber(x)
-> (MOVWstoreidx1 [i-1] {s} p idx w mem)
+(MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHR(L|W)const [8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx1 [i] {s} p idx w mem)
(MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
&& x.Uses == 1
&& clobber(x)
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 14784bef3a..2fce9c151e 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -106,13 +106,13 @@ func rewriteValue386(v *Value) bool {
case Op386MOVBloadidx1:
return rewriteValue386_Op386MOVBloadidx1_0(v)
case Op386MOVBstore:
- return rewriteValue386_Op386MOVBstore_0(v)
+ return rewriteValue386_Op386MOVBstore_0(v) || rewriteValue386_Op386MOVBstore_10(v)
case Op386MOVBstoreconst:
return rewriteValue386_Op386MOVBstoreconst_0(v)
case Op386MOVBstoreconstidx1:
return rewriteValue386_Op386MOVBstoreconstidx1_0(v)
case Op386MOVBstoreidx1:
- return rewriteValue386_Op386MOVBstoreidx1_0(v) || rewriteValue386_Op386MOVBstoreidx1_10(v)
+ return rewriteValue386_Op386MOVBstoreidx1_0(v) || rewriteValue386_Op386MOVBstoreidx1_10(v) || rewriteValue386_Op386MOVBstoreidx1_20(v)
case Op386MOVLload:
return rewriteValue386_Op386MOVLload_0(v)
case Op386MOVLloadidx1:
@@ -5545,6 +5545,51 @@ func rewriteValue386_Op386MOVBstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstore [i] {s} p (SHRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHRWconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[2]
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVBstore [i] {s} p (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstore [i-1] {s} p w mem)
@@ -5590,6 +5635,99 @@ func rewriteValue386_Op386MOVBstore_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstore [i] {s} p w x:(MOVBstore {s} [i+1] p (SHRWconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ w := v.Args[1]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstore {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[2]
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != Op386SHRWconst {
+ break
+ }
+ if x_1.AuxInt != 8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstore_10(v *Value) bool {
+ // match: (MOVBstore [i] {s} p w x:(MOVBstore {s} [i+1] p (SHRLconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ w := v.Args[1]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstore {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[2]
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != Op386SHRLconst {
+ break
+ }
+ if x_1.AuxInt != 8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstore [i-1] {s} p w0 mem)
@@ -6166,6 +6304,612 @@ func rewriteValue386_Op386MOVBstoreidx1_0(v *Value) bool {
v.AddArg(mem)
return true
}
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRWconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386SHRWconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRWconst [8] w) x:(MOVBstoreidx1 [i-1] {s} idx p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386SHRWconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstoreidx1_10(v *Value) bool {
+ // match: (MOVBstoreidx1 [i] {s} idx p (SHRWconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386SHRWconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} idx p (SHRWconst [8] w) x:(MOVBstoreidx1 [i-1] {s} idx p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386SHRWconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRLconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRLconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} idx p (SHRLconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRLconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} idx p w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRLconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRLconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} idx p w x:(MOVBstoreidx1 [i+1] {s} idx p (SHRLconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRLconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRWconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRWconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} idx p (SHRWconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ p := v.Args[0]
+ idx := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRWconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} idx p w x:(MOVBstoreidx1 [i+1] {s} p idx (SHRWconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRWconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} idx p w x:(MOVBstoreidx1 [i+1] {s} idx p (SHRWconst [8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i] {s} p idx w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[3]
+ idx := v.Args[0]
+ p := v.Args[1]
+ w := v.Args[2]
+ x := v.Args[3]
+ if x.Op != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i+1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ _ = x.Args[3]
+ if idx != x.Args[0] {
+ break
+ }
+ if p != x.Args[1] {
+ break
+ }
+ x_2 := x.Args[2]
+ if x_2.Op != Op386SHRWconst {
+ break
+ }
+ if x_2.AuxInt != 8 {
+ break
+ }
+ if w != x_2.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstoreidx1_20(v *Value) bool {
// match: (MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
@@ -6276,9 +7020,6 @@ func rewriteValue386_Op386MOVBstoreidx1_0(v *Value) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValue386_Op386MOVBstoreidx1_10(v *Value) bool {
// match: (MOVBstoreidx1 [i] {s} idx p (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go
index 230aadfb74..d0043da7ef 100644
--- a/test/codegen/memcombine.go
+++ b/test/codegen/memcombine.go
@@ -113,11 +113,13 @@ func load_be16_idx(b []byte, idx int) {
func load_le_byte2_uint16(s []byte) uint16 {
// arm64:`MOVHU\t\(R[0-9]+\)`,-`ORR`,-`MOVB`
+ // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL`
return uint16(s[0]) | uint16(s[1])<<8
}
func load_le_byte2_uint16_inv(s []byte) uint16 {
// arm64:`MOVHU\t\(R[0-9]+\)`,-`ORR`,-`MOVB`
+ // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL`
return uint16(s[1])<<8 | uint16(s[0])
}
@@ -173,11 +175,13 @@ func load_be_byte8_uint64_inv(s []byte) uint64 {
func load_le_byte2_uint16_idx(s []byte, idx int) uint16 {
// arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOVB`
+ // 386:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`ORL`,-`MOVB`
return uint16(s[idx]) | uint16(s[idx+1])<<8
}
func load_le_byte2_uint16_idx_inv(s []byte, idx int) uint16 {
// arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOVB`
+ // 386:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`ORL`,-`MOVB`
return uint16(s[idx+1])<<8 | uint16(s[idx])
}
@@ -405,9 +409,16 @@ func store_be16_idx(b []byte, idx int) {
func store_le_byte_2(b []byte, val uint16) {
_ = b[2]
// arm64:`MOVH\sR[0-9]+,\s1\(R[0-9]+\)`,-`MOVB`
+ // 386:`MOVW\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`
b[1], b[2] = byte(val), byte(val>>8)
}
+func store_le_byte_2_inv(b []byte, val uint16) {
+ _ = b[2]
+ // 386:`MOVW\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`
+ b[2], b[1] = byte(val>>8), byte(val)
+}
+
func store_le_byte_4(b []byte, val uint32) {
_ = b[4]
// arm64:`MOVW\sR[0-9]+,\s1\(R[0-9]+\)`,-`MOVB`,-`MOVH`
@@ -441,9 +452,16 @@ func store_be_byte_8(b []byte, val uint64) {
func store_le_byte_2_idx(b []byte, idx int, val uint16) {
_, _ = b[idx+0], b[idx+1]
// arm64:`MOVH\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOVB`
+ // 386:`MOVW\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+`,-`MOVB`
b[idx+1], b[idx+0] = byte(val>>8), byte(val)
}
+func store_le_byte_2_idx_inv(b []byte, idx int, val uint16) {
+ _, _ = b[idx+0], b[idx+1]
+ // 386:`MOVW\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+`,-`MOVB`
+ b[idx+0], b[idx+1] = byte(val), byte(val>>8)
+}
+
func store_le_byte_4_idx(b []byte, idx int, val uint32) {
_, _, _, _ = b[idx+0], b[idx+1], b[idx+2], b[idx+3]
// arm64:`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOVB`,-`MOVH`
From 5eff6bfdbc837f8099503566ffe52e5174e804a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=AD?=
Date: Tue, 16 Oct 2018 12:04:55 +0100
Subject: [PATCH 146/240] encoding/json: fix "data changed underfoot?" panic
Given a program as follows:
data := []byte(`{"F": {
"a": 2,
"3": 4
}}`)
json.Unmarshal(data, &map[string]map[int]int{})
The JSON package should error, as "a" is not a valid integer. However,
we'd encounter a panic:
panic: JSON decoder out of sync - data changing underfoot?
The reason was that decodeState.object would return a nil error on
encountering the invalid map key string, while saving the key type error
for later. This broke if we were inside another object, as we would
abruptly end parsing the nested object, leaving the decoder in an
unexpected state.
To fix this, simply avoid storing the map element and continue decoding
the object, to leave the decoder state exactly as if we hadn't seen an
invalid key type.
This affected both signed and unsigned integer keys, so fix both and add
two test cases.
Updates #28189.
Change-Id: I8a6204cc3ff9fb04ed769df7a20a824c8b94faff
Reviewed-on: https://go-review.googlesource.com/c/142518
Reviewed-by: Ian Lance Taylor
---
src/encoding/json/decode.go | 8 +++++---
src/encoding/json/decode_test.go | 10 ++++++++++
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index cab4616ba3..6608415e13 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -786,7 +786,7 @@ func (d *decodeState) object(v reflect.Value) error {
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || reflect.Zero(kt).OverflowInt(n) {
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
- return nil
+ break
}
kv = reflect.ValueOf(n).Convert(kt)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -794,14 +794,16 @@ func (d *decodeState) object(v reflect.Value) error {
n, err := strconv.ParseUint(s, 10, 64)
if err != nil || reflect.Zero(kt).OverflowUint(n) {
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
- return nil
+ break
}
kv = reflect.ValueOf(n).Convert(kt)
default:
panic("json: Unexpected key type") // should never occur
}
}
- v.SetMapIndex(kv, subv)
+ if kv.IsValid() {
+ v.SetMapIndex(kv, subv)
+ }
}
// Next token must be , or }.
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 5fbe67a706..70731a62d6 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -554,6 +554,16 @@ var unmarshalTests = []unmarshalTest{
ptr: new(map[uint8]string),
err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2},
},
+ {
+ in: `{"F":{"a":2,"3":4}}`,
+ ptr: new(map[string]map[int]int),
+ err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(int(0)), Offset: 7},
+ },
+ {
+ in: `{"F":{"a":2,"3":4}}`,
+ ptr: new(map[string]map[uint]int),
+ err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(uint(0)), Offset: 7},
+ },
// Map keys can be encoding.TextUnmarshalers.
{in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY},
From 4b36e129f865f802eb87f7aa2b25e3297c5d8cfd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=AD?=
Date: Thu, 11 Oct 2018 14:43:47 +0100
Subject: [PATCH 147/240] encoding/json: always verify we can get a field's
value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Calling .Interface on a struct field's reflect.Value isn't always safe.
For example, if that field is an unexported anonymous struct.
We only descended into this branch if the struct type had any methods,
so this bug had gone unnoticed for a few release cycles.
Add the check, and add a simple test case.
Fixes #28145.
Change-Id: I02f7e0ab9a4a0c18a5e2164211922fe9c3d30f64
Reviewed-on: https://go-review.googlesource.com/c/141537
Run-TryBot: Daniel Martí
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/encoding/json/decode.go | 2 +-
src/encoding/json/decode_test.go | 15 +++++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 6608415e13..731553dca6 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -473,7 +473,7 @@ func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnm
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
- if v.Type().NumMethod() > 0 {
+ if v.Type().NumMethod() > 0 && v.CanInterface() {
if u, ok := v.Interface().(Unmarshaler); ok {
return u, nil, reflect.Value{}
}
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 70731a62d6..54432600a5 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -266,6 +266,10 @@ type XYZ struct {
Z interface{}
}
+type unexportedWithMethods struct{}
+
+func (unexportedWithMethods) F() {}
+
func sliceAddr(x []int) *[]int { return &x }
func mapAddr(x map[string]int) *map[string]int { return &x }
@@ -2151,6 +2155,9 @@ func TestInvalidStringOption(t *testing.T) {
//
// (Issue 24152) If the embedded struct is given an explicit name,
// ensure that the normal unmarshal logic does not panic in reflect.
+//
+// (Issue 28145) If the embedded struct is given an explicit name and has
+// exported methods, don't cause a panic trying to get its value.
func TestUnmarshalEmbeddedUnexported(t *testing.T) {
type (
embed1 struct{ Q int }
@@ -2190,6 +2197,9 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
embed2 `json:"embed2"`
Q int
}
+ S9 struct {
+ unexportedWithMethods `json:"embed"`
+ }
)
tests := []struct {
@@ -2251,6 +2261,11 @@ func TestUnmarshalEmbeddedUnexported(t *testing.T) {
in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
ptr: new(S8),
out: &S8{embed1{1}, embed2{2}, 3},
+ }, {
+ // Issue 228145, similar to the cases above.
+ in: `{"embed": {}}`,
+ ptr: new(S9),
+ out: &S9{},
}}
for i, tt := range tests {
From 39fa301bdc5cd99e4f71d7da5f6f38a6f313d611 Mon Sep 17 00:00:00 2001
From: Lynn Boger
Date: Mon, 15 Oct 2018 12:53:07 -0400
Subject: [PATCH 148/240] test/codegen: enable more tests for ppc64/ppc64le
Adding cases for ppc64,ppc64le to the codegen tests
where appropriate.
Change-Id: Idf8cbe88a4ab4406a4ef1ea777bd15a58b68f3ed
Reviewed-on: https://go-review.googlesource.com/c/142557
Run-TryBot: Lynn Boger
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
test/codegen/arithmetic.go | 22 +++++++++++++++++++
test/codegen/comparisons.go | 1 +
test/codegen/copy.go | 7 +++++++
test/codegen/floats.go | 12 +++++++++++
test/codegen/math.go | 15 +++++++++++++
test/codegen/mathbits.go | 20 ++++++++++++++++--
test/codegen/noextend.go | 42 +++++++++++++++++++++++++++++++++++++
test/codegen/rotate.go | 8 +++++++
test/codegen/stack.go | 5 +++++
9 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index b1cdef6eee..d91eb16edb 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -48,12 +48,16 @@ func Pow2Muls(n1, n2 int) (int, int) {
// 386:"SHLL\t[$]5",-"IMULL"
// arm:"SLL\t[$]5",-"MUL"
// arm64:"LSL\t[$]5",-"MUL"
+ // ppc64:"SLD\t[$]5",-"MUL"
+ // ppc64le:"SLD\t[$]5",-"MUL"
a := n1 * 32
// amd64:"SHLQ\t[$]6",-"IMULQ"
// 386:"SHLL\t[$]6",-"IMULL"
// arm:"SLL\t[$]6",-"MUL"
// arm64:`NEG\sR[0-9]+<<6,\sR[0-9]+`,-`LSL`,-`MUL`
+ // ppc64:"SLD\t[$]6","NEG\\sR[0-9]+,\\sR[0-9]+",-"MUL"
+ // ppc64le:"SLD\t[$]6","NEG\\sR[0-9]+,\\sR[0-9]+",-"MUL"
b := -64 * n2
return a, b
@@ -117,12 +121,16 @@ func Pow2Divs(n1 uint, n2 int) (uint, int) {
// amd64:"SHRQ\t[$]5",-"DIVQ"
// arm:"SRL\t[$]5",-".*udiv"
// arm64:"LSR\t[$]5",-"UDIV"
+ // ppc64:"SRD"
+ // ppc64le:"SRD"
a := n1 / 32 // unsigned
// amd64:"SARQ\t[$]6",-"IDIVQ"
// 386:"SARL\t[$]6",-"IDIVL"
// arm:"SRA\t[$]6",-".*udiv"
// arm64:"ASR\t[$]6",-"SDIV"
+ // ppc64:"SRAD"
+ // ppc64le:"SRAD"
b := n2 / 64 // signed
return a, b
@@ -149,6 +157,8 @@ func Pow2Mods(n1 uint, n2 int) (uint, int) {
// amd64:"ANDQ\t[$]31",-"DIVQ"
// arm:"AND\t[$]31",-".*udiv"
// arm64:"AND\t[$]31",-"UDIV"
+ // ppc64:"ANDCC\t[$]31"
+ // ppc64le:"ANDCC\t[$]31"
a := n1 % 32 // unsigned
// 386:-"IDIVL"
@@ -177,36 +187,48 @@ func ConstMods(n1 uint, n2 int) (uint, int) {
func LenDiv1(a []int) int {
// 386:"SHRL\t[$]10"
// amd64:"SHRQ\t[$]10"
+ // ppc64:"SRD"\t[$]10"
+ // ppc64le:"SRD"\t[$]10"
return len(a) / 1024
}
func LenDiv2(s string) int {
// 386:"SHRL\t[$]11"
// amd64:"SHRQ\t[$]11"
+ // ppc64:"SRD\t[$]11"
+ // ppc64le:"SRD\t[$]11"
return len(s) / (4097 >> 1)
}
func LenMod1(a []int) int {
// 386:"ANDL\t[$]1023"
// amd64:"ANDQ\t[$]1023"
+ // ppc64:"ANDCC\t[$]1023"
+ // ppc64le:"ANDCC\t[$]1023"
return len(a) % 1024
}
func LenMod2(s string) int {
// 386:"ANDL\t[$]2047"
// amd64:"ANDQ\t[$]2047"
+ // ppc64:"ANDCC\t[$]2047"
+ // ppc64le:"ANDCC\t[$]2047"
return len(s) % (4097 >> 1)
}
func CapDiv(a []int) int {
// 386:"SHRL\t[$]12"
// amd64:"SHRQ\t[$]12"
+ // ppc64:"SRD\t[$]12"
+ // ppc64le:"SRD\t[$]12"
return cap(a) / ((1 << 11) + 2048)
}
func CapMod(a []int) int {
// 386:"ANDL\t[$]4095"
// amd64:"ANDQ\t[$]4095"
+ // ppc64:"ANDCC\t[$]4095"
+ // ppc64le:"ANDCC\t[$]4095"
return cap(a) % ((1 << 11) + 2048)
}
diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go
index 072393f3a6..fb17d3ca5d 100644
--- a/test/codegen/comparisons.go
+++ b/test/codegen/comparisons.go
@@ -36,6 +36,7 @@ func CompareString2(s string) bool {
func CompareString3(s string) bool {
// amd64:`CMPQ\t\(.*\), [A-Z]`
// arm64:-`CMPW\t`
+ // ppc64:-`CMPW\t`
// ppc64le:-`CMPW\t`
// s390x:-`CMPW\t`
return s == "xxxxxxxx"
diff --git a/test/codegen/copy.go b/test/codegen/copy.go
index dc8ee43f4c..46c2bde9ab 100644
--- a/test/codegen/copy.go
+++ b/test/codegen/copy.go
@@ -16,6 +16,8 @@ func movesmall4() {
// amd64:-".*memmove"
// arm:-".*memmove"
// arm64:-".*memmove"
+ // ppc64:-".*memmove"
+ // ppc64le:-".*memmove"
copy(x[1:], x[:])
}
@@ -24,6 +26,8 @@ func movesmall7() {
// 386:-".*memmove"
// amd64:-".*memmove"
// arm64:-".*memmove"
+ // ppc64:-".*memmove"
+ // ppc64le:-".*memmove"
copy(x[1:], x[:])
}
@@ -63,6 +67,7 @@ func moveDisjointNoOverlap(a *[256]byte) {
func ptrEqual() {
// amd64:-"JEQ",-"JNE"
+ // ppc64:-"BEQ",-"BNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[:], x[:])
@@ -70,6 +75,7 @@ func ptrEqual() {
func ptrOneOffset() {
// amd64:-"JEQ",-"JNE"
+ // ppc64:-"BEQ",-"BNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[1:], x[:])
@@ -77,6 +83,7 @@ func ptrOneOffset() {
func ptrBothOffset() {
// amd64:-"JEQ",-"JNE"
+ // ppc64:-"BEQ",-"BNE"
// ppc64le:-"BEQ",-"BNE"
// s390x:-"BEQ",-"BNE"
copy(x[1:], x[2:])
diff --git a/test/codegen/floats.go b/test/codegen/floats.go
index c20f6984bf..5e1f60b08b 100644
--- a/test/codegen/floats.go
+++ b/test/codegen/floats.go
@@ -22,6 +22,8 @@ func Mul2(f float64) float64 {
// amd64:"ADDSD",-"MULSD"
// arm/7:"ADDD",-"MULD"
// arm64:"FADDD",-"FMULD"
+ // ppc64:"FADD",-"FMUL"
+ // ppc64le:"FADD",-"FMUL"
return f * 2.0
}
@@ -31,6 +33,8 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// amd64:"MULSD",-"DIVSD"
// arm/7:"MULD",-"DIVD"
// arm64:"FMULD",-"FDIVD"
+ // ppc64:"FMUL",-"FDIV"
+ // ppc64le:"FMUL",-"FDIV"
x := f1 / 16.0
// 386/sse2:"MULSD",-"DIVSD"
@@ -38,6 +42,8 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// amd64:"MULSD",-"DIVSD"
// arm/7:"MULD",-"DIVD"
// arm64:"FMULD",-"FDIVD"
+ // ppc64:"FMUL",-"FDIVD"
+ // ppc64le:"FMUL",-"FDIVD"
y := f2 / 0.125
// 386/sse2:"ADDSD",-"DIVSD",-"MULSD"
@@ -45,6 +51,8 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// amd64:"ADDSD",-"DIVSD",-"MULSD"
// arm/7:"ADDD",-"MULD",-"DIVD"
// arm64:"FADDD",-"FMULD",-"FDIVD"
+ // ppc64:"FADD",-"FMUL",-"FDIV"
+ // ppc64le:"FADD",-"FMUL",-"FDIV"
z := f3 / 0.5
return x, y, z
@@ -71,6 +79,7 @@ func indexStore(b0 []float64, b1 float64, idx int) {
func FusedAdd32(x, y, z float32) float32 {
// s390x:"FMADDS\t"
+ // ppc64:"FMADDS\t"
// ppc64le:"FMADDS\t"
// arm64:"FMADDS"
return x*y + z
@@ -78,6 +87,7 @@ func FusedAdd32(x, y, z float32) float32 {
func FusedSub32_a(x, y, z float32) float32 {
// s390x:"FMSUBS\t"
+ // ppc64:"FMSUBS\t"
// ppc64le:"FMSUBS\t"
return x*y - z
}
@@ -89,6 +99,7 @@ func FusedSub32_b(x, y, z float32) float32 {
func FusedAdd64(x, y, z float64) float64 {
// s390x:"FMADD\t"
+ // ppc64:"FMADD\t"
// ppc64le:"FMADD\t"
// arm64:"FMADDD"
return x*y + z
@@ -96,6 +107,7 @@ func FusedAdd64(x, y, z float64) float64 {
func FusedSub64_a(x, y, z float64) float64 {
// s390x:"FMSUB\t"
+ // ppc64:"FMSUB\t"
// ppc64le:"FMSUB\t"
return x*y - z
}
diff --git a/test/codegen/math.go b/test/codegen/math.go
index 78e7bfa110..aaf6b080ff 100644
--- a/test/codegen/math.go
+++ b/test/codegen/math.go
@@ -13,21 +13,25 @@ var sink64 [8]float64
func approx(x float64) {
// s390x:"FIDBR\t[$]6"
// arm64:"FRINTPD"
+ // ppc64:"FRIP"
// ppc64le:"FRIP"
sink64[0] = math.Ceil(x)
// s390x:"FIDBR\t[$]7"
// arm64:"FRINTMD"
+ // ppc64:"FRIM"
// ppc64le:"FRIM"
sink64[1] = math.Floor(x)
// s390x:"FIDBR\t[$]1"
// arm64:"FRINTAD"
+ // ppc64:"FRIN"
// ppc64le:"FRIN"
sink64[2] = math.Round(x)
// s390x:"FIDBR\t[$]5"
// arm64:"FRINTZD"
+ // ppc64:"FRIZ"
// ppc64le:"FRIZ"
sink64[3] = math.Trunc(x)
@@ -51,11 +55,13 @@ func abs(x, y float64) {
// amd64:"BTRQ\t[$]63"
// arm64:"FABSD\t"
// s390x:"LPDFR\t",-"MOVD\t" (no integer load/store)
+ // ppc64:"FABS\t"
// ppc64le:"FABS\t"
sink64[0] = math.Abs(x)
// amd64:"BTRQ\t[$]63","PXOR" (TODO: this should be BTSQ)
// s390x:"LNDFR\t",-"MOVD\t" (no integer load/store)
+ // ppc64:"FNABS\t"
// ppc64le:"FNABS\t"
sink64[1] = -math.Abs(y)
}
@@ -70,11 +76,13 @@ func abs32(x float32) float32 {
func copysign(a, b, c float64) {
// amd64:"BTRQ\t[$]63","SHRQ\t[$]63","SHLQ\t[$]63","ORQ"
// s390x:"CPSDR",-"MOVD" (no integer load/store)
+ // ppc64:"FCPSGN"
// ppc64le:"FCPSGN"
sink64[0] = math.Copysign(a, b)
// amd64:"BTSQ\t[$]63"
// s390x:"LNDFR\t",-"MOVD\t" (no integer load/store)
+ // ppc64:"FCPSGN"
// ppc64le:"FCPSGN"
// arm64:"ORR", -"AND"
sink64[1] = math.Copysign(c, -1)
@@ -86,6 +94,7 @@ func copysign(a, b, c float64) {
// amd64:-"SHLQ\t[$]1",-"SHRQ\t[$]1","SHRQ\t[$]63","SHLQ\t[$]63","ORQ"
// s390x:"CPSDR\t",-"MOVD\t" (no integer load/store)
+ // ppc64:"FCPSGN"
// ppc64le:"FCPSGN"
sink64[3] = math.Copysign(-1, c)
}
@@ -93,6 +102,8 @@ func copysign(a, b, c float64) {
func fromFloat64(f64 float64) uint64 {
// amd64:"MOVQ\tX.*, [^X].*"
// arm64:"FMOVD\tF.*, R.*"
+ // ppc64:"MFVSRD"
+ // ppc64le:"MFVSRD"
return math.Float64bits(f64+1) + 1
}
@@ -105,6 +116,8 @@ func fromFloat32(f32 float32) uint32 {
func toFloat64(u64 uint64) float64 {
// amd64:"MOVQ\t[^X].*, X.*"
// arm64:"FMOVD\tR.*, F.*"
+ // ppc64:"MTVSRD"
+ // ppc64le:"MTVSRD"
return math.Float64frombits(u64+1) + 1
}
@@ -135,6 +148,7 @@ func constantCheck32() bool {
func constantConvert32(x float32) float32 {
// amd64:"MOVSS\t[$]f32.3f800000\\(SB\\)"
// s390x:"FMOVS\t[$]f32.3f800000\\(SB\\)"
+ // ppc64:"FMOVS\t[$]f32.3f800000\\(SB\\)"
// ppc64le:"FMOVS\t[$]f32.3f800000\\(SB\\)"
// arm64:"FMOVS\t[$]\\(1.0\\)"
if x > math.Float32frombits(0x3f800000) {
@@ -146,6 +160,7 @@ func constantConvert32(x float32) float32 {
func constantConvertInt32(x uint32) uint32 {
// amd64:-"MOVSS"
// s390x:-"FMOVS"
+ // ppc64:-"FMOVS"
// ppc64le:-"FMOVS"
// arm64:-"FMOVS"
if x > math.Float32bits(1) {
diff --git a/test/codegen/mathbits.go b/test/codegen/mathbits.go
index 89a77d96f9..c21de19707 100644
--- a/test/codegen/mathbits.go
+++ b/test/codegen/mathbits.go
@@ -105,6 +105,7 @@ func OnesCount(n uint) int {
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
// ppc64:"POPCNTD"
+ // ppc64le:"POPCNTD"
return bits.OnesCount(n)
}
@@ -113,6 +114,7 @@ func OnesCount64(n uint64) int {
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
// ppc64:"POPCNTD"
+ // ppc64le:"POPCNTD"
return bits.OnesCount64(n)
}
@@ -121,6 +123,7 @@ func OnesCount32(n uint32) int {
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
// ppc64:"POPCNTW"
+ // ppc64le:"POPCNTW"
return bits.OnesCount32(n)
}
@@ -129,12 +132,14 @@ func OnesCount16(n uint16) int {
// arm64:"VCNT","VUADDLV"
// s390x:"POPCNT"
// ppc64:"POPCNTW"
+ // ppc64le:"POPCNTW"
return bits.OnesCount16(n)
}
func OnesCount8(n uint8) int {
// s390x:"POPCNT"
// ppc64:"POPCNTB"
+ // ppc64le:"POPCNTB"
return bits.OnesCount8(n)
}
@@ -176,6 +181,7 @@ func RotateLeft64(n uint64) uint64 {
// amd64:"ROLQ"
// arm64:"ROR"
// ppc64:"ROTL"
+ // ppc64le:"ROTL"
// s390x:"RLLG"
return bits.RotateLeft64(n, 37)
}
@@ -184,6 +190,7 @@ func RotateLeft32(n uint32) uint32 {
// amd64:"ROLL" 386:"ROLL"
// arm64:"RORW"
// ppc64:"ROTLW"
+ // ppc64le:"ROTLW"
// s390x:"RLL"
return bits.RotateLeft32(n, 9)
}
@@ -202,6 +209,7 @@ func RotateLeftVariable(n uint, m int) uint {
// amd64:"ROLQ"
// arm64:"ROR"
// ppc64:"ROTL"
+ // ppc64le:"ROTL"
// s390x:"RLLG"
return bits.RotateLeft(n, m)
}
@@ -210,6 +218,7 @@ func RotateLeftVariable64(n uint64, m int) uint64 {
// amd64:"ROLQ"
// arm64:"ROR"
// ppc64:"ROTL"
+ // ppc64le:"ROTL"
// s390x:"RLLG"
return bits.RotateLeft64(n, m)
}
@@ -218,6 +227,7 @@ func RotateLeftVariable32(n uint32, m int) uint32 {
// amd64:"ROLL"
// arm64:"RORW"
// ppc64:"ROTLW"
+ // ppc64le:"ROTLW"
// s390x:"RLL"
return bits.RotateLeft32(n, m)
}
@@ -230,6 +240,7 @@ func TrailingZeros(n uint) int {
// amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
// s390x:"FLOGR"
// ppc64:"ANDN","POPCNTD"
+ // ppc64le:"ANDN","POPCNTD"
return bits.TrailingZeros(n)
}
@@ -237,6 +248,7 @@ func TrailingZeros64(n uint64) int {
// amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
// s390x:"FLOGR"
// ppc64:"ANDN","POPCNTD"
+ // ppc64le:"ANDN","POPCNTD"
return bits.TrailingZeros64(n)
}
@@ -244,6 +256,7 @@ func TrailingZeros32(n uint32) int {
// amd64:"BTSQ\\t\\$32","BSFQ"
// s390x:"FLOGR","MOVWZ"
// ppc64:"ANDN","POPCNTW"
+ // ppc64le:"ANDN","POPCNTW"
return bits.TrailingZeros32(n)
}
@@ -251,6 +264,7 @@ func TrailingZeros16(n uint16) int {
// amd64:"BSFL","BTSL\\t\\$16"
// s390x:"FLOGR","OR\t\\$65536"
// ppc64:"POPCNTD","OR\\t\\$65536"
+ // ppc64le:"POPCNTD","OR\\t\\$65536"
return bits.TrailingZeros16(n)
}
@@ -319,13 +333,15 @@ func IterateBits8(n uint8) int {
func Mul(x, y uint) (hi, lo uint) {
// amd64:"MULQ"
// arm64:"UMULH","MUL"
- // ppc64: "MULHDU", "MULLD"
+ // ppc64:"MULHDU","MULLD"
+ // ppc64le:"MULHDU","MULLD"
return bits.Mul(x, y)
}
func Mul64(x, y uint64) (hi, lo uint64) {
// amd64:"MULQ"
// arm64:"UMULH","MUL"
- // ppc64: "MULHDU", "MULLD"
+ // ppc64:"MULHDU","MULLD"
+ // ppc64le:"MULHDU","MULLD"
return bits.Mul64(x, y)
}
diff --git a/test/codegen/noextend.go b/test/codegen/noextend.go
index ee4900226c..46bfe3f2f9 100644
--- a/test/codegen/noextend.go
+++ b/test/codegen/noextend.go
@@ -21,30 +21,38 @@ var val8 [8]uint8
func set16(x8 int8, u8 uint8, y8 int8, z8 uint8) {
// Truncate not needed, load does sign/zero extend
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
sval16[0] = int16(x8)
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
val16[0] = uint16(u8)
// AND not needed due to size
+ // ppc64:-"ANDCC"
// ppc64le:-"ANDCC"
sval16[1] = 255 & int16(x8+y8)
+ // ppc64:-"ANDCC"
// ppc64le:-"ANDCC"
val16[1] = 255 & uint16(u8+z8)
}
func shiftidx(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) {
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
sval16[0] = int16(val16[x8>>1])
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
val16[0] = uint16(sval16[u8>>2])
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
sval16[1] = int16(val16[x16>>1])
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
val16[1] = uint16(sval16[u16>>2])
@@ -53,87 +61,109 @@ func shiftidx(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) {
func setnox(x8 int8, u8 uint8, y8 int8, z8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) {
// Truncate not needed due to sign/zero extension on load
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
sval16[0] = int16(x8)
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
val16[0] = uint16(u8)
// AND not needed due to size
+ // ppc64:-"ANDCC"
// ppc64le:-"ANDCC"
sval16[1] = 255 & int16(x8+y8)
+ // ppc64:-"ANDCC"
// ppc64le:-"ANDCC"
val16[1] = 255 & uint16(u8+z8)
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
sval32[0] = int32(x8)
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
sval32[1] = int32(x16)
+ //ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
//ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
val32[0] = uint32(u8)
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
val32[1] = uint32(u16)
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
sval64[0] = int64(x8)
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
sval64[1] = int64(x16)
+ // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
sval64[2] = int64(x32)
+ //ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
//ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
val64[0] = uint64(u8)
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
val64[1] = uint64(u16)
+ // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
val64[2] = uint64(u32)
}
func cmp16(x8 int8, u8 uint8, x32 int32, u32 uint32, x64 int64, u64 uint64) bool {
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
if int16(x8) == sval16[0] {
return true
}
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
if uint16(u8) == val16[0] {
return true
}
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if uint16(u32>>16) == val16[0] {
return true
}
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if uint16(u64>>48) == val16[0] {
return true
}
// Verify the truncates are using the correct sign.
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if int16(x32) == sval16[0] {
return true
}
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
if uint16(u32) == val16[0] {
return true
}
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if int16(x64) == sval16[0] {
return true
}
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
if uint16(u64) == val16[0] {
return true
@@ -143,32 +173,38 @@ func cmp16(x8 int8, u8 uint8, x32 int32, u32 uint32, x64 int64, u64 uint64) bool
}
func cmp32(x8 int8, u8 uint8, x16 int16, u16 uint16, x64 int64, u64 uint64) bool {
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
if int32(x8) == sval32[0] {
return true
}
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
if uint32(u8) == val32[0] {
return true
}
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
if int32(x16) == sval32[0] {
return true
}
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if uint32(u16) == val32[0] {
return true
}
// Verify the truncates are using the correct sign.
+ // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
if int32(x64) == sval32[0] {
return true
}
+ // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
if uint32(u64) == val32[0] {
return true
@@ -179,31 +215,37 @@ func cmp32(x8 int8, u8 uint8, x16 int16, u16 uint16, x64 int64, u64 uint64) bool
func cmp64(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) bool {
+ // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
if int64(x8) == sval64[0] {
return true
}
+ // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
if uint64(u8) == val64[0] {
return true
}
+ // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
if int64(x16) == sval64[0] {
return true
}
+ // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
if uint64(u16) == val64[0] {
return true
}
+ // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
if int64(x32) == sval64[0] {
return true
}
+ // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
// ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
if uint64(u32) == val64[0] {
return true
diff --git a/test/codegen/rotate.go b/test/codegen/rotate.go
index 5812e1c0b1..ce24b57877 100644
--- a/test/codegen/rotate.go
+++ b/test/codegen/rotate.go
@@ -16,18 +16,21 @@ func rot64(x uint64) uint64 {
// amd64:"ROLQ\t[$]7"
// arm64:"ROR\t[$]57"
// s390x:"RLLG\t[$]7"
+ // ppc64:"ROTL\t[$]7"
// ppc64le:"ROTL\t[$]7"
a += x<<7 | x>>57
// amd64:"ROLQ\t[$]8"
// arm64:"ROR\t[$]56"
// s390x:"RLLG\t[$]8"
+ // ppc64:"ROTL\t[$]8"
// ppc64le:"ROTL\t[$]8"
a += x<<8 + x>>56
// amd64:"ROLQ\t[$]9"
// arm64:"ROR\t[$]55"
// s390x:"RLLG\t[$]9"
+ // ppc64:"ROTL\t[$]9"
// ppc64le:"ROTL\t[$]9"
a += x<<9 ^ x>>55
@@ -41,6 +44,7 @@ func rot32(x uint32) uint32 {
// arm:"MOVW\tR\\d+@>25"
// arm64:"RORW\t[$]25"
// s390x:"RLL\t[$]7"
+ // ppc64:"ROTLW\t[$]7"
// ppc64le:"ROTLW\t[$]7"
a += x<<7 | x>>25
@@ -48,6 +52,7 @@ func rot32(x uint32) uint32 {
// arm:"MOVW\tR\\d+@>24"
// arm64:"RORW\t[$]24"
// s390x:"RLL\t[$]8"
+ // ppc64:"ROTLW\t[$]8"
// ppc64le:"ROTLW\t[$]8"
a += x<<8 + x>>24
@@ -55,6 +60,7 @@ func rot32(x uint32) uint32 {
// arm:"MOVW\tR\\d+@>23"
// arm64:"RORW\t[$]23"
// s390x:"RLL\t[$]9"
+ // ppc64:"ROTLW\t[$]9"
// ppc64le:"ROTLW\t[$]9"
a += x<<9 ^ x>>23
@@ -101,6 +107,7 @@ func rot64nc(x uint64, z uint) uint64 {
z &= 63
// amd64:"ROLQ"
+ // ppc64:"ROTL"
// ppc64le:"ROTL"
a += x<>(64-z)
@@ -116,6 +123,7 @@ func rot32nc(x uint32, z uint) uint32 {
z &= 31
// amd64:"ROLL"
+ // ppc64:"ROTLW"
// ppc64le:"ROTLW"
a += x<>(32-z)
diff --git a/test/codegen/stack.go b/test/codegen/stack.go
index 0f2f6178c7..ed2c1ed959 100644
--- a/test/codegen/stack.go
+++ b/test/codegen/stack.go
@@ -18,6 +18,7 @@ import "runtime"
// arm:"TEXT\t.*, [$]-4-"
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
+// ppc64:"TEXT\t.*, [$]0-"
// ppc64le:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func StackStore() int {
@@ -37,6 +38,7 @@ type T struct {
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
+// ppc64:"TEXT\t.*, [$]0-"
// ppc64le:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ZeroLargeStruct(x *T) {
@@ -51,6 +53,7 @@ func ZeroLargeStruct(x *T) {
// amd64:"TEXT\t.*, [$]0-"
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
+// ppc64:"TEXT\t.*, [$]0-"
// ppc64le:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
// Note: that 386 currently has to spill a register.
@@ -65,6 +68,7 @@ func KeepWanted(t *T) {
// - arm & mips fail due to softfloat calls
// amd64:"TEXT\t.*, [$]0-"
// arm64:"TEXT\t.*, [$]0-"
+// ppc64:"TEXT\t.*, [$]0-"
// ppc64le:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ArrayAdd64(a, b [4]float64) [4]float64 {
@@ -78,6 +82,7 @@ func ArrayAdd64(a, b [4]float64) [4]float64 {
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
+// ppc64:"TEXT\t.*, [$]0-"
// ppc64le:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ArrayInit(i, j int) [4]int {
From 62c52a5ee19279a2151bdf178eee11b95c188a91 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Tue, 16 Oct 2018 11:58:00 -0700
Subject: [PATCH 149/240] cmd/compile/internal/gc: simplify typechecking
definitions
There are only a handful of nodes that we need to pass to
typecheckdef (OLITERAL, ONAME, OTYPE, and ONONAME), but typecheck1
takes the awkward approach of calling typecheckdef on every node with
Sym != nil, and then excluding a long list of uninteresting Ops that
have a non-nil Sym.
Passes toolstash-check.
Change-Id: I0271d2faff0208ad57ddc1f1a540a5fbed870234
Reviewed-on: https://go-review.googlesource.com/c/142657
Run-TryBot: Matthew Dempsky
TryBot-Result: Gobot Gobot
Reviewed-by: Brad Fitzpatrick
---
src/cmd/compile/internal/gc/typecheck.go | 31 +++++++++++-------------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index cfdd88d45e..d2354e47be 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -296,21 +296,21 @@ func indexlit(n *Node) *Node {
// n.Left = typecheck1(n.Left, top)
func typecheck1(n *Node, top int) *Node {
switch n.Op {
- case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, ORETJMP:
- // n.Sym is a field/method name, not a variable.
- default:
- if n.Sym != nil {
- if n.Op == ONAME && n.SubOp() != 0 && top&Ecall == 0 {
- yyerror("use of builtin %v not in function call", n.Sym)
- n.Type = nil
- return n
- }
+ case OLITERAL, ONAME, ONONAME, OTYPE:
+ if n.Sym == nil {
+ break
+ }
- typecheckdef(n)
- if n.Op == ONONAME {
- n.Type = nil
- return n
- }
+ if n.Op == ONAME && n.SubOp() != 0 && top&Ecall == 0 {
+ yyerror("use of builtin %v not in function call", n.Sym)
+ n.Type = nil
+ return n
+ }
+
+ typecheckdef(n)
+ if n.Op == ONONAME {
+ n.Type = nil
+ return n
}
}
@@ -3666,9 +3666,6 @@ func typecheckdef(n *Node) {
default:
Fatalf("typecheckdef %v", n.Op)
- case OGOTO, OLABEL, OPACK:
- // nothing to do here
-
case OLITERAL:
if n.Name.Param.Ntype != nil {
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
From 965fa3b191270bbc23a040a520ce43406ba29343 Mon Sep 17 00:00:00 2001
From: Matthew Dempsky
Date: Tue, 16 Oct 2018 12:49:17 -0700
Subject: [PATCH 150/240] cmd/compile: remove -dolinkobj flag
This used to be used by cmd/vet and some assembly generation tests, but
those were removed in CL 37691 and CL 107336. No point in keeping an
unneeded flag around.
Fixes #28220.
Change-Id: I59f8546954ab36ea61ceba81c10d6e16d74b966a
Reviewed-on: https://go-review.googlesource.com/c/142677
Run-TryBot: Matthew Dempsky
Reviewed-by: Brad Fitzpatrick
TryBot-Result: Gobot Gobot
---
src/cmd/compile/internal/gc/go.go | 1 -
src/cmd/compile/internal/gc/main.go | 115 ++++++++++++++--------------
src/cmd/compile/internal/gc/obj.go | 4 -
3 files changed, 56 insertions(+), 64 deletions(-)
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 605afd6407..57533237bc 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -92,7 +92,6 @@ var pragcgobuf [][]string
var outfile string
var linkobj string
-var dolinkobj bool
// nerrors is the number of compiler errors reported
// since the last call to saveerrors.
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 9a226318b9..5b159e3661 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -218,7 +218,6 @@ func Main(archInit func(*Arch)) {
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
}
- flag.BoolVar(&dolinkobj, "dolinkobj", true, "generate linker-specific objects; if false, some invalid code may compile")
flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
flag.StringVar(&outfile, "o", "", "write output to `file`")
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
@@ -606,71 +605,69 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "escapes")
escapes(xtop)
- if dolinkobj {
- // Collect information for go:nowritebarrierrec
- // checking. This must happen before transformclosure.
- // We'll do the final check after write barriers are
- // inserted.
- if compiling_runtime {
- nowritebarrierrecCheck = newNowritebarrierrecChecker()
+ // Collect information for go:nowritebarrierrec
+ // checking. This must happen before transformclosure.
+ // We'll do the final check after write barriers are
+ // inserted.
+ if compiling_runtime {
+ nowritebarrierrecCheck = newNowritebarrierrecChecker()
+ }
+
+ // Phase 7: Transform closure bodies to properly reference captured variables.
+ // This needs to happen before walk, because closures must be transformed
+ // before walk reaches a call of a closure.
+ timings.Start("fe", "xclosures")
+ for _, n := range xtop {
+ if n.Op == ODCLFUNC && n.Func.Closure != nil {
+ Curfn = n
+ transformclosure(n)
}
+ }
- // Phase 7: Transform closure bodies to properly reference captured variables.
- // This needs to happen before walk, because closures must be transformed
- // before walk reaches a call of a closure.
- timings.Start("fe", "xclosures")
- for _, n := range xtop {
- if n.Op == ODCLFUNC && n.Func.Closure != nil {
- Curfn = n
- transformclosure(n)
- }
+ // Prepare for SSA compilation.
+ // This must be before peekitabs, because peekitabs
+ // can trigger function compilation.
+ initssaconfig()
+
+ // Just before compilation, compile itabs found on
+ // the right side of OCONVIFACE so that methods
+ // can be de-virtualized during compilation.
+ Curfn = nil
+ peekitabs()
+
+ // Phase 8: Compile top level functions.
+ // Don't use range--walk can add functions to xtop.
+ timings.Start("be", "compilefuncs")
+ fcount = 0
+ for i := 0; i < len(xtop); i++ {
+ n := xtop[i]
+ if n.Op == ODCLFUNC {
+ funccompile(n)
+ fcount++
}
+ }
+ timings.AddEvent(fcount, "funcs")
- // Prepare for SSA compilation.
- // This must be before peekitabs, because peekitabs
- // can trigger function compilation.
- initssaconfig()
+ if nsavederrors+nerrors == 0 {
+ fninit(xtop)
+ }
- // Just before compilation, compile itabs found on
- // the right side of OCONVIFACE so that methods
- // can be de-virtualized during compilation.
- Curfn = nil
- peekitabs()
+ compileFunctions()
- // Phase 8: Compile top level functions.
- // Don't use range--walk can add functions to xtop.
- timings.Start("be", "compilefuncs")
- fcount = 0
- for i := 0; i < len(xtop); i++ {
- n := xtop[i]
- if n.Op == ODCLFUNC {
- funccompile(n)
- fcount++
- }
- }
- timings.AddEvent(fcount, "funcs")
+ if nowritebarrierrecCheck != nil {
+ // Write barriers are now known. Check the
+ // call graph.
+ nowritebarrierrecCheck.check()
+ nowritebarrierrecCheck = nil
+ }
- if nsavederrors+nerrors == 0 {
- fninit(xtop)
- }
-
- compileFunctions()
-
- if nowritebarrierrecCheck != nil {
- // Write barriers are now known. Check the
- // call graph.
- nowritebarrierrecCheck.check()
- nowritebarrierrecCheck = nil
- }
-
- // Finalize DWARF inline routine DIEs, then explicitly turn off
- // DWARF inlining gen so as to avoid problems with generated
- // method wrappers.
- if Ctxt.DwFixups != nil {
- Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
- Ctxt.DwFixups = nil
- genDwarfInline = 0
- }
+ // Finalize DWARF inline routine DIEs, then explicitly turn off
+ // DWARF inlining gen so as to avoid problems with generated
+ // method wrappers.
+ if Ctxt.DwFixups != nil {
+ Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
+ Ctxt.DwFixups = nil
+ genDwarfInline = 0
}
// Phase 9: Check external declarations.
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 19862c03aa..aed0f060cf 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -43,10 +43,6 @@ const (
)
func dumpobj() {
- if !dolinkobj {
- dumpobj1(outfile, modeCompilerObj)
- return
- }
if linkobj == "" {
dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
return
From a52289ef2bf7e9b7a619caecc14d6c95eff9eeae Mon Sep 17 00:00:00 2001
From: Filippo Valsorda
Date: Tue, 16 Oct 2018 13:01:07 -0400
Subject: [PATCH 151/240] Revert "fmt: fix incorrect format of whole-number
floats when using %#v"
Numbers without decimals are valid Go representations of whole-number
floats. That is, "var x float64 = 5" is valid Go. Avoid breakage in
tests that expect a certain output from %#v by reverting to it.
To guarantee the right type is generated by a print use %T(%#v) instead.
Added a test to lock in this behavior.
This reverts commit 7c7cecc1846aaaa0ce73931644fe1df2b4559e09.
Fixes #27634
Updates #26363
Change-Id: I544c400a0903777dd216452a7e86dfe60b0b0283
Reviewed-on: https://go-review.googlesource.com/c/142597
Run-TryBot: Filippo Valsorda
TryBot-Result: Gobot Gobot
Reviewed-by: Rob Pike
Reviewed-by: Bryan C. Mills
---
src/fmt/fmt_test.go | 7 +++----
src/fmt/format.go | 41 +++++++++++++++--------------------------
test/switch5.go | 8 ++++----
3 files changed, 22 insertions(+), 34 deletions(-)
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index d63271a805..e97372225c 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -686,11 +686,10 @@ var fmtTests = []struct {
{"%#v", 1.2345678, "1.2345678"},
{"%#v", float32(1.2345678), "1.2345678"},
- // Whole number floats should have a single trailing zero added, but not
- // for exponent notation.
- {"%#v", 1.0, "1.0"},
+ // Whole number floats are printed without decimals. See Issue 27634.
+ {"%#v", 1.0, "1"},
{"%#v", 1000000.0, "1e+06"},
- {"%#v", float32(1.0), "1.0"},
+ {"%#v", float32(1.0), "1"},
{"%#v", float32(1000000.0), "1e+06"},
// Only print []byte and []uint8 as type []byte if they appear at the top level.
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 3a3cd8d1a1..91103f2c07 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -481,19 +481,15 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) {
return
}
// The sharp flag forces printing a decimal point for non-binary formats
- // and retains trailing zeros, which we may need to restore. For the sharpV
- // flag, we ensure a single trailing zero is present if the output is not
- // in exponent notation.
- if f.sharpV || (f.sharp && verb != 'b') {
+ // and retains trailing zeros, which we may need to restore.
+ if f.sharp && verb != 'b' {
digits := 0
- if !f.sharpV {
- switch verb {
- case 'g', 'G':
- digits = prec
- // If no precision is set explicitly use a precision of 6.
- if digits == -1 {
- digits = 6
- }
+ switch verb {
+ case 'v', 'g', 'G':
+ digits = prec
+ // If no precision is set explicitly use a precision of 6.
+ if digits == -1 {
+ digits = 6
}
}
@@ -502,32 +498,25 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) {
var tailBuf [5]byte
tail := tailBuf[:0]
- var hasDecimalPoint, hasExponent bool
+ hasDecimalPoint := false
// Starting from i = 1 to skip sign at num[0].
for i := 1; i < len(num); i++ {
switch num[i] {
case '.':
hasDecimalPoint = true
case 'e', 'E':
- hasExponent = true
tail = append(tail, num[i:]...)
num = num[:i]
default:
digits--
}
}
- if f.sharpV {
- if !hasDecimalPoint && !hasExponent {
- num = append(num, '.', '0')
- }
- } else {
- if !hasDecimalPoint {
- num = append(num, '.')
- }
- for digits > 0 {
- num = append(num, '0')
- digits--
- }
+ if !hasDecimalPoint {
+ num = append(num, '.')
+ }
+ for digits > 0 {
+ num = append(num, '0')
+ digits--
}
num = append(num, tail...)
}
diff --git a/test/switch5.go b/test/switch5.go
index 6641d582bc..ce95bf8d7b 100644
--- a/test/switch5.go
+++ b/test/switch5.go
@@ -24,8 +24,8 @@ func f0(x int) {
func f1(x float32) {
switch x {
case 5:
- case 5: // ERROR "duplicate case 5 .value 5\.0. in switch"
- case 5.0: // ERROR "duplicate case 5 .value 5\.0. in switch"
+ case 5: // ERROR "duplicate case 5 in switch"
+ case 5.0: // ERROR "duplicate case 5 in switch"
}
}
@@ -44,9 +44,9 @@ func f3(e interface{}) {
case 0: // ERROR "duplicate case 0 in switch"
case int64(0):
case float32(10):
- case float32(10): // ERROR "duplicate case float32\(10\) .value 10\.0. in switch"
+ case float32(10): // ERROR "duplicate case float32\(10\) .value 10. in switch"
case float64(10):
- case float64(10): // ERROR "duplicate case float64\(10\) .value 10\.0. in switch"
+ case float64(10): // ERROR "duplicate case float64\(10\) .value 10. in switch"
}
}
From fa913a36a2793524a65972c7c65f4a0578cb3392 Mon Sep 17 00:00:00 2001
From: Ilya Tocar
Date: Mon, 17 Sep 2018 14:08:03 -0500
Subject: [PATCH 152/240] cmd/compile/internal/gc: inline autogenerated (*T).M
wrappers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently all inlining of autogenerated wrappers is disabled,
because it causes build failures, when indexed export format is enabled.
Turns out we can reenable it for common case of (*T).M wrappers.
This fixes most performance degradation of 1.11 vs 1.10.
encoding/binary:
name old time/op new time/op delta
ReadSlice1000Int32s-6 14.8µs ± 2% 11.5µs ± 2% -22.01% (p=0.000 n=10+10)
WriteSlice1000Int32s-6 14.8µs ± 2% 11.7µs ± 2% -20.95% (p=0.000 n=10+10)
bufio:
name old time/op new time/op delta
WriterFlush-6 32.4ns ± 1% 28.8ns ± 0% -11.17% (p=0.000 n=9+10)
sort:
SearchWrappers-6 231ns ± 1% 231ns ± 0% ~ (p=0.129 n=9+10)
SortString1K-6 365µs ± 1% 298µs ± 1% -18.43% (p=0.000 n=9+10)
SortString1K_Slice-6 274µs ± 2% 276µs ± 1% ~ (p=0.105 n=10+10)
StableString1K-6 490µs ± 1% 373µs ± 1% -23.73% (p=0.000 n=10+10)
SortInt1K-6 210µs ± 1% 142µs ± 1% -32.69% (p=0.000 n=10+10)
StableInt1K-6 243µs ± 0% 151µs ± 1% -37.75% (p=0.000 n=10+10)
StableInt1K_Slice-6 130µs ± 1% 130µs ± 0% ~ (p=0.237 n=10+8)
SortInt64K-6 19.9ms ± 1% 13.5ms ± 1% -32.32% (p=0.000 n=10+10)
SortInt64K_Slice-6 11.5ms ± 1% 11.5ms ± 1% ~ (p=0.912 n=10+10)
StableInt64K-6 21.5ms ± 0% 13.5ms ± 1% -37.30% (p=0.000 n=9+10)
Sort1e2-6 108µs ± 2% 83µs ± 3% -23.26% (p=0.000 n=10+10)
Stable1e2-6 218µs ± 0% 161µs ± 1% -25.99% (p=0.000 n=8+9)
Sort1e4-6 22.6ms ± 1% 16.8ms ± 0% -25.45% (p=0.000 n=10+7)
Stable1e4-6 67.6ms ± 1% 49.7ms ± 0% -26.48% (p=0.000 n=10+10)
Sort1e6-6 3.44s ± 0% 2.55s ± 1% -26.05% (p=0.000 n=8+9)
Stable1e6-6 13.7s ± 0% 9.9s ± 1% -27.68% (p=0.000 n=8+10)
Fixes #27621
Updates #25338
Change-Id: I6fe633202f63fa829a6ab849c44d7e45f8835dff
Reviewed-on: https://go-review.googlesource.com/c/135697
Run-TryBot: Ilya Tocar
TryBot-Result: Gobot Gobot
Reviewed-by: Matthew Dempsky
---
src/cmd/compile/internal/gc/inl_test.go | 27 +++++++++++++++++++++++--
src/cmd/compile/internal/gc/subr.go | 9 ++++-----
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
index 3fc0fbed1d..2f15cc3828 100644
--- a/src/cmd/compile/internal/gc/inl_test.go
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -26,7 +26,8 @@ func TestIntendedInlining(t *testing.T) {
t.Parallel()
// want is the list of function names (by package) that should
- // be inlined.
+ // be inlinable. If they have no callers in thier packages, they
+ // might not actually be inlined anywhere.
want := map[string][]string{
"runtime": {
// TODO(mvdan): enable these once mid-stack
@@ -111,6 +112,11 @@ func TestIntendedInlining(t *testing.T) {
"(*Buffer).UnreadByte",
"(*Buffer).tryGrowByReslice",
},
+ "compress/flate": {
+ "byLiteral.Len",
+ "byLiteral.Less",
+ "byLiteral.Swap",
+ },
"unicode/utf8": {
"FullRune",
"FullRuneInString",
@@ -162,6 +168,13 @@ func TestIntendedInlining(t *testing.T) {
want["runtime"] = append(want["runtime"], "rotl_31")
}
+ // Functions that must actually be inlined; they must have actual callers.
+ must := map[string]bool{
+ "compress/flate.byLiteral.Len": true,
+ "compress/flate.byLiteral.Less": true,
+ "compress/flate.byLiteral.Swap": true,
+ }
+
notInlinedReason := make(map[string]string)
pkgs := make([]string, 0, len(want))
for pname, fnames := range want {
@@ -188,6 +201,7 @@ func TestIntendedInlining(t *testing.T) {
scanner := bufio.NewScanner(pr)
curPkg := ""
canInline := regexp.MustCompile(`: can inline ([^ ]*)`)
+ haveInlined := regexp.MustCompile(`: inlining call to ([^ ]*)`)
cannotInline := regexp.MustCompile(`: cannot inline ([^ ]*): (.*)`)
for scanner.Scan() {
line := scanner.Text()
@@ -195,11 +209,20 @@ func TestIntendedInlining(t *testing.T) {
curPkg = line[2:]
continue
}
- if m := canInline.FindStringSubmatch(line); m != nil {
+ if m := haveInlined.FindStringSubmatch(line); m != nil {
fname := m[1]
delete(notInlinedReason, curPkg+"."+fname)
continue
}
+ if m := canInline.FindStringSubmatch(line); m != nil {
+ fname := m[1]
+ fullname := curPkg + "." + fname
+ // If function must be inlined somewhere, beeing inlinable is not enough
+ if _, ok := must[fullname]; !ok {
+ delete(notInlinedReason, fullname)
+ continue
+ }
+ }
if m := cannotInline.FindStringSubmatch(line); m != nil {
fname, reason := m[1], m[2]
fullName := curPkg + "." + fname
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 9a6c61a651..7c9c8a157d 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -1728,11 +1728,10 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
Curfn = fn
typecheckslice(fn.Nbody.Slice(), Etop)
- // TODO(mdempsky): Investigate why this doesn't work with
- // indexed export. For now, we disable even in non-indexed
- // mode to ensure fair benchmark comparisons and to track down
- // unintended compilation differences.
- if false {
+ // Inline calls within (*T).M wrappers. This is safe because we only
+ // generate those wrappers within the same compilation unit as (T).M.
+ // TODO(mdempsky): Investigate why we can't enable this more generally.
+ if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
inlcalls(fn)
}
escAnalyze([]*Node{fn}, false)
From 0b63086f64ad7da114b003b98f1c78a6beb6ef26 Mon Sep 17 00:00:00 2001
From: Emmanuel T Odeke
Date: Tue, 17 Jul 2018 19:02:53 -0700
Subject: [PATCH 153/240] cmd/compile: fix label redefinition error column
numbers
Ensure that label redefinition error column numbers
print the actual start of the label instead of the
position of the label's delimiting token ":".
For example, given this program:
package main
func main() {
foo:
foo:
foo:
foo :
}
* Before:
main.go:5:13: label foo defined and not used
main.go:6:7: label foo already defined at main.go:5:13
main.go:7:4: label foo already defined at main.go:5:13
main.go:8:16: label foo already defined at main.go:5:13
* After:
main.go:5:13: label foo defined and not used
main.go:6:4: label foo already defined at main.go:5:13
main.go:7:1: label foo already defined at main.go:5:13
main.go:8:1: label foo already defined at main.go:5:13
Fixes #26411
Change-Id: I8eb874b97fdc8862547176d57ac2fa0f075f2367
Reviewed-on: https://go-review.googlesource.com/c/124595
Run-TryBot: Emmanuel Odeke
TryBot-Result: Gobot Gobot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/syntax/branches.go | 2 +-
test/fixedbugs/issue26411.go | 94 +++++++++++++++++++++
2 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 test/fixedbugs/issue26411.go
diff --git a/src/cmd/compile/internal/syntax/branches.go b/src/cmd/compile/internal/syntax/branches.go
index a03e2734d2..56e97c71d8 100644
--- a/src/cmd/compile/internal/syntax/branches.go
+++ b/src/cmd/compile/internal/syntax/branches.go
@@ -77,7 +77,7 @@ func (ls *labelScope) declare(b *block, s *LabeledStmt) *label {
labels = make(map[string]*label)
ls.labels = labels
} else if alt := labels[name]; alt != nil {
- ls.err(s.Pos(), "label %s already defined at %s", name, alt.lstmt.Label.Pos().String())
+ ls.err(s.Label.Pos(), "label %s already defined at %s", name, alt.lstmt.Label.Pos().String())
return alt
}
l := &label{b, s, false}
diff --git a/test/fixedbugs/issue26411.go b/test/fixedbugs/issue26411.go
new file mode 100644
index 0000000000..789c176dae
--- /dev/null
+++ b/test/fixedbugs/issue26411.go
@@ -0,0 +1,94 @@
+// +build !nacl,!js
+// run
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Ensure that label redefinition errors print out
+// a column number that matches the start of the current label's
+// definition instead of the label delimiting token ":"
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+)
+
+func main() {
+ tmpdir, err := ioutil.TempDir("", "issue26411")
+ if err != nil {
+ log.Fatalf("Failed to create temporary directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ samples := []struct {
+ code string
+ wantOutput []string
+ }{
+ {
+ code: `
+package main
+
+func main() {
+foo:
+foo:
+}
+`,
+ wantOutput: []string{
+ "^.+:5:1: label foo defined and not used\n",
+ ".+:6:1: label foo already defined at .+:5:1\n$",
+ },
+ },
+ {
+ code: `
+package main
+
+func main() {
+
+ bar:
+ bar:
+bar:
+bar :
+}
+`,
+
+ wantOutput: []string{
+ "^.+:6:13: label bar defined and not used\n",
+ ".+:7:4: label bar already defined at .+:6:13\n",
+ ".+:8:1: label bar already defined at .+:6:13\n",
+ ".+:9:1: label bar already defined at .+:6:13\n$",
+ },
+ },
+ }
+
+ for i, sample := range samples {
+ filename := filepath.Join(tmpdir, fmt.Sprintf("%d.go", i))
+ if err := ioutil.WriteFile(filename, []byte(sample.code), 0644); err != nil {
+ log.Printf("#%d: failed to create file %s", i, filename)
+ continue
+ }
+ output, _ := exec.Command("go", "tool", "compile", filename).CombinedOutput()
+
+ // Now match the output
+ for _, regex := range sample.wantOutput {
+ reg := regexp.MustCompile(regex)
+ matches := reg.FindAll(output, -1)
+ for _, match := range matches {
+ index := bytes.Index(output, match)
+ output = bytes.Join([][]byte{output[:index], output[index+len(match):]}, []byte(""))
+ }
+ }
+
+ if len(output) != 0 {
+ log.Printf("#%d: did not match all the output\nResidual output:\n\t%s", i, output)
+ }
+ }
+}
From e861c3e003b37622603ff690aba5e62c0ddb31c2 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Tue, 16 Oct 2018 15:53:38 -0700
Subject: [PATCH 154/240] cmd/compile: simplified test case (cleanup)
Follow-up on https://golang.org/cl/124595; no semantic changes.
Updates #26411.
Change-Id: Ic1c4622dbf79529ff61530f9c25ec742c2abe5ca
Reviewed-on: https://go-review.googlesource.com/c/142720
Run-TryBot: Robert Griesemer
Reviewed-by: Emmanuel Odeke
TryBot-Result: Gobot Gobot
---
test/fixedbugs/issue26411.go | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/test/fixedbugs/issue26411.go b/test/fixedbugs/issue26411.go
index 789c176dae..5f40bf2522 100644
--- a/test/fixedbugs/issue26411.go
+++ b/test/fixedbugs/issue26411.go
@@ -29,9 +29,9 @@ func main() {
}
defer os.RemoveAll(tmpdir)
- samples := []struct {
- code string
- wantOutput []string
+ tests := []struct {
+ code string
+ errors []string
}{
{
code: `
@@ -42,7 +42,7 @@ foo:
foo:
}
`,
- wantOutput: []string{
+ errors: []string{
"^.+:5:1: label foo defined and not used\n",
".+:6:1: label foo already defined at .+:5:1\n$",
},
@@ -60,7 +60,7 @@ bar :
}
`,
- wantOutput: []string{
+ errors: []string{
"^.+:6:13: label bar defined and not used\n",
".+:7:4: label bar already defined at .+:6:13\n",
".+:8:1: label bar already defined at .+:6:13\n",
@@ -69,26 +69,24 @@ bar :
},
}
- for i, sample := range samples {
+ for i, test := range tests {
filename := filepath.Join(tmpdir, fmt.Sprintf("%d.go", i))
- if err := ioutil.WriteFile(filename, []byte(sample.code), 0644); err != nil {
+ if err := ioutil.WriteFile(filename, []byte(test.code), 0644); err != nil {
log.Printf("#%d: failed to create file %s", i, filename)
continue
}
output, _ := exec.Command("go", "tool", "compile", filename).CombinedOutput()
- // Now match the output
- for _, regex := range sample.wantOutput {
- reg := regexp.MustCompile(regex)
- matches := reg.FindAll(output, -1)
- for _, match := range matches {
- index := bytes.Index(output, match)
- output = bytes.Join([][]byte{output[:index], output[index+len(match):]}, []byte(""))
- }
+ // remove each matching error from the output
+ for _, err := range test.errors {
+ rx := regexp.MustCompile(err)
+ match := rx.Find(output)
+ output = bytes.Replace(output, match, nil, 1) // remove match (which might be nil) from output
}
+ // at this point all output should have been consumed
if len(output) != 0 {
- log.Printf("#%d: did not match all the output\nResidual output:\n\t%s", i, output)
+ log.Printf("Test case %d has unmatched errors:\n%s", i, output)
}
}
}
From 9c039ea27a0deafcc713a1fced175ba73ae47b6a Mon Sep 17 00:00:00 2001
From: Rijnard van Tonder
Date: Wed, 17 Oct 2018 01:10:14 +0000
Subject: [PATCH 155/240] crypto/aes: remove redundant nil check around loop
Change-Id: I8cc4b5efe798e74b6daabd64fc2dd5486dcb7c5e
GitHub-Last-Rev: 694509e33df7c5729ec0bf7b053ff18ebd87c36b
GitHub-Pull-Request: golang/go#28115
Reviewed-on: https://go-review.googlesource.com/c/140998
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gobot Gobot
Reviewed-by: Ian Lance Taylor
---
src/crypto/aes/aes_test.go | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/crypto/aes/aes_test.go b/src/crypto/aes/aes_test.go
index bedc2da946..1e8bac4bb5 100644
--- a/src/crypto/aes/aes_test.go
+++ b/src/crypto/aes/aes_test.go
@@ -231,12 +231,10 @@ L:
continue L
}
}
- if dec != nil {
- for j, v := range dec {
- if v != tt.dec[j] {
- t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
- continue L
- }
+ for j, v := range dec {
+ if v != tt.dec[j] {
+ t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
+ continue L
}
}
}
From ee76992200a282f0ed4eb52e686ec254d8313cdc Mon Sep 17 00:00:00 2001
From: Filippo Valsorda
Date: Fri, 12 Oct 2018 17:07:04 -0400
Subject: [PATCH 156/240] crypto/tls,crypto/x509: normalize RFC references
Use the format "RFC XXXX, Section X.X" (or "Appendix Y.X") as it fits
more properly in prose than a link, is more future-proof, and as there
are multiple ways to render an RFC. Capital "S" to follow the quoting
standard of RFCs themselves.
Applied the new goimports grouping to all files in those packages, too.
Change-Id: I01267bb3a3b02664f8f822e97b129075bb14d404
Reviewed-on: https://go-review.googlesource.com/c/141918
Reviewed-by: Dmitri Shuralyov
---
src/crypto/tls/auth.go | 7 +++--
src/crypto/tls/cipher_suites.go | 8 +++---
src/crypto/tls/common.go | 27 ++++++++-----------
src/crypto/tls/conn.go | 2 +-
src/crypto/tls/handshake_client.go | 2 +-
src/crypto/tls/handshake_messages.go | 33 +++++++++++------------
src/crypto/tls/handshake_messages_test.go | 3 +--
src/crypto/tls/handshake_server.go | 4 +--
src/crypto/tls/key_agreement.go | 5 ++--
src/crypto/tls/prf.go | 15 +++++------
src/crypto/x509/pem_decrypt.go | 2 +-
src/crypto/x509/pkix/pkix.go | 2 +-
src/crypto/x509/verify.go | 20 +++++++-------
src/crypto/x509/x509.go | 32 ++++++++++------------
14 files changed, 72 insertions(+), 90 deletions(-)
diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go
index 88face4cde..a27db45b01 100644
--- a/src/crypto/tls/auth.go
+++ b/src/crypto/tls/auth.go
@@ -23,10 +23,9 @@ import (
func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) {
if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 {
// For TLS 1.1 and before, the signature algorithm could not be
- // negotiated and the hash is fixed based on the signature type.
- // For TLS 1.2, if the client didn't send signature_algorithms
- // extension then we can assume that it supports SHA1. See
- // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ // negotiated and the hash is fixed based on the signature type. For TLS
+ // 1.2, if the client didn't send signature_algorithms extension then we
+ // can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
switch pubkey.(type) {
case *rsa.PublicKey:
if tlsVersion < VersionTLS12 {
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 3c8dc4b2d2..d232996629 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -13,9 +13,8 @@ import (
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
- "hash"
-
"golang_org/x/crypto/chacha20poly1305"
+ "hash"
)
// a keyAgreement implements the client and server side of a TLS key agreement
@@ -303,7 +302,7 @@ func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
}
}
-// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
type tls10MAC struct {
h hash.Hash
}
@@ -390,7 +389,6 @@ const (
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
- // that the client is doing version fallback. See
- // https://tools.ietf.org/html/rfc7507.
+ // that the client is doing version fallback. See RFC 7507.
TLS_FALLBACK_SCSV uint16 = 0x5600
)
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index 7b627fc025..50db88eb60 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -79,7 +79,7 @@ const (
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
- extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
+ extensionSCT uint16 = 18 // RFC 6962, Section 6
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
@@ -128,7 +128,7 @@ const (
)
// Signature algorithms (for internal signaling use). Starting at 16 to avoid overlap with
-// TLS 1.2 codepoints (RFC 5246, section A.4.1), with which these have nothing to do.
+// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do.
const (
signaturePKCS1v15 uint8 = iota + 16
signatureECDSA
@@ -177,9 +177,9 @@ type ConnectionState struct {
}
// ExportKeyingMaterial returns length bytes of exported key material in a new
-// slice as defined in https://tools.ietf.org/html/rfc5705. If context is nil,
-// it is not used as part of the seed. If the connection was set to allow
-// renegotiation via Config.Renegotiation, this function will return an error.
+// slice as defined in RFC 5705. If context is nil, it is not used as part of
+// the seed. If the connection was set to allow renegotiation via
+// Config.Renegotiation, this function will return an error.
func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
return cs.ekm(label, context, length)
}
@@ -222,7 +222,7 @@ type ClientSessionCache interface {
}
// SignatureScheme identifies a signature algorithm supported by TLS. See
-// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3.
+// RFC 8446, Section 4.2.3.
type SignatureScheme uint16
const (
@@ -252,32 +252,27 @@ type ClientHelloInfo struct {
// ServerName indicates the name of the server requested by the client
// in order to support virtual hosting. ServerName is only set if the
- // client is using SNI (see
- // https://tools.ietf.org/html/rfc4366#section-3.1).
+ // client is using SNI (see RFC 4366, Section 3.1).
ServerName string
// SupportedCurves lists the elliptic curves supported by the client.
// SupportedCurves is set only if the Supported Elliptic Curves
- // Extension is being used (see
- // https://tools.ietf.org/html/rfc4492#section-5.1.1).
+ // Extension is being used (see RFC 4492, Section 5.1.1).
SupportedCurves []CurveID
// SupportedPoints lists the point formats supported by the client.
// SupportedPoints is set only if the Supported Point Formats Extension
- // is being used (see
- // https://tools.ietf.org/html/rfc4492#section-5.1.2).
+ // is being used (see RFC 4492, Section 5.1.2).
SupportedPoints []uint8
// SignatureSchemes lists the signature and hash schemes that the client
// is willing to verify. SignatureSchemes is set only if the Signature
- // Algorithms Extension is being used (see
- // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1).
+ // Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
SignatureSchemes []SignatureScheme
// SupportedProtos lists the application protocols supported by the client.
// SupportedProtos is set only if the Application-Layer Protocol
- // Negotiation Extension is being used (see
- // https://tools.ietf.org/html/rfc7301#section-3.1).
+ // Negotiation Extension is being used (see RFC 7301, Section 3.1).
//
// Servers can select a protocol by setting Config.NextProtos in a
// GetConfigForClient return value.
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 6e27e695bd..f05135bc33 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -205,7 +205,7 @@ func (hc *halfConn) incSeq() {
// extractPadding returns, in constant time, the length of the padding to remove
// from the end of payload. It also returns a byte which is equal to 255 if the
-// padding was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
func extractPadding(payload []byte) (toRemove int, good byte) {
if len(payload) < 1 {
return 0, 0
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 32fdc6d6eb..af290e33a7 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -845,7 +845,7 @@ func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
// hostnameInSNI converts name into an approriate hostname for SNI.
// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
-// See https://tools.ietf.org/html/rfc6066#section-3.
+// See RFC 6066, Section 3.
func hostnameInSNI(name string) string {
host := name
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index a5bf10efb8..27004b2d69 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -155,7 +155,7 @@ func (m *clientHelloMsg) marshal() []byte {
z[3] = byte(l)
z = z[4:]
- // RFC 3546, section 3.1
+ // RFC 3546, Section 3.1
//
// struct {
// NameType name_type;
@@ -182,7 +182,7 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[l:]
}
if m.ocspStapling {
- // RFC 4366, section 3.6
+ // RFC 4366, Section 3.6
z[0] = byte(extensionStatusRequest >> 8)
z[1] = byte(extensionStatusRequest)
z[2] = 0
@@ -192,7 +192,7 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[9:]
}
if len(m.supportedCurves) > 0 {
- // https://tools.ietf.org/html/rfc4492#section-5.5.1
+ // RFC 4492, Section 5.5.1
z[0] = byte(extensionSupportedCurves >> 8)
z[1] = byte(extensionSupportedCurves)
l := 2 + 2*len(m.supportedCurves)
@@ -209,7 +209,7 @@ func (m *clientHelloMsg) marshal() []byte {
}
}
if len(m.supportedPoints) > 0 {
- // https://tools.ietf.org/html/rfc4492#section-5.5.2
+ // RFC 4492, Section 5.5.2
z[0] = byte(extensionSupportedPoints >> 8)
z[1] = byte(extensionSupportedPoints)
l := 1 + len(m.supportedPoints)
@@ -224,7 +224,7 @@ func (m *clientHelloMsg) marshal() []byte {
}
}
if m.ticketSupported {
- // https://tools.ietf.org/html/rfc5077#section-3.2
+ // RFC 5077, Section 3.2
z[0] = byte(extensionSessionTicket >> 8)
z[1] = byte(extensionSessionTicket)
l := len(m.sessionTicket)
@@ -235,7 +235,7 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[len(m.sessionTicket):]
}
if len(m.supportedSignatureAlgorithms) > 0 {
- // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ // RFC 5246, Section 7.4.1.4.1
z[0] = byte(extensionSignatureAlgorithms >> 8)
z[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(m.supportedSignatureAlgorithms)
@@ -285,7 +285,7 @@ func (m *clientHelloMsg) marshal() []byte {
lengths[1] = byte(stringsLength)
}
if m.scts {
- // https://tools.ietf.org/html/rfc6962#section-3.3.1
+ // RFC 6962, Section 3.3.1
z[0] = byte(extensionSCT >> 8)
z[1] = byte(extensionSCT)
// zero uint16 for the zero-length extension_data
@@ -396,9 +396,8 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
if nameType == 0 {
m.serverName = string(d[:nameLen])
- // An SNI value may not include a
- // trailing dot. See
- // https://tools.ietf.org/html/rfc6066#section-3.
+ // An SNI value may not include a trailing dot.
+ // See RFC 6066, Section 3.
if strings.HasSuffix(m.serverName, ".") {
return false
}
@@ -414,7 +413,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
case extensionStatusRequest:
m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
case extensionSupportedCurves:
- // https://tools.ietf.org/html/rfc4492#section-5.5.1
+ // RFC 4492, Section 5.5.1
if length < 2 {
return false
}
@@ -430,7 +429,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
d = d[2:]
}
case extensionSupportedPoints:
- // https://tools.ietf.org/html/rfc4492#section-5.5.2
+ // RFC 4492, Section 5.5.2
if length < 1 {
return false
}
@@ -441,11 +440,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.supportedPoints = make([]uint8, l)
copy(m.supportedPoints, data[1:])
case extensionSessionTicket:
- // https://tools.ietf.org/html/rfc5077#section-3.2
+ // RFC 5077, Section 3.2
m.ticketSupported = true
m.sessionTicket = data[:length]
case extensionSignatureAlgorithms:
- // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ // RFC 5246, Section 7.4.1.4.1
if length < 2 || length&1 != 0 {
return false
}
@@ -1224,7 +1223,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
return m.raw
}
- // See https://tools.ietf.org/html/rfc4346#section-7.4.4
+ // See RFC 4346, Section 7.4.4.
length := 1 + len(m.certificateTypes) + 2
casLength := 0
for _, ca := range m.certificateAuthorities {
@@ -1374,7 +1373,7 @@ func (m *certificateVerifyMsg) marshal() (x []byte) {
return m.raw
}
- // See https://tools.ietf.org/html/rfc4346#section-7.4.8
+ // See RFC 4346, Section 7.4.8.
siglength := len(m.signature)
length := 2 + siglength
if m.hasSignatureAndHash {
@@ -1452,7 +1451,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) {
return m.raw
}
- // See https://tools.ietf.org/html/rfc5077#section-3.3
+ // See RFC 5077, Section 3.3.
ticketLen := len(m.ticket)
length := 2 + 4 + ticketLen
x = make([]byte, 4+length)
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index 4a4a466768..52c5d30e8f 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -271,8 +271,7 @@ func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value {
}
func TestRejectEmptySCTList(t *testing.T) {
- // https://tools.ietf.org/html/rfc6962#section-3.3.1 specifies that
- // empty SCT lists are invalid.
+ // RFC 6962, Section 3.3.1 specifies that empty SCT lists are invalid.
var random [32]byte
sct := []byte{0x42, 0x42, 0x42, 0x42}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index ac491bad39..b077c90580 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -49,7 +49,7 @@ func (c *Conn) serverHandshake() error {
return err
}
- // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+ // For an overview of TLS handshaking, see RFC 5246, Section 7.3.
c.buffering = true
if isResume {
// The client has included a session ticket and so we do an abbreviated handshake.
@@ -268,7 +268,7 @@ Curves:
return false, errors.New("tls: no cipher suite supported by both client and server")
}
- // See https://tools.ietf.org/html/rfc7507.
+ // See RFC 7507.
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
// The client is doing a fallback connection.
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 1e77facce0..1baa901ec7 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -12,10 +12,9 @@ import (
"crypto/sha1"
"crypto/x509"
"errors"
+ "golang_org/x/crypto/curve25519"
"io"
"math/big"
-
- "golang_org/x/crypto/curve25519"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
@@ -200,7 +199,7 @@ NextCandidate:
ecdhePublic = elliptic.Marshal(curve, x, y)
}
- // https://tools.ietf.org/html/rfc4492#section-5.4
+ // See RFC 4492, Section 5.4.
serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHParams[0] = 3 // named curve
serverECDHParams[1] = byte(ka.curveid >> 8)
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index a8cf21da15..a31a50d14f 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -16,14 +16,14 @@ import (
"hash"
)
-// Split a premaster secret in two as specified in RFC 4346, section 5.
+// Split a premaster secret in two as specified in RFC 4346, Section 5.
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
s1 = secret[0 : (len(secret)+1)/2]
s2 = secret[len(secret)/2:]
return
}
-// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+// pHash implements the P_hash function, as defined in RFC 4346, Section 5.
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h := hmac.New(hash, secret)
h.Write(seed)
@@ -44,7 +44,7 @@ func pHash(result, secret, seed []byte, hash func() hash.Hash) {
}
}
-// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5.
func prf10(result, secret, label, seed []byte) {
hashSHA1 := sha1.New
hashMD5 := md5.New
@@ -63,7 +63,7 @@ func prf10(result, secret, label, seed []byte) {
}
}
-// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5.
func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
return func(result, secret, label, seed []byte) {
labelAndSeed := make([]byte, len(label)+len(seed))
@@ -140,7 +140,7 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe
}
// masterFromPreMasterSecret generates the master secret from the pre-master
-// secret. See https://tools.ietf.org/html/rfc5246#section-8.1
+// secret. See RFC 5246, Section 8.1.
func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
seed = append(seed, clientRandom...)
@@ -153,7 +153,7 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr
// keysFromMasterSecret generates the connection keys from the master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
-// RFC 2246, section 6.3.
+// RFC 2246, Section 6.3.
func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
seed = append(seed, serverRandom...)
@@ -353,8 +353,7 @@ func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte,
return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
}
-// ekmFromMasterSecret generates exported keying material as defined in
-// https://tools.ietf.org/html/rfc5705.
+// ekmFromMasterSecret generates exported keying material as defined in RFC 5705.
func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
return func(label string, context []byte, length int) ([]byte, error) {
switch label {
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 0388d63e14..93d1e4a922 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -203,7 +203,7 @@ func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, al
// the data separately, but it doesn't seem worth the additional
// code.
copy(encrypted, data)
- // See RFC 1423, section 1.1
+ // See RFC 1423, Section 1.1.
for i := 0; i < pad; i++ {
encrypted = append(encrypted, byte(pad))
}
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
index 3cc4d587e3..59c3b15c83 100644
--- a/src/crypto/x509/pkix/pkix.go
+++ b/src/crypto/x509/pkix/pkix.go
@@ -95,7 +95,7 @@ func (r RDNSequence) String() string {
type RelativeDistinguishedNameSET []AttributeTypeAndValue
// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
-// https://tools.ietf.org/html/rfc5280#section-4.1.2.4
+// RFC 5280, Section 4.1.2.4.
type AttributeTypeAndValue struct {
Type asn1.ObjectIdentifier
Value interface{}
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 91be7c05f9..23ee2d2512 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -222,10 +222,9 @@ type rfc2821Mailbox struct {
}
// parseRFC2821Mailbox parses an email address into local and domain parts,
-// based on the ABNF for a “Mailbox” from RFC 2821. According to
-// https://tools.ietf.org/html/rfc5280#section-4.2.1.6 that's correct for an
-// rfc822Name from a certificate: “The format of an rfc822Name is a "Mailbox"
-// as defined in https://tools.ietf.org/html/rfc2821#section-4.1.2”.
+// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280,
+// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The
+// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”.
func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
if len(in) == 0 {
return mailbox, false
@@ -242,9 +241,8 @@ func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
// quoted-pair = ("\" text) / obs-qp
// text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text
//
- // (Names beginning with “obs-” are the obsolete syntax from
- // https://tools.ietf.org/html/rfc2822#section-4. Since it has
- // been 16 years, we no longer accept that.)
+ // (Names beginning with “obs-” are the obsolete syntax from RFC 2822,
+ // Section 4. Since it has been 16 years, we no longer accept that.)
in = in[1:]
QuotedString:
for {
@@ -298,7 +296,7 @@ func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
// Atom ("." Atom)*
NextChar:
for len(in) > 0 {
- // atext from https://tools.ietf.org/html/rfc2822#section-3.2.4
+ // atext from RFC 2822, Section 3.2.4
c := in[0]
switch {
@@ -334,7 +332,7 @@ func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
return mailbox, false
}
- // https://tools.ietf.org/html/rfc3696#section-3
+ // From RFC 3696, Section 3:
// “period (".") may also appear, but may not be used to start
// or end the local part, nor may two or more consecutive
// periods appear.”
@@ -415,7 +413,7 @@ func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, erro
}
func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
- // https://tools.ietf.org/html/rfc5280#section-4.2.1.10
+ // From RFC 5280, Section 4.2.1.10:
// “a uniformResourceIdentifier that does not include an authority
// component with a host name specified as a fully qualified domain
// name (e.g., if the URI either does not include an authority
@@ -987,7 +985,7 @@ func (c *Certificate) VerifyHostname(h string) error {
}
if ip := net.ParseIP(candidateIP); ip != nil {
// We only match IP addresses against IP SANs.
- // https://tools.ietf.org/html/rfc6125#appendix-B.2
+ // See RFC 6125, Appendix B.2.
for _, candidate := range c.IPAddresses {
if ip.Equal(candidate) {
return nil
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 2e72471de2..7e8f675886 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -24,6 +24,8 @@ import (
"encoding/pem"
"errors"
"fmt"
+ "golang_org/x/crypto/cryptobyte"
+ cryptobyte_asn1 "golang_org/x/crypto/cryptobyte/asn1"
"io"
"math/big"
"net"
@@ -32,9 +34,6 @@ import (
"strings"
"time"
"unicode/utf8"
-
- "golang_org/x/crypto/cryptobyte"
- cryptobyte_asn1 "golang_org/x/crypto/cryptobyte/asn1"
)
// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
@@ -78,7 +77,7 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
}
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
// This is a NULL parameters value which is required by
- // https://tools.ietf.org/html/rfc3279#section-2.3.1.
+ // RFC 3279, Section 2.3.1.
publicKeyAlgorithm.Parameters = asn1.NullRawValue
case *ecdsa.PublicKey:
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
@@ -334,7 +333,7 @@ var signatureAlgorithmDetails = []struct {
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that
-// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
+// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
type pssParameters struct {
// The following three fields are not marked as
// optional because the default values specify SHA-1,
@@ -413,13 +412,11 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm
return UnknownSignatureAlgorithm
}
- // PSS is greatly overburdened with options. This code forces
- // them into three buckets by requiring that the MGF1 hash
- // function always match the message hash function (as
- // recommended in
- // https://tools.ietf.org/html/rfc3447#section-8.1), that the
- // salt length matches the hash length, and that the trailer
- // field has the default value.
+ // PSS is greatly overburdened with options. This code forces them into
+ // three buckets by requiring that the MGF1 hash function always match the
+ // message hash function (as recommended in RFC 3447, Section 8.1), that the
+ // salt length matches the hash length, and that the trailer field has the
+ // default value.
if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) ||
!params.MGF.Algorithm.Equal(oidMGF1) ||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
@@ -987,8 +984,8 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
- // RSA public keys must have a NULL in the parameters
- // (https://tools.ietf.org/html/rfc3279#section-2.3.1).
+ // RSA public keys must have a NULL in the parameters.
+ // See RFC 3279, Section 2.3.1.
if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) {
return nil, errors.New("x509: RSA key missing NULL parameters")
}
@@ -1203,7 +1200,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
}
if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 {
- // https://tools.ietf.org/html/rfc5280#section-4.2.1.10:
+ // From RFC 5280, Section 4.2.1.10:
// “either the permittedSubtrees field
// or the excludedSubtrees MUST be
// present”
@@ -1798,7 +1795,7 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectAltName
- // https://tools.ietf.org/html/rfc5280#section-4.2.1.6
+ // From RFC 5280, Section 4.2.1.6:
// “If the subject field contains an empty sequence ... then
// subjectAltName extension ... is marked as critical”
ret[n].Critical = subjectIsEmpty
@@ -2357,8 +2354,7 @@ func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndVa
// parseCSRExtensions parses the attributes from a CSR and extracts any
// requested extensions.
func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
- // pkcs10Attribute reflects the Attribute structure from section 4.1 of
- // https://tools.ietf.org/html/rfc2986.
+ // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1.
type pkcs10Attribute struct {
Id asn1.ObjectIdentifier
Values []asn1.RawValue `asn1:"set"`
From 101a677ebf87f6ed0ed877533c54c7270edadc20 Mon Sep 17 00:00:00 2001
From: Rob Pike
Date: Sat, 13 Oct 2018 21:06:43 +1100
Subject: [PATCH 157/240] cmd/doc: add -all flag to print all documentation for
package
Unlike the one for the old godoc, you need the -u flag to see
unexported symbols. This seems like the right behavior: it's
consistent.
For now at least, the argument must be a package, not a symbol.
This is also different from old godoc.
Required a little refactoring but also cleaned up a few things.
Update #25595
Leaving the bug open for now until we tackle
go doc -all symbol
Change-Id: Ibc1975bfa592cb1e92513eb2e5e9e11e01a60095
Reviewed-on: https://go-review.googlesource.com/c/141977
Run-TryBot: Rob Pike
TryBot-Result: Gobot Gobot