From 26713b5fefc158feb1f0f3d5d30627de226f7668 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 19 Feb 2021 17:37:17 -0500 Subject: [PATCH 0001/1298] go/types: don't write during sanitizeInfo if nothing has changed In its final phase, the typechecker walks the types it produces to ensure that no unexpanded type instances leak through the API. However, this also walks shared types (such as those in the universe scope), resulting in a potential data race during concurrent typechecking passes. Fix this by being careful not to write if nothing needs to be changed. Since any shared types should already be sanitized, this should eliminate data races. For #44434 Change-Id: Iadb2e78863efe0e974e69a00e255f26cfaf9386a Reviewed-on: https://go-review.googlesource.com/c/go/+/294411 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/go/types/sanitize.go | 82 ++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index c4e729ec9b..3a6896c5c2 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -6,6 +6,11 @@ package types // sanitizeInfo walks the types contained in info to ensure that all instances // are expanded. +// +// This includes some objects that may be shared across concurrent +// type-checking passes (such as those in the universe scope), so we are +// careful here not to write types that are already sanitized. This avoids a +// data race as any shared types should already be sanitized. func sanitizeInfo(info *Info) { var s sanitizer = make(map[Type]Type) @@ -13,27 +18,42 @@ func sanitizeInfo(info *Info) { // If modified, they must be assigned back. for e, tv := range info.Types { - tv.Type = s.typ(tv.Type) - info.Types[e] = tv + if typ := s.typ(tv.Type); typ != tv.Type { + tv.Type = typ + info.Types[e] = tv + } } for e, inf := range info.Inferred { + changed := false for i, targ := range inf.Targs { - inf.Targs[i] = s.typ(targ) + if typ := s.typ(targ); typ != targ { + inf.Targs[i] = typ + changed = true + } + } + if typ := s.typ(inf.Sig); typ != inf.Sig { + inf.Sig = typ.(*Signature) + changed = true + } + if changed { + info.Inferred[e] = inf } - inf.Sig = s.typ(inf.Sig).(*Signature) - info.Inferred[e] = inf } for _, obj := range info.Defs { if obj != nil { - obj.setType(s.typ(obj.Type())) + if typ := s.typ(obj.Type()); typ != obj.Type() { + obj.setType(typ) + } } } for _, obj := range info.Uses { if obj != nil { - obj.setType(s.typ(obj.Type())) + if typ := s.typ(obj.Type()); typ != obj.Type() { + obj.setType(typ) + } } } @@ -57,16 +77,22 @@ func (s sanitizer) typ(typ Type) Type { // nothing to do case *Array: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Slice: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Struct: s.varList(t.fields) case *Pointer: - t.base = s.typ(t.base) + if base := s.typ(t.base); base != t.base { + t.base = base + } case *Tuple: s.tuple(t) @@ -87,20 +113,32 @@ func (s sanitizer) typ(typ Type) Type { s.typ(t.allTypes) case *Map: - t.key = s.typ(t.key) - t.elem = s.typ(t.elem) + if key := s.typ(t.key); key != t.key { + t.key = key + } + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Chan: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Named: - t.orig = s.typ(t.orig) - t.underlying = s.typ(t.underlying) + if orig := s.typ(t.orig); orig != t.orig { + t.orig = orig + } + if under := s.typ(t.underlying); under != t.underlying { + t.underlying = under + } s.typeList(t.targs) s.funcList(t.methods) case *TypeParam: - t.bound = s.typ(t.bound) + if bound := s.typ(t.bound); bound != t.bound { + t.bound = bound + } case *instance: typ = t.expand() @@ -115,7 +153,9 @@ func (s sanitizer) typ(typ Type) Type { func (s sanitizer) var_(v *Var) { if v != nil { - v.typ = s.typ(v.typ) + if typ := s.typ(v.typ); typ != v.typ { + v.typ = typ + } } } @@ -133,7 +173,9 @@ func (s sanitizer) tuple(t *Tuple) { func (s sanitizer) func_(f *Func) { if f != nil { - f.typ = s.typ(f.typ) + if typ := s.typ(f.typ); typ != f.typ { + f.typ = typ + } } } @@ -145,6 +187,8 @@ func (s sanitizer) funcList(list []*Func) { func (s sanitizer) typeList(list []Type) { for i, t := range list { - list[i] = s.typ(t) + if typ := s.typ(t); typ != t { + list[i] = typ + } } } -- GitLab From 078f08f0ee1eb6cb172fc1f9d53f34c5783e522d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 16 Feb 2021 21:05:08 -0800 Subject: [PATCH 0002/1298] spec: every type has a method set (minor clarification) The spec states that a type "may" have a method set associated with it. Yet every type has a method set, which may be empty. This is clarified later in the same paragraph. Be clear in the first sentence as well. Per the suggestion from https://github.com/DQNEO. Fixes #44318. Change-Id: I6097b1c7062853e404b7fead56d18a7f9c576fc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/292853 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Ian Lance Taylor --- doc/go_spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 59c9ce3c43..e22fabd699 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -830,7 +830,7 @@ The underlying type of []B1, B3, and B4 i

Method sets

-A type may have a method set associated with it. +A type has a (possibly empty) method set associated with it. The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T. -- GitLab From a8942d2cffd80c68febe1c908a0eb464d2f5bb40 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Feb 2021 17:01:35 -0500 Subject: [PATCH 0003/1298] runtime/pprof: disable TestMorestack on darwin/arm64 Something is weird about darwin and TestMorestack, but it is only manifesting on arm64 and race+amd64. Disable for now. Change-Id: I5862372fdd0b5ffae802fdefb65b2aa04e266fcc Reviewed-on: https://go-review.googlesource.com/c/go/+/294409 Reviewed-by: Dmitri Shuralyov Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot --- src/runtime/pprof/pprof_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 168c1d4496..14321b0934 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -591,6 +591,11 @@ func TestMorestack(t *testing.T) { // https://build.golang.org/log/280d387327806e17c8aabeb38b9503dbbd942ed1 t.Skip("skipping on darwin race detector") } + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + // For whatever reason, darwin/arm64 also doesn't work. + // https://build.golang.org/log/c45e82cc25f152642e6fb90d882ef5a8cd130ce5 + t.Skip("skipping on darwin/arm64") + } testCPUProfile(t, stackContainsAll, []string{"runtime.newstack,runtime/pprof.growstack"}, avoidFunctions(), func(duration time.Duration) { t := time.After(duration) c := make(chan bool) -- GitLab From 5b76343a1040571e3d2249168a00a4dc814e920a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 22 Jun 2020 13:27:10 -0400 Subject: [PATCH 0004/1298] go/build: prefer //go:build over // +build lines Part of //go:build change (#41184). See https://golang.org/design/draft-gobuild - Reject files with multiple //go:build lines. - If a file has both //go:build and // +build lines, only use the //go:build line. - Otherwise fall back to // +build lines - Use go/build/constraint for parsing both //go:build and // +build lines. For Go 1.17. Change-Id: I32e2404d8ce266230f767718dc7cc24e77b425e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/240607 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/go/build/build.go | 139 ++++++++++++++++++------------------- src/go/build/build_test.go | 88 +++++++++++++++-------- src/go/build/deps_test.go | 2 +- 3 files changed, 127 insertions(+), 102 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index 217fadf5bd..0732f6aa19 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "go/ast" + "go/build/constraint" "go/doc" "go/token" exec "internal/execabs" @@ -1423,7 +1424,7 @@ func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binary // Look for +build comments to accept or reject the file. ok, sawBinaryOnly, err := ctxt.shouldBuild(info.header, allTags) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %v", name, err) } if !ok && !ctxt.UseAllFiles { return nil, nil @@ -1459,11 +1460,12 @@ var ( bSlashSlash = []byte(slashSlash) bStarSlash = []byte(starSlash) bSlashStar = []byte(slashStar) + bPlusBuild = []byte("+build") goBuildComment = []byte("//go:build") errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment") - errMultipleGoBuild = errors.New("multiple //go:build comments") // unused in Go 1.(N-1) + errMultipleGoBuild = errors.New("multiple //go:build comments") ) func isGoBuildComment(line []byte) bool { @@ -1498,8 +1500,7 @@ var binaryOnlyComment = []byte("//go:binary-only-package") // shouldBuild reports whether the file should be built // and whether a //go:binary-only-package comment was found. func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) (shouldBuild, binaryOnly bool, err error) { - - // Pass 1. Identify leading run of // comments and blank lines, + // Identify leading run of // comments and blank lines, // which must be followed by a blank line. // Also identify any //go:build comments. content, goBuild, sawBinaryOnly, err := parseFileHeader(content) @@ -1507,44 +1508,42 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) (shoul return false, false, err } - // Pass 2. Process each +build line in the run. - p := content - shouldBuild = true - sawBuild := false - for len(p) > 0 { - line := p - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, p = line[:i], p[i+1:] - } else { - p = p[len(p):] - } - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, bSlashSlash) { - continue + // If //go:build line is present, it controls. + // Otherwise fall back to +build processing. + switch { + case goBuild != nil: + x, err := constraint.Parse(string(goBuild)) + if err != nil { + return false, false, fmt.Errorf("parsing //go:build line: %v", err) } - line = bytes.TrimSpace(line[len(bSlashSlash):]) - if len(line) > 0 && line[0] == '+' { - // Looks like a comment +line. - f := strings.Fields(string(line)) - if f[0] == "+build" { - sawBuild = true - ok := false - for _, tok := range f[1:] { - if ctxt.match(tok, allTags) { - ok = true - } - } - if !ok { + shouldBuild = ctxt.eval(x, allTags) + + default: + shouldBuild = true + p := content + for len(p) > 0 { + line := p + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, p = line[:i], p[i+1:] + } else { + p = p[len(p):] + } + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) { + continue + } + text := string(line) + if !constraint.IsPlusBuild(text) { + continue + } + if x, err := constraint.Parse(text); err == nil { + if !ctxt.eval(x, allTags) { shouldBuild = false } } } } - if goBuild != nil && !sawBuild { - return false, false, errGoBuildWithoutBuild - } - return shouldBuild, sawBinaryOnly, nil } @@ -1580,7 +1579,7 @@ Lines: } if !inSlashStar && isGoBuildComment(line) { - if false && goBuild != nil { // enabled in Go 1.N + if goBuild != nil { return nil, nil, false, errMultipleGoBuild } goBuild = line @@ -1649,7 +1648,7 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) if len(cond) > 0 { ok := false for _, c := range cond { - if ctxt.match(c, nil) { + if ctxt.matchAuto(c, nil) { ok = true break } @@ -1831,50 +1830,44 @@ func splitQuoted(s string) (r []string, err error) { return args, err } -// match reports whether the name is one of: +// matchAuto interprets text as either a +build or //go:build expression (whichever works), +// reporting whether the expression matches the build context. // +// matchAuto is only used for testing of tag evaluation +// and in #cgo lines, which accept either syntax. +func (ctxt *Context) matchAuto(text string, allTags map[string]bool) bool { + if strings.ContainsAny(text, "&|()") { + text = "//go:build " + text + } else { + text = "// +build " + text + } + x, err := constraint.Parse(text) + if err != nil { + return false + } + return ctxt.eval(x, allTags) +} + +func (ctxt *Context) eval(x constraint.Expr, allTags map[string]bool) bool { + return x.Eval(func(tag string) bool { return ctxt.matchTag(tag, allTags) }) +} + +// matchTag reports whether the name is one of: +// +// cgo (if cgo is enabled) // $GOOS // $GOARCH -// cgo (if cgo is enabled) -// !cgo (if cgo is disabled) // ctxt.Compiler -// !ctxt.Compiler +// linux (if GOOS = android) +// solaris (if GOOS = illumos) // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) -// !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) -// a comma-separated list of any of these // -func (ctxt *Context) match(name string, allTags map[string]bool) bool { - if name == "" { - if allTags != nil { - allTags[name] = true - } - return false - } - if i := strings.Index(name, ","); i >= 0 { - // comma-separated list - ok1 := ctxt.match(name[:i], allTags) - ok2 := ctxt.match(name[i+1:], allTags) - return ok1 && ok2 - } - if strings.HasPrefix(name, "!!") { // bad syntax, reject always - return false - } - if strings.HasPrefix(name, "!") { // negation - return len(name) > 1 && !ctxt.match(name[1:], allTags) - } - +// It records all consulted tags in allTags. +func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool { if allTags != nil { allTags[name] = true } - // Tags must be letters, digits, underscores or dots. - // Unlike in Go identifiers, all digits are fine (e.g., "386"). - for _, c := range name { - if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { - return false - } - } - // special tags if ctxt.CgoEnabled && name == "cgo" { return true @@ -1946,10 +1939,10 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { } n := len(l) if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { - return ctxt.match(l[n-1], allTags) && ctxt.match(l[n-2], allTags) + return ctxt.matchTag(l[n-1], allTags) && ctxt.matchTag(l[n-2], allTags) } if n >= 1 && (knownOS[l[n-1]] || knownArch[l[n-1]]) { - return ctxt.match(l[n-1], allTags) + return ctxt.matchTag(l[n-1], allTags) } return true } diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index d8f264cac7..0762a150eb 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -30,7 +30,7 @@ func TestMatch(t *testing.T) { match := func(tag string, want map[string]bool) { t.Helper() m := make(map[string]bool) - if !ctxt.match(tag, m) { + if !ctxt.matchAuto(tag, m) { t.Errorf("%s context should match %s, does not", what, tag) } if !reflect.DeepEqual(m, want) { @@ -40,7 +40,7 @@ func TestMatch(t *testing.T) { nomatch := func(tag string, want map[string]bool) { t.Helper() m := make(map[string]bool) - if ctxt.match(tag, m) { + if ctxt.matchAuto(tag, m) { t.Errorf("%s context should NOT match %s, does", what, tag) } if !reflect.DeepEqual(m, want) { @@ -153,6 +153,13 @@ var shouldBuildTests = []struct { tags: map[string]bool{"yes": true}, shouldBuild: true, }, + { + name: "Yes2", + content: "//go:build yes\n" + + "package main\n", + tags: map[string]bool{"yes": true}, + shouldBuild: true, + }, { name: "Or", content: "// +build no yes\n\n" + @@ -160,6 +167,13 @@ var shouldBuildTests = []struct { tags: map[string]bool{"yes": true, "no": true}, shouldBuild: true, }, + { + name: "Or2", + content: "//go:build no || yes\n" + + "package main\n", + tags: map[string]bool{"yes": true, "no": true}, + shouldBuild: true, + }, { name: "And", content: "// +build no,yes\n\n" + @@ -167,6 +181,13 @@ var shouldBuildTests = []struct { tags: map[string]bool{"yes": true, "no": true}, shouldBuild: false, }, + { + name: "And2", + content: "//go:build no && yes\n" + + "package main\n", + tags: map[string]bool{"yes": true, "no": true}, + shouldBuild: false, + }, { name: "Cgo", content: "// +build cgo\n\n" + @@ -177,12 +198,23 @@ var shouldBuildTests = []struct { tags: map[string]bool{"cgo": true}, shouldBuild: false, }, + { + name: "Cgo2", + content: "//go:build cgo\n" + + "// Copyright The Go Authors.\n\n" + + "// This package implements parsing of tags like\n" + + "// +build tag1\n" + + "package build", + tags: map[string]bool{"cgo": true}, + shouldBuild: false, + }, { name: "AfterPackage", content: "// Copyright The Go Authors.\n\n" + "package build\n\n" + "// shouldBuild checks tags given by lines of the form\n" + "// +build tag\n" + + "//go:build tag\n" + "func shouldBuild(content []byte)\n", tags: map[string]bool{}, shouldBuild: true, @@ -194,6 +226,13 @@ var shouldBuildTests = []struct { tags: map[string]bool{}, shouldBuild: true, }, + { + name: "TooClose2", + content: "//go:build yes\n" + + "package main\n", + tags: map[string]bool{"yes": true}, + shouldBuild: true, + }, { name: "TooCloseNo", content: "// +build no\n" + @@ -201,6 +240,13 @@ var shouldBuildTests = []struct { tags: map[string]bool{}, shouldBuild: true, }, + { + name: "TooCloseNo2", + content: "//go:build no\n" + + "package main\n", + tags: map[string]bool{"no": true}, + shouldBuild: false, + }, { name: "BinaryOnly", content: "//go:binary-only-package\n" + @@ -211,41 +257,30 @@ var shouldBuildTests = []struct { shouldBuild: true, }, { - name: "ValidGoBuild", - content: "// +build yes\n\n" + + name: "BinaryOnly2", + content: "//go:binary-only-package\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{"yes": true}, - shouldBuild: true, - }, - { - name: "MissingBuild", - content: "//go:build no\n" + - "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, + binaryOnly: true, shouldBuild: false, - err: errGoBuildWithoutBuild, }, { - name: "MissingBuild2", - content: "/* */\n" + - "// +build yes\n\n" + + name: "ValidGoBuild", + content: "// +build yes\n\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, shouldBuild: false, - err: errGoBuildWithoutBuild, }, { name: "MissingBuild2", - content: "/*\n" + + content: "/* */\n" + "// +build yes\n\n" + - "*/\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, shouldBuild: false, - err: errGoBuildWithoutBuild, }, { name: "Comment1", @@ -263,9 +298,8 @@ var shouldBuildTests = []struct { "*/\n\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, shouldBuild: false, - err: errGoBuildWithoutBuild, }, { name: "Comment3", @@ -274,9 +308,8 @@ var shouldBuildTests = []struct { "*/\n\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, shouldBuild: false, - err: errGoBuildWithoutBuild, }, { name: "Comment4", @@ -290,9 +323,8 @@ var shouldBuildTests = []struct { content: "/**/\n" + "//go:build no\n" + "package main\n", - tags: map[string]bool{}, + tags: map[string]bool{"no": true}, shouldBuild: false, - err: errGoBuildWithoutBuild, }, } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index e5c849e8f5..42184276ea 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -295,7 +295,7 @@ var depsRules = ` FMT < go/build/constraint; - go/doc, go/parser, internal/goroot, internal/goversion + go/build/constraint, go/doc, go/parser, internal/goroot, internal/goversion < go/build; DEBUG, go/build, go/types, text/scanner -- GitLab From 9fd6cc105db89107bf163d2f0c1f8f55e442ec4d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Jun 2020 16:22:35 -0400 Subject: [PATCH 0005/1298] go/printer: canonicalize //go:build and // +build lines while formatting Part of //go:build change (#41184). See https://golang.org/design/draft-gobuild Gofmt and any other go/printer-using program will now: - move //go:build and //+build lines to the appropriate file location - if there's no //go:build line, add one derived from the // +build lines - if there is a //go:build line, recompute and replace any // +build lines to match what the //go:build line says For Go 1.17. Change-Id: Ide5cc3b4a07507ba9ed6f8b0de846e840876f49f Reviewed-on: https://go-review.googlesource.com/c/go/+/240608 Trust: Russ Cox Trust: Jay Conrod Run-TryBot: Russ Cox Reviewed-by: Jay Conrod --- src/go/build/deps_test.go | 8 +- src/go/format/format_test.go | 4 + src/go/printer/gobuild.go | 170 ++++++++++++++++++++++++ src/go/printer/printer.go | 14 ++ src/go/printer/printer_test.go | 20 ++- src/go/printer/testdata/gobuild1.golden | 6 + src/go/printer/testdata/gobuild1.input | 7 + src/go/printer/testdata/gobuild2.golden | 8 ++ src/go/printer/testdata/gobuild2.input | 9 ++ src/go/printer/testdata/gobuild3.golden | 10 ++ src/go/printer/testdata/gobuild3.input | 11 ++ src/go/printer/testdata/gobuild4.golden | 6 + src/go/printer/testdata/gobuild4.input | 5 + src/go/printer/testdata/gobuild5.golden | 4 + src/go/printer/testdata/gobuild5.input | 4 + src/go/printer/testdata/gobuild6.golden | 5 + src/go/printer/testdata/gobuild6.input | 4 + src/go/printer/testdata/gobuild7.golden | 11 ++ src/go/printer/testdata/gobuild7.input | 11 ++ 19 files changed, 307 insertions(+), 10 deletions(-) create mode 100644 src/go/printer/gobuild.go create mode 100644 src/go/printer/testdata/gobuild1.golden create mode 100644 src/go/printer/testdata/gobuild1.input create mode 100644 src/go/printer/testdata/gobuild2.golden create mode 100644 src/go/printer/testdata/gobuild2.input create mode 100644 src/go/printer/testdata/gobuild3.golden create mode 100644 src/go/printer/testdata/gobuild3.input create mode 100644 src/go/printer/testdata/gobuild4.golden create mode 100644 src/go/printer/testdata/gobuild4.input create mode 100644 src/go/printer/testdata/gobuild5.golden create mode 100644 src/go/printer/testdata/gobuild5.input create mode 100644 src/go/printer/testdata/gobuild6.golden create mode 100644 src/go/printer/testdata/gobuild6.input create mode 100644 src/go/printer/testdata/gobuild7.golden create mode 100644 src/go/printer/testdata/gobuild7.input diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 42184276ea..e05d0aac2e 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -279,7 +279,10 @@ var depsRules = ` < go/ast < go/parser; - go/parser, text/tabwriter + FMT + < go/build/constraint; + + go/build/constraint, go/parser, text/tabwriter < go/printer < go/format; @@ -292,9 +295,6 @@ var depsRules = ` container/heap, go/constant, go/parser, regexp < go/types; - FMT - < go/build/constraint; - go/build/constraint, go/doc, go/parser, internal/goroot, internal/goversion < go/build; diff --git a/src/go/format/format_test.go b/src/go/format/format_test.go index 27f4c74cdf..6cc0278b79 100644 --- a/src/go/format/format_test.go +++ b/src/go/format/format_test.go @@ -151,6 +151,10 @@ var tests = []string{ // erroneous programs "ERROR1 + 2 +", "ERRORx := 0", + + // build comments + "// copyright\n\n//go:build x\n\npackage p\n", + "// copyright\n\n//go:build x\n// +build x\n\npackage p\n", } func String(s string) (string, error) { diff --git a/src/go/printer/gobuild.go b/src/go/printer/gobuild.go new file mode 100644 index 0000000000..f00492d077 --- /dev/null +++ b/src/go/printer/gobuild.go @@ -0,0 +1,170 @@ +// Copyright 2020 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 printer + +import ( + "go/build/constraint" + "sort" + "text/tabwriter" +) + +func (p *printer) fixGoBuildLines() { + if len(p.goBuild)+len(p.plusBuild) == 0 { + return + } + + // Find latest possible placement of //go:build and // +build comments. + // That's just after the last blank line before we find a non-comment. + // (We'll add another blank line after our comment block.) + // When we start dropping // +build comments, we can skip over /* */ comments too. + // Note that we are processing tabwriter input, so every comment + // begins and ends with a tabwriter.Escape byte. + // And some newlines have turned into \f bytes. + insert := 0 + for pos := 0; ; { + // Skip leading space at beginning of line. + blank := true + for pos < len(p.output) && (p.output[pos] == ' ' || p.output[pos] == '\t') { + pos++ + } + // Skip over // comment if any. + if pos+3 < len(p.output) && p.output[pos] == tabwriter.Escape && p.output[pos+1] == '/' && p.output[pos+2] == '/' { + blank = false + for pos < len(p.output) && !isNL(p.output[pos]) { + pos++ + } + } + // Skip over \n at end of line. + if pos >= len(p.output) || !isNL(p.output[pos]) { + break + } + pos++ + + if blank { + insert = pos + } + } + + // If there is a //go:build comment before the place we identified, + // use that point instead. (Earlier in the file is always fine.) + if len(p.goBuild) > 0 && p.goBuild[0] < insert { + insert = p.goBuild[0] + } else if len(p.plusBuild) > 0 && p.plusBuild[0] < insert { + insert = p.plusBuild[0] + } + + var x constraint.Expr + switch len(p.goBuild) { + case 0: + // Synthesize //go:build expression from // +build lines. + for _, pos := range p.plusBuild { + y, err := constraint.Parse(p.commentTextAt(pos)) + if err != nil { + x = nil + break + } + if x == nil { + x = y + } else { + x = &constraint.AndExpr{X: x, Y: y} + } + } + case 1: + // Parse //go:build expression. + x, _ = constraint.Parse(p.commentTextAt(p.goBuild[0])) + } + + var block []byte + if x == nil { + // Don't have a valid //go:build expression to treat as truth. + // Bring all the lines together but leave them alone. + // Note that these are already tabwriter-escaped. + for _, pos := range p.goBuild { + block = append(block, p.lineAt(pos)...) + } + for _, pos := range p.plusBuild { + block = append(block, p.lineAt(pos)...) + } + } else { + block = append(block, tabwriter.Escape) + block = append(block, "//go:build "...) + block = append(block, x.String()...) + block = append(block, tabwriter.Escape, '\n') + if len(p.plusBuild) > 0 { + lines, err := constraint.PlusBuildLines(x) + if err != nil { + lines = []string{"// +build error: " + err.Error()} + } + for _, line := range lines { + block = append(block, tabwriter.Escape) + block = append(block, line...) + block = append(block, tabwriter.Escape, '\n') + } + } + } + block = append(block, '\n') + + // Build sorted list of lines to delete from remainder of output. + toDelete := append(p.goBuild, p.plusBuild...) + sort.Ints(toDelete) + + // Collect output after insertion point, with lines deleted, into after. + var after []byte + start := insert + for _, end := range toDelete { + if end < start { + continue + } + after = appendLines(after, p.output[start:end]) + start = end + len(p.lineAt(end)) + } + after = appendLines(after, p.output[start:]) + if n := len(after); n >= 2 && isNL(after[n-1]) && isNL(after[n-2]) { + after = after[:n-1] + } + + p.output = p.output[:insert] + p.output = append(p.output, block...) + p.output = append(p.output, after...) +} + +// appendLines is like append(x, y...) +// but it avoids creating doubled blank lines, +// which would not be gofmt-standard output. +// It assumes that only whole blocks of lines are being appended, +// not line fragments. +func appendLines(x, y []byte) []byte { + if len(y) > 0 && isNL(y[0]) && // y starts in blank line + (len(x) == 0 || len(x) >= 2 && isNL(x[len(x)-1]) && isNL(x[len(x)-2])) { // x is empty or ends in blank line + y = y[1:] // delete y's leading blank line + } + return append(x, y...) +} + +func (p *printer) lineAt(start int) []byte { + pos := start + for pos < len(p.output) && !isNL(p.output[pos]) { + pos++ + } + if pos < len(p.output) { + pos++ + } + return p.output[start:pos] +} + +func (p *printer) commentTextAt(start int) string { + if start < len(p.output) && p.output[start] == tabwriter.Escape { + start++ + } + pos := start + for pos < len(p.output) && p.output[pos] != tabwriter.Escape && !isNL(p.output[pos]) { + pos++ + } + return string(p.output[start:pos]) +} + +func isNL(b byte) bool { + return b == '\n' || b == '\f' +} diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go index 0077afeaff..f02c1b847b 100644 --- a/src/go/printer/printer.go +++ b/src/go/printer/printer.go @@ -8,6 +8,7 @@ package printer import ( "fmt" "go/ast" + "go/build/constraint" "go/token" "io" "os" @@ -64,6 +65,8 @@ type printer struct { lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace) prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL wsbuf []whiteSpace // delayed white space + goBuild []int // start index of all //go:build comments in output + plusBuild []int // start index of all // +build comments in output // Positions // The out position differs from the pos position when the result @@ -649,6 +652,11 @@ func (p *printer) writeComment(comment *ast.Comment) { // shortcut common case of //-style comments if text[1] == '/' { + if constraint.IsGoBuild(text) { + p.goBuild = append(p.goBuild, len(p.output)) + } else if constraint.IsPlusBuild(text) { + p.plusBuild = append(p.plusBuild, len(p.output)) + } p.writeString(pos, trimRight(text), true) return } @@ -1122,6 +1130,8 @@ func (p *printer) printNode(node interface{}) error { // get comments ready for use p.nextComment() + p.print(pmode(0)) + // format node switch n := node.(type) { case ast.Expr: @@ -1313,6 +1323,10 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{ p.impliedSemi = false // EOF acts like a newline p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) + // output is buffered in p.output now. + // fix //go:build and // +build comments if needed. + p.fixGoBuildLines() + // redirect output through a trimmer to eliminate trailing whitespace // (Input to a tabwriter must be untrimmed since trailing tabs provide // formatting information. The tabwriter could provide trimming diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index b15dcbf000..03c4badb04 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -88,8 +88,11 @@ func lineAt(text []byte, offs int) []byte { // diff compares a and b. func diff(aname, bname string, a, b []byte) error { - var buf bytes.Buffer // holding long error message + if bytes.Equal(a, b) { + return nil + } + var buf bytes.Buffer // holding long error message // compare lengths if len(a) != len(b) { fmt.Fprintf(&buf, "\nlength changed: len(%s) = %d, len(%s) = %d", aname, len(a), bname, len(b)) @@ -97,7 +100,7 @@ func diff(aname, bname string, a, b []byte) error { // compare contents line := 1 - offs := 1 + offs := 0 for i := 0; i < len(a) && i < len(b); i++ { ch := a[i] if ch != b[i] { @@ -112,10 +115,8 @@ func diff(aname, bname string, a, b []byte) error { } } - if buf.Len() > 0 { - return errors.New(buf.String()) - } - return nil + fmt.Fprintf(&buf, "\n%s:\n%s\n%s:\n%s", aname, a, bname, b) + return errors.New(buf.String()) } func runcheck(t *testing.T, source, golden string, mode checkMode) { @@ -207,6 +208,13 @@ var data = []entry{ {"go2numbers.input", "go2numbers.golden", idempotent}, {"go2numbers.input", "go2numbers.norm", normNumber | idempotent}, {"generics.input", "generics.golden", idempotent}, + {"gobuild1.input", "gobuild1.golden", idempotent}, + {"gobuild2.input", "gobuild2.golden", idempotent}, + {"gobuild3.input", "gobuild3.golden", idempotent}, + {"gobuild4.input", "gobuild4.golden", idempotent}, + {"gobuild5.input", "gobuild5.golden", idempotent}, + {"gobuild6.input", "gobuild6.golden", idempotent}, + {"gobuild7.input", "gobuild7.golden", idempotent}, } func TestFiles(t *testing.T) { diff --git a/src/go/printer/testdata/gobuild1.golden b/src/go/printer/testdata/gobuild1.golden new file mode 100644 index 0000000000..649da40e91 --- /dev/null +++ b/src/go/printer/testdata/gobuild1.golden @@ -0,0 +1,6 @@ +//go:build x +// +build x + +package p + +func f() diff --git a/src/go/printer/testdata/gobuild1.input b/src/go/printer/testdata/gobuild1.input new file mode 100644 index 0000000000..6538ee61af --- /dev/null +++ b/src/go/printer/testdata/gobuild1.input @@ -0,0 +1,7 @@ +package p + +//go:build x + +func f() + +// +build y diff --git a/src/go/printer/testdata/gobuild2.golden b/src/go/printer/testdata/gobuild2.golden new file mode 100644 index 0000000000..c46fd34c55 --- /dev/null +++ b/src/go/printer/testdata/gobuild2.golden @@ -0,0 +1,8 @@ +//go:build x +// +build x + +// other comment + +package p + +func f() diff --git a/src/go/printer/testdata/gobuild2.input b/src/go/printer/testdata/gobuild2.input new file mode 100644 index 0000000000..f0f772a7b2 --- /dev/null +++ b/src/go/printer/testdata/gobuild2.input @@ -0,0 +1,9 @@ +// +build y + +// other comment + +package p + +func f() + +//go:build x diff --git a/src/go/printer/testdata/gobuild3.golden b/src/go/printer/testdata/gobuild3.golden new file mode 100644 index 0000000000..db92c5787e --- /dev/null +++ b/src/go/printer/testdata/gobuild3.golden @@ -0,0 +1,10 @@ +// other comment + +//go:build x +// +build x + +// yet another comment + +package p + +func f() diff --git a/src/go/printer/testdata/gobuild3.input b/src/go/printer/testdata/gobuild3.input new file mode 100644 index 0000000000..d0c97b27ad --- /dev/null +++ b/src/go/printer/testdata/gobuild3.input @@ -0,0 +1,11 @@ +// other comment + +// +build y + +// yet another comment + +package p + +//go:build x + +func f() diff --git a/src/go/printer/testdata/gobuild4.golden b/src/go/printer/testdata/gobuild4.golden new file mode 100644 index 0000000000..b16477f9ad --- /dev/null +++ b/src/go/printer/testdata/gobuild4.golden @@ -0,0 +1,6 @@ +//go:build (x || y) && z +// +build x y +// +build z + +// doc comment +package p diff --git a/src/go/printer/testdata/gobuild4.input b/src/go/printer/testdata/gobuild4.input new file mode 100644 index 0000000000..29d5a0ae14 --- /dev/null +++ b/src/go/printer/testdata/gobuild4.input @@ -0,0 +1,5 @@ +// doc comment +package p + +// +build x y +// +build z diff --git a/src/go/printer/testdata/gobuild5.golden b/src/go/printer/testdata/gobuild5.golden new file mode 100644 index 0000000000..2808a53cce --- /dev/null +++ b/src/go/printer/testdata/gobuild5.golden @@ -0,0 +1,4 @@ +//go:build !(x || y) && z +// +build !x,!y,z + +package p diff --git a/src/go/printer/testdata/gobuild5.input b/src/go/printer/testdata/gobuild5.input new file mode 100644 index 0000000000..ec5815cdc6 --- /dev/null +++ b/src/go/printer/testdata/gobuild5.input @@ -0,0 +1,4 @@ +//go:build !(x || y) && z +// +build something else + +package p diff --git a/src/go/printer/testdata/gobuild6.golden b/src/go/printer/testdata/gobuild6.golden new file mode 100644 index 0000000000..abb1e2acbb --- /dev/null +++ b/src/go/printer/testdata/gobuild6.golden @@ -0,0 +1,5 @@ +//go:build !(x || y) && z + +// no +build line + +package p diff --git a/src/go/printer/testdata/gobuild6.input b/src/go/printer/testdata/gobuild6.input new file mode 100644 index 0000000000..162189754f --- /dev/null +++ b/src/go/printer/testdata/gobuild6.input @@ -0,0 +1,4 @@ +//go:build !(x || y) && z +// no +build line + +package p diff --git a/src/go/printer/testdata/gobuild7.golden b/src/go/printer/testdata/gobuild7.golden new file mode 100644 index 0000000000..bf41dd4b59 --- /dev/null +++ b/src/go/printer/testdata/gobuild7.golden @@ -0,0 +1,11 @@ +// Copyright 2013 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. + +// TODO(rsc): Delete this file once Go 1.17 comes out and we can retire Go 1.15 support. + +//go:build !go1.16 +// +build !go1.16 + +// Package buildtag defines an Analyzer that checks build tags. +package buildtag diff --git a/src/go/printer/testdata/gobuild7.input b/src/go/printer/testdata/gobuild7.input new file mode 100644 index 0000000000..bf41dd4b59 --- /dev/null +++ b/src/go/printer/testdata/gobuild7.input @@ -0,0 +1,11 @@ +// Copyright 2013 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. + +// TODO(rsc): Delete this file once Go 1.17 comes out and we can retire Go 1.15 support. + +//go:build !go1.16 +// +build !go1.16 + +// Package buildtag defines an Analyzer that checks build tags. +package buildtag -- GitLab From 0625460f79eed41039939f957baceaff5e269672 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Feb 2021 09:01:32 -0500 Subject: [PATCH 0006/1298] cmd/vet: update buildtag check for //go:build lines Brings in golang.org/x/tools@2363391a and adjusts, adds cmd/vet tests accordingly. Part of //go:build change (#41184). See https://golang.org/design/draft-gobuild This brings in the new //go:build checks in cmd/vet. Change-Id: I8a9735cc014171691012b307ec30e94c81aadfe1 Reviewed-on: https://go-review.googlesource.com/c/go/+/240609 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 6 +- .../go/analysis/passes/buildtag/buildtag.go | 318 ++++++++++++++---- .../analysis/passes/buildtag/buildtag_old.go | 174 ++++++++++ .../passes/loopclosure/loopclosure.go | 67 +++- .../go/analysis/unitchecker/unitchecker.go | 2 +- .../go/analysis/unitchecker/unitchecker112.go | 1 + src/cmd/vendor/modules.txt | 2 +- src/cmd/vet/testdata/asm/asm1.s | 1 + src/cmd/vet/testdata/buildtag/buildtag.go | 6 +- src/cmd/vet/testdata/buildtag/buildtag2.go | 22 ++ src/cmd/vet/testdata/buildtag/buildtag3.go | 15 + src/cmd/vet/testdata/buildtag/buildtag4.go | 11 + src/cmd/vet/testdata/buildtag/buildtag5.go | 11 + src/cmd/vet/testdata/buildtag/buildtag6.s | 9 + src/cmd/vet/testdata/buildtag/buildtag7.s | 11 + src/cmd/vet/testdata/tagtest/file1.go | 1 + src/cmd/vet/testdata/tagtest/file2.go | 1 + src/cmd/vet/vet_test.go | 9 +- 19 files changed, 582 insertions(+), 87 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag_old.go create mode 100644 src/cmd/vet/testdata/buildtag/buildtag2.go create mode 100644 src/cmd/vet/testdata/buildtag/buildtag3.go create mode 100644 src/cmd/vet/testdata/buildtag/buildtag4.go create mode 100644 src/cmd/vet/testdata/buildtag/buildtag5.go create mode 100644 src/cmd/vet/testdata/buildtag/buildtag6.s create mode 100644 src/cmd/vet/testdata/buildtag/buildtag7.s diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 5414e5e688..24ad6c2432 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -8,5 +8,5 @@ require ( golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/mod v0.4.1 golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect - golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff + golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 3dc0565f65..e9b62f46e1 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -13,7 +13,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -25,14 +24,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e h1:f5mksnk+hgXHnImpZoWj64ja99j9zV7YUgrVG95uFE4= golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff h1:6EkB024TP1fu6cmQqeCNw685zYDVt5g8N1BXh755SQM= -golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f h1:R8L2zr6nSvQoIIw/EiaPP6HfmxeiArf+Nh/CWTC60wQ= +golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go index 841b928578..c4407ad91f 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go @@ -2,14 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.16 +// +build go1.16 + // Package buildtag defines an Analyzer that checks build tags. package buildtag import ( - "bytes" - "fmt" "go/ast" + "go/build/constraint" "go/parser" + "go/token" "strings" "unicode" @@ -52,118 +55,313 @@ func runBuildTag(pass *analysis.Pass) (interface{}, error) { } func checkGoFile(pass *analysis.Pass, f *ast.File) { - pastCutoff := false + var check checker + check.init(pass) + defer check.finish() + for _, group := range f.Comments { // A +build comment is ignored after or adjoining the package declaration. if group.End()+1 >= f.Package { - pastCutoff = true + check.plusBuildOK = false } - - // "+build" is ignored within or after a /*...*/ comment. - if !strings.HasPrefix(group.List[0].Text, "//") { - pastCutoff = true - continue + // A //go:build comment is ignored after the package declaration + // (but adjoining it is OK, in contrast to +build comments). + if group.Pos() >= f.Package { + check.goBuildOK = false } // Check each line of a //-comment. for _, c := range group.List { - if !strings.Contains(c.Text, "+build") { - continue - } - if err := checkLine(c.Text, pastCutoff); err != nil { - pass.Reportf(c.Pos(), "%s", err) + // "+build" is ignored within or after a /*...*/ comment. + if !strings.HasPrefix(c.Text, "//") { + check.plusBuildOK = false } + check.comment(c.Slash, c.Text) } } } func checkOtherFile(pass *analysis.Pass, filename string) error { + var check checker + check.init(pass) + defer check.finish() + + // We cannot use the Go parser, since this may not be a Go source file. + // Read the raw bytes instead. content, tf, err := analysisutil.ReadFile(pass.Fset, filename) if err != nil { return err } - // We must look at the raw lines, as build tags may appear in non-Go - // files such as assembly files. - lines := bytes.SplitAfter(content, nl) + check.file(token.Pos(tf.Base()), string(content)) + return nil +} + +type checker struct { + pass *analysis.Pass + plusBuildOK bool // "+build" lines still OK + goBuildOK bool // "go:build" lines still OK + crossCheck bool // cross-check go:build and +build lines when done reading file + inStar bool // currently in a /* */ comment + goBuildPos token.Pos // position of first go:build line found + plusBuildPos token.Pos // position of first "+build" line found + goBuild constraint.Expr // go:build constraint found + plusBuild constraint.Expr // AND of +build constraints found +} + +func (check *checker) init(pass *analysis.Pass) { + check.pass = pass + check.goBuildOK = true + check.plusBuildOK = true + check.crossCheck = true +} +func (check *checker) file(pos token.Pos, text string) { // Determine cutpoint where +build comments are no longer valid. // They are valid in leading // comments in the file followed by // a blank line. // // This must be done as a separate pass because of the // requirement that the comment be followed by a blank line. - var cutoff int - for i, line := range lines { - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, slashSlash) { - if len(line) > 0 { - break - } - cutoff = i + var plusBuildCutoff int + fullText := text + for text != "" { + i := strings.Index(text, "\n") + if i < 0 { + i = len(text) + } else { + i++ + } + offset := len(fullText) - len(text) + line := text[:i] + text = text[i:] + line = strings.TrimSpace(line) + if !strings.HasPrefix(line, "//") && line != "" { + break + } + if line == "" { + plusBuildCutoff = offset } } - for i, line := range lines { - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, slashSlash) { - continue + // Process each line. + // Must stop once we hit goBuildOK == false + text = fullText + check.inStar = false + for text != "" { + i := strings.Index(text, "\n") + if i < 0 { + i = len(text) + } else { + i++ } - if !bytes.Contains(line, []byte("+build")) { + offset := len(fullText) - len(text) + line := text[:i] + text = text[i:] + check.plusBuildOK = offset < plusBuildCutoff + + if strings.HasPrefix(line, "//") { + check.comment(pos+token.Pos(offset), line) continue } - if err := checkLine(string(line), i >= cutoff); err != nil { - pass.Reportf(analysisutil.LineStart(tf, i+1), "%s", err) - continue + + // Keep looking for the point at which //go:build comments + // stop being allowed. Skip over, cut out any /* */ comments. + for { + line = strings.TrimSpace(line) + if check.inStar { + i := strings.Index(line, "*/") + if i < 0 { + line = "" + break + } + line = line[i+len("*/"):] + check.inStar = false + continue + } + if strings.HasPrefix(line, "/*") { + check.inStar = true + line = line[len("/*"):] + continue + } + break + } + if line != "" { + // Found non-comment non-blank line. + // Ends space for valid //go:build comments, + // but also ends the fraction of the file we can + // reliably parse. From this point on we might + // incorrectly flag "comments" inside multiline + // string constants or anything else (this might + // not even be a Go program). So stop. + break } } - return nil } -// checkLine checks a line that starts with "//" and contains "+build". -func checkLine(line string, pastCutoff bool) error { - line = strings.TrimPrefix(line, "//") - line = strings.TrimSpace(line) - - if strings.HasPrefix(line, "+build") { - fields := strings.Fields(line) - if fields[0] != "+build" { - // Comment is something like +buildasdf not +build. - return fmt.Errorf("possible malformed +build comment") +func (check *checker) comment(pos token.Pos, text string) { + if strings.HasPrefix(text, "//") { + if strings.Contains(text, "+build") { + check.plusBuildLine(pos, text) } - if pastCutoff { - return fmt.Errorf("+build comment must appear before package clause and be followed by a blank line") + if strings.Contains(text, "//go:build") { + check.goBuildLine(pos, text) } - if err := checkArguments(fields); err != nil { - return err + } + if strings.HasPrefix(text, "/*") { + if i := strings.Index(text, "\n"); i >= 0 { + // multiline /* */ comment - process interior lines + check.inStar = true + i++ + pos += token.Pos(i) + text = text[i:] + for text != "" { + i := strings.Index(text, "\n") + if i < 0 { + i = len(text) + } else { + i++ + } + line := text[:i] + if strings.HasPrefix(line, "//") { + check.comment(pos, line) + } + pos += token.Pos(i) + text = text[i:] + } + check.inStar = false + } + } +} + +func (check *checker) goBuildLine(pos token.Pos, line string) { + if !constraint.IsGoBuild(line) { + if !strings.HasPrefix(line, "//go:build") && constraint.IsGoBuild("//"+strings.TrimSpace(line[len("//"):])) { + check.pass.Reportf(pos, "malformed //go:build line (space between // and go:build)") } + return + } + if !check.goBuildOK || check.inStar { + check.pass.Reportf(pos, "misplaced //go:build comment") + check.crossCheck = false + return + } + + if check.goBuildPos == token.NoPos { + check.goBuildPos = pos } else { + check.pass.Reportf(pos, "unexpected extra //go:build line") + check.crossCheck = false + } + + // testing hack: stop at // ERROR + if i := strings.Index(line, " // ERROR "); i >= 0 { + line = line[:i] + } + + x, err := constraint.Parse(line) + if err != nil { + check.pass.Reportf(pos, "%v", err) + check.crossCheck = false + return + } + + if check.goBuild == nil { + check.goBuild = x + } +} + +func (check *checker) plusBuildLine(pos token.Pos, line string) { + line = strings.TrimSpace(line) + if !constraint.IsPlusBuild(line) { // Comment with +build but not at beginning. - if !pastCutoff { - return fmt.Errorf("possible malformed +build comment") + // Only report early in file. + if check.plusBuildOK && !strings.HasPrefix(line, "// want") { + check.pass.Reportf(pos, "possible malformed +build comment") } + return + } + if !check.plusBuildOK { // inStar implies !plusBuildOK + check.pass.Reportf(pos, "misplaced +build comment") + check.crossCheck = false } - return nil -} -func checkArguments(fields []string) error { + if check.plusBuildPos == token.NoPos { + check.plusBuildPos = pos + } + + // testing hack: stop at // ERROR + if i := strings.Index(line, " // ERROR "); i >= 0 { + line = line[:i] + } + + fields := strings.Fields(line[len("//"):]) + // IsPlusBuildConstraint check above implies fields[0] == "+build" for _, arg := range fields[1:] { for _, elem := range strings.Split(arg, ",") { if strings.HasPrefix(elem, "!!") { - return fmt.Errorf("invalid double negative in build constraint: %s", arg) + check.pass.Reportf(pos, "invalid double negative in build constraint: %s", arg) + check.crossCheck = false + continue } elem = strings.TrimPrefix(elem, "!") for _, c := range elem { if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { - return fmt.Errorf("invalid non-alphanumeric build constraint: %s", arg) + check.pass.Reportf(pos, "invalid non-alphanumeric build constraint: %s", arg) + check.crossCheck = false + break } } } } - return nil + + if check.crossCheck { + y, err := constraint.Parse(line) + if err != nil { + // Should never happen - constraint.Parse never rejects a // +build line. + // Also, we just checked the syntax above. + // Even so, report. + check.pass.Reportf(pos, "%v", err) + check.crossCheck = false + return + } + if check.plusBuild == nil { + check.plusBuild = y + } else { + check.plusBuild = &constraint.AndExpr{X: check.plusBuild, Y: y} + } + } } -var ( - nl = []byte("\n") - slashSlash = []byte("//") -) +func (check *checker) finish() { + if !check.crossCheck || check.plusBuildPos == token.NoPos || check.goBuildPos == token.NoPos { + return + } + + // Have both //go:build and // +build, + // with no errors found (crossCheck still true). + // Check they match. + var want constraint.Expr + lines, err := constraint.PlusBuildLines(check.goBuild) + if err != nil { + check.pass.Reportf(check.goBuildPos, "%v", err) + return + } + for _, line := range lines { + y, err := constraint.Parse(line) + if err != nil { + // Definitely should not happen, but not the user's fault. + // Do not report. + return + } + if want == nil { + want = y + } else { + want = &constraint.AndExpr{X: want, Y: y} + } + } + if want.String() != check.plusBuild.String() { + check.pass.Reportf(check.plusBuildPos, "+build lines do not match //go:build condition") + return + } +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag_old.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag_old.go new file mode 100644 index 0000000000..e9234925f9 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag_old.go @@ -0,0 +1,174 @@ +// Copyright 2013 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. + +// TODO(rsc): Delete this file once Go 1.17 comes out and we can retire Go 1.15 support. + +//go:build !go1.16 +// +build !go1.16 + +// Package buildtag defines an Analyzer that checks build tags. +package buildtag + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "strings" + "unicode" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" +) + +const Doc = "check that +build tags are well-formed and correctly located" + +var Analyzer = &analysis.Analyzer{ + Name: "buildtag", + Doc: Doc, + Run: runBuildTag, +} + +func runBuildTag(pass *analysis.Pass) (interface{}, error) { + for _, f := range pass.Files { + checkGoFile(pass, f) + } + for _, name := range pass.OtherFiles { + if err := checkOtherFile(pass, name); err != nil { + return nil, err + } + } + for _, name := range pass.IgnoredFiles { + if strings.HasSuffix(name, ".go") { + f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments) + if err != nil { + // Not valid Go source code - not our job to diagnose, so ignore. + return nil, nil + } + checkGoFile(pass, f) + } else { + if err := checkOtherFile(pass, name); err != nil { + return nil, err + } + } + } + return nil, nil +} + +func checkGoFile(pass *analysis.Pass, f *ast.File) { + pastCutoff := false + for _, group := range f.Comments { + // A +build comment is ignored after or adjoining the package declaration. + if group.End()+1 >= f.Package { + pastCutoff = true + } + + // "+build" is ignored within or after a /*...*/ comment. + if !strings.HasPrefix(group.List[0].Text, "//") { + pastCutoff = true + continue + } + + // Check each line of a //-comment. + for _, c := range group.List { + if !strings.Contains(c.Text, "+build") { + continue + } + if err := checkLine(c.Text, pastCutoff); err != nil { + pass.Reportf(c.Pos(), "%s", err) + } + } + } +} + +func checkOtherFile(pass *analysis.Pass, filename string) error { + content, tf, err := analysisutil.ReadFile(pass.Fset, filename) + if err != nil { + return err + } + + // We must look at the raw lines, as build tags may appear in non-Go + // files such as assembly files. + lines := bytes.SplitAfter(content, nl) + + // Determine cutpoint where +build comments are no longer valid. + // They are valid in leading // comments in the file followed by + // a blank line. + // + // This must be done as a separate pass because of the + // requirement that the comment be followed by a blank line. + var cutoff int + for i, line := range lines { + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, slashSlash) { + if len(line) > 0 { + break + } + cutoff = i + } + } + + for i, line := range lines { + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, slashSlash) { + continue + } + if !bytes.Contains(line, []byte("+build")) { + continue + } + if err := checkLine(string(line), i >= cutoff); err != nil { + pass.Reportf(analysisutil.LineStart(tf, i+1), "%s", err) + continue + } + } + return nil +} + +// checkLine checks a line that starts with "//" and contains "+build". +func checkLine(line string, pastCutoff bool) error { + line = strings.TrimPrefix(line, "//") + line = strings.TrimSpace(line) + + if strings.HasPrefix(line, "+build") { + fields := strings.Fields(line) + if fields[0] != "+build" { + // Comment is something like +buildasdf not +build. + return fmt.Errorf("possible malformed +build comment") + } + if pastCutoff { + return fmt.Errorf("+build comment must appear before package clause and be followed by a blank line") + } + if err := checkArguments(fields); err != nil { + return err + } + } else { + // Comment with +build but not at beginning. + if !pastCutoff { + return fmt.Errorf("possible malformed +build comment") + } + } + return nil +} + +func checkArguments(fields []string) error { + for _, arg := range fields[1:] { + for _, elem := range strings.Split(arg, ",") { + if strings.HasPrefix(elem, "!!") { + return fmt.Errorf("invalid double negative in build constraint: %s", arg) + } + elem = strings.TrimPrefix(elem, "!") + for _, c := range elem { + if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { + return fmt.Errorf("invalid non-alphanumeric build constraint: %s", arg) + } + } + } + } + return nil +} + +var ( + nl = []byte("\n") + slashSlash = []byte("//") +) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go index a14e7eb55d..3ea91574dc 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go @@ -8,22 +8,14 @@ package loopclosure import ( "go/ast" + "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) -// TODO(adonovan): also report an error for the following structure, -// which is often used to ensure that deferred calls do not accumulate -// in a loop: -// -// for i, x := range c { -// func() { -// ...reference to i or x... -// }() -// } - const Doc = `check references to loop variables from within nested functions This analyzer checks for references to loop variables from within a @@ -95,16 +87,19 @@ func run(pass *analysis.Pass) (interface{}, error) { if len(body.List) == 0 { return } - var last *ast.CallExpr + // The function invoked in the last return statement. + var fun ast.Expr switch s := body.List[len(body.List)-1].(type) { case *ast.GoStmt: - last = s.Call + fun = s.Call.Fun case *ast.DeferStmt: - last = s.Call - default: - return + fun = s.Call.Fun + case *ast.ExprStmt: // check for errgroup.Group.Go() + if call, ok := s.X.(*ast.CallExpr); ok { + fun = goInvokes(pass.TypesInfo, call) + } } - lit, ok := last.Fun.(*ast.FuncLit) + lit, ok := fun.(*ast.FuncLit) if !ok { return } @@ -128,3 +123,43 @@ func run(pass *analysis.Pass) (interface{}, error) { }) return nil, nil } + +// goInvokes returns a function expression that would be called asynchronously +// (but not awaited) in another goroutine as a consequence of the call. +// For example, given the g.Go call below, it returns the function literal expression. +// +// import "sync/errgroup" +// var g errgroup.Group +// g.Go(func() error { ... }) +// +// Currently only "golang.org/x/sync/errgroup.Group()" is considered. +func goInvokes(info *types.Info, call *ast.CallExpr) ast.Expr { + f := typeutil.StaticCallee(info, call) + // Note: Currently only supports: golang.org/x/sync/errgroup.Go. + if f == nil || f.Name() != "Go" { + return nil + } + recv := f.Type().(*types.Signature).Recv() + if recv == nil { + return nil + } + rtype, ok := recv.Type().(*types.Pointer) + if !ok { + return nil + } + named, ok := rtype.Elem().(*types.Named) + if !ok { + return nil + } + if named.Obj().Name() != "Group" { + return nil + } + pkg := f.Pkg() + if pkg == nil { + return nil + } + if pkg.Path() != "golang.org/x/sync/errgroup" { + return nil + } + return call.Args[0] +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index 713e1380ef..5424489f8b 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -97,7 +97,7 @@ func Main(analyzers ...*analysis.Analyzer) { Usage of %[1]s: %.16[1]s unit.cfg # execute analysis specified by config file - %.16[1]s help # general help + %.16[1]s help # general help, including listing analyzers and flags %.16[1]s help name # help on specific analyzer and its flags `, progname) os.Exit(1) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go index 9051456e39..3180f4abe1 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.12 // +build go1.12 package unitchecker diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 616fb6c1e6..abe70ae87e 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -44,7 +44,7 @@ golang.org/x/mod/zip golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff +# golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ## explicit golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/internal/analysisflags diff --git a/src/cmd/vet/testdata/asm/asm1.s b/src/cmd/vet/testdata/asm/asm1.s index a5bb6dd0af..050c498d12 100644 --- a/src/cmd/vet/testdata/asm/asm1.s +++ b/src/cmd/vet/testdata/asm/asm1.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 // +build amd64 TEXT ·arg1(SB),0,$0-2 diff --git a/src/cmd/vet/testdata/buildtag/buildtag.go b/src/cmd/vet/testdata/buildtag/buildtag.go index c2fd6aaaf2..7371e6ef6f 100644 --- a/src/cmd/vet/testdata/buildtag/buildtag.go +++ b/src/cmd/vet/testdata/buildtag/buildtag.go @@ -4,12 +4,14 @@ // This file contains tests for the buildtag checker. -// +builder // ERROR "possible malformed \+build comment" +// ERRORNEXT "possible malformed [+]build comment" +// +builder // +build !ignore package testdata -// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line$" +// ERRORNEXT "misplaced \+build comment" +// +build toolate var _ = 3 diff --git a/src/cmd/vet/testdata/buildtag/buildtag2.go b/src/cmd/vet/testdata/buildtag/buildtag2.go new file mode 100644 index 0000000000..d8808dd6a2 --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag2.go @@ -0,0 +1,22 @@ +// Copyright 2013 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 buildtag checker. + +// ERRORNEXT "possible malformed [+]build comment" +// +builder +// +build !ignore + +package testdata + +// ERRORNEXT "misplaced \+build comment" +// +build toolate +// ERRORNEXT "misplaced //go:build comment" +//go:build toolate + +var _ = 3 + +var _ = ` +// +build notacomment +` diff --git a/src/cmd/vet/testdata/buildtag/buildtag3.go b/src/cmd/vet/testdata/buildtag/buildtag3.go new file mode 100644 index 0000000000..241a7dbaac --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag3.go @@ -0,0 +1,15 @@ +// Copyright 2020 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 buildtag checker. + +//go:build good +// ERRORNEXT "[+]build lines do not match //go:build condition" +// +build bad + +package testdata + +var _ = ` +// +build notacomment +` diff --git a/src/cmd/vet/testdata/buildtag/buildtag4.go b/src/cmd/vet/testdata/buildtag/buildtag4.go new file mode 100644 index 0000000000..5b40d6951b --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag4.go @@ -0,0 +1,11 @@ +// Copyright 2020 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 buildtag checker. + +//go:build !(bad || worse) +// +build !bad +// +build !worse + +package testdata diff --git a/src/cmd/vet/testdata/buildtag/buildtag5.go b/src/cmd/vet/testdata/buildtag/buildtag5.go new file mode 100644 index 0000000000..12aeb82b9b --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag5.go @@ -0,0 +1,11 @@ +// Copyright 2020 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 buildtag checker. + +//go:build !(bad || worse) + +package testdata + +// +build other // ERROR "misplaced \+build comment" diff --git a/src/cmd/vet/testdata/buildtag/buildtag6.s b/src/cmd/vet/testdata/buildtag/buildtag6.s new file mode 100644 index 0000000000..40fe14c5d6 --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag6.s @@ -0,0 +1,9 @@ +// Copyright 2020 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. + +#include "go_asm.h" + +// ok because we cannot parse assembly files. +// +build no + diff --git a/src/cmd/vet/testdata/buildtag/buildtag7.s b/src/cmd/vet/testdata/buildtag/buildtag7.s new file mode 100644 index 0000000000..b622d48f1b --- /dev/null +++ b/src/cmd/vet/testdata/buildtag/buildtag7.s @@ -0,0 +1,11 @@ +// Copyright 2020 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 + +#include "go_asm.h" + +// ok because we cannot parse assembly files +// the assembler would complain if we did assemble this file. +//go:build no diff --git a/src/cmd/vet/testdata/tagtest/file1.go b/src/cmd/vet/testdata/tagtest/file1.go index 47fe3c80af..2204524821 100644 --- a/src/cmd/vet/testdata/tagtest/file1.go +++ b/src/cmd/vet/testdata/tagtest/file1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build testtag // +build testtag package main diff --git a/src/cmd/vet/testdata/tagtest/file2.go b/src/cmd/vet/testdata/tagtest/file2.go index 1f45efcbf2..979b0d451d 100644 --- a/src/cmd/vet/testdata/tagtest/file2.go +++ b/src/cmd/vet/testdata/tagtest/file2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !testtag // +build !testtag package main diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index d15d1ce377..50dd0735fa 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -334,8 +334,8 @@ type wantedError struct { } var ( - errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`) - errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`) + errRx = regexp.MustCompile(`// (?:GC_)?ERROR(NEXT)? (.*)`) + errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO(NEXT)? (.*)`) errQuotesRx = regexp.MustCompile(`"([^"]*)"`) lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`) ) @@ -364,7 +364,10 @@ func wantedErrors(file, short string) (errs []wantedError) { if m == nil { continue } - all := m[1] + if m[1] == "NEXT" { + lineNum++ + } + all := m[2] mm := errQuotesRx.FindAllStringSubmatch(all, -1) if mm == nil { log.Fatalf("%s:%d: invalid errchk line: %s", file, lineNum, line) -- GitLab From d4b26382342c98a95b85140b2863bc30c48edd68 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Feb 2021 18:35:10 -0500 Subject: [PATCH 0007/1298] all: go fmt std cmd (but revert vendor) Make all our package sources use Go 1.17 gofmt format (adding //go:build lines). Part of //go:build change (#41184). See https://golang.org/design/draft-gobuild Change-Id: Ia0534360e4957e58cd9a18429c39d0e32a6addb4 Reviewed-on: https://go-review.googlesource.com/c/go/+/294430 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Jason A. Donenfeld Reviewed-by: Ian Lance Taylor --- src/archive/tar/stat_actime1.go | 1 + src/archive/tar/stat_actime2.go | 1 + src/archive/tar/stat_unix.go | 1 + src/bytes/boundary_test.go | 1 + src/cmd/api/run.go | 1 + src/cmd/compile/internal/gc/bootstrap.go | 1 + src/cmd/compile/internal/gc/pprof.go | 1 + src/cmd/compile/internal/gc/trace.go | 1 + src/cmd/compile/internal/ir/mknode.go | 1 + src/cmd/compile/internal/logopt/escape.go | 1 + .../internal/logopt/escape_bootstrap.go | 1 + src/cmd/compile/internal/ssa/flags_test.go | 1 + .../internal/typecheck/mapfile_mmap.go | 1 + .../internal/typecheck/mapfile_read.go | 1 + .../compile/internal/typecheck/mkbuiltin.go | 1 + .../compile/internal/types2/example_test.go | 1 + src/cmd/dist/sys_default.go | 1 + src/cmd/dist/test_linux.go | 1 + src/cmd/dist/util_gc.go | 1 + src/cmd/dist/util_gccgo.go | 1 + src/cmd/go/go11.go | 1 + src/cmd/go/go_unix_test.go | 1 + src/cmd/go/internal/base/signal_notunix.go | 1 + src/cmd/go/internal/base/signal_unix.go | 1 + .../internal/filelock/filelock_fcntl.go | 1 + .../internal/filelock/filelock_other.go | 1 + .../internal/filelock/filelock_plan9.go | 1 + .../internal/filelock/filelock_test.go | 1 + .../internal/filelock/filelock_unix.go | 1 + .../internal/filelock/filelock_windows.go | 1 + .../lockedfile/lockedfile_filelock.go | 1 + .../internal/lockedfile/lockedfile_plan9.go | 1 + .../go/internal/lockedfile/lockedfile_test.go | 1 + .../go/internal/lockedfile/transform_test.go | 1 + src/cmd/go/internal/modfetch/bootstrap.go | 1 + .../go/internal/modfetch/codehost/shell.go | 1 + src/cmd/go/internal/modfetch/sumdb.go | 1 + src/cmd/go/internal/modload/stat_openfile.go | 1 + src/cmd/go/internal/modload/stat_unix.go | 1 + src/cmd/go/internal/modload/stat_windows.go | 1 + src/cmd/go/internal/renameio/renameio_test.go | 1 + src/cmd/go/internal/renameio/umask_test.go | 1 + .../go/internal/robustio/robustio_flaky.go | 1 + .../go/internal/robustio/robustio_other.go | 1 + src/cmd/go/internal/test/genflags.go | 1 + src/cmd/go/internal/web/bootstrap.go | 1 + src/cmd/go/internal/web/http.go | 1 + src/cmd/go/internal/web/url_other.go | 1 + src/cmd/go/internal/web/url_other_test.go | 1 + src/cmd/go/internal/work/testgo.go | 1 + src/cmd/internal/bio/buf_mmap.go | 1 + src/cmd/internal/bio/buf_nommap.go | 1 + src/cmd/internal/goobj/mkbuiltin.go | 1 + src/cmd/internal/obj/stringer.go | 1 + src/cmd/link/elf_test.go | 1 + src/cmd/link/internal/ld/elf_test.go | 1 + src/cmd/link/internal/ld/execarchive.go | 1 + .../link/internal/ld/execarchive_noexec.go | 1 + src/cmd/link/internal/ld/fallocate_test.go | 1 + src/cmd/link/internal/ld/outbuf_mmap.go | 1 + .../link/internal/ld/outbuf_nofallocate.go | 1 + src/cmd/link/internal/ld/outbuf_nommap.go | 1 + src/cmd/link/internal/ld/outbuf_notdarwin.go | 1 + src/cmd/nm/nm_cgo_test.go | 1 + src/cmd/pprof/readlineui.go | 1 + src/cmd/trace/annotations_test.go | 1 + src/cmd/trace/trace_test.go | 1 + src/cmd/trace/trace_unix_test.go | 1 + src/crypto/aes/aes_gcm.go | 1 + src/crypto/aes/cipher_asm.go | 1 + src/crypto/aes/cipher_generic.go | 1 + src/crypto/aes/gcm_ppc64le.go | 1 + src/crypto/cipher/xor_generic.go | 1 + src/crypto/cipher/xor_ppc64x.go | 1 + src/crypto/ecdsa/ecdsa_noasm.go | 1 + src/crypto/ecdsa/ecdsa_s390x_test.go | 1 + src/crypto/elliptic/fuzz_test.go | 1 + src/crypto/elliptic/p256.go | 1 + src/crypto/elliptic/p256_asm.go | 1 + src/crypto/elliptic/p256_generic.go | 1 + src/crypto/elliptic/p256_ppc64le.go | 1 + src/crypto/elliptic/p256_s390x.go | 1 + src/crypto/internal/subtle/aliasing.go | 1 + .../internal/subtle/aliasing_appengine.go | 1 + src/crypto/md5/gen.go | 1 + src/crypto/md5/md5block_decl.go | 1 + src/crypto/md5/md5block_generic.go | 1 + src/crypto/rand/eagain.go | 1 + src/crypto/rand/rand_batched.go | 1 + src/crypto/rand/rand_batched_test.go | 1 + src/crypto/rand/rand_js.go | 1 + src/crypto/rand/rand_unix.go | 1 + src/crypto/sha1/fallback_test.go | 1 + src/crypto/sha1/issue15617_test.go | 1 + src/crypto/sha1/sha1block_decl.go | 1 + src/crypto/sha1/sha1block_generic.go | 1 + src/crypto/sha256/fallback_test.go | 1 + src/crypto/sha256/sha256block_decl.go | 1 + src/crypto/sha256/sha256block_generic.go | 1 + src/crypto/sha512/fallback_test.go | 1 + src/crypto/sha512/sha512block_amd64.go | 1 + src/crypto/sha512/sha512block_decl.go | 1 + src/crypto/sha512/sha512block_generic.go | 1 + src/crypto/tls/generate_cert.go | 1 + src/crypto/tls/handshake_unix_test.go | 1 + .../x509/internal/macos/corefoundation.go | 1 + src/crypto/x509/internal/macos/security.go | 1 + src/crypto/x509/root_bsd.go | 1 + src/crypto/x509/root_darwin.go | 1 + src/crypto/x509/root_ios.go | 4 ++-- src/crypto/x509/root_ios_gen.go | 1 + src/crypto/x509/root_js.go | 1 + src/crypto/x509/root_omit.go | 1 + src/crypto/x509/root_omit_test.go | 1 + src/crypto/x509/root_plan9.go | 1 + src/crypto/x509/root_unix.go | 1 + src/crypto/x509/root_unix_test.go | 1 + src/crypto/x509/x509_test_import.go | 1 + src/debug/pe/file_cgo_test.go | 1 + src/encoding/csv/fuzz.go | 1 + src/encoding/gob/debug.go | 1 + src/encoding/gob/decgen.go | 1 + src/encoding/gob/dump.go | 1 + src/encoding/gob/encgen.go | 1 + src/encoding/json/fuzz.go | 1 + src/go/build/gc.go | 1 + src/go/build/gccgo.go | 1 + src/go/doc/headscan.go | 1 + src/go/types/example_test.go | 1 + src/go/types/gotype.go | 1 + src/hash/crc32/crc32_otherarch.go | 1 + src/hash/crc32/gen_const_ppc64le.go | 1 + src/html/fuzz.go | 1 + src/image/color/palette/gen.go | 1 + src/image/internal/imageutil/gen.go | 1 + src/image/png/fuzz.go | 1 + src/index/suffixarray/gen.go | 1 + src/internal/abi/abi_amd64.go | 1 + src/internal/abi/abi_generic.go | 1 + src/internal/bytealg/compare_generic.go | 1 + src/internal/bytealg/compare_native.go | 1 + src/internal/bytealg/count_generic.go | 1 + src/internal/bytealg/count_native.go | 1 + src/internal/bytealg/index_generic.go | 1 + src/internal/bytealg/index_native.go | 1 + src/internal/bytealg/indexbyte_generic.go | 1 + src/internal/bytealg/indexbyte_native.go | 1 + src/internal/cpu/cpu_arm64_android.go | 1 + src/internal/cpu/cpu_arm64_darwin.go | 5 ++--- src/internal/cpu/cpu_arm64_freebsd.go | 1 + src/internal/cpu/cpu_arm64_hwcap.go | 4 ++-- src/internal/cpu/cpu_arm64_linux.go | 5 ++--- src/internal/cpu/cpu_arm64_other.go | 1 + src/internal/cpu/cpu_mips64x.go | 1 + src/internal/cpu/cpu_no_name.go | 4 ++-- src/internal/cpu/cpu_ppc64x.go | 1 + src/internal/cpu/cpu_ppc64x_aix.go | 1 + src/internal/cpu/cpu_ppc64x_linux.go | 1 + src/internal/cpu/cpu_x86.go | 1 + src/internal/cpu/cpu_x86_test.go | 1 + src/internal/goroot/gc.go | 1 + src/internal/goroot/gccgo.go | 1 + src/internal/poll/errno_unix.go | 1 + src/internal/poll/errno_windows.go | 1 + src/internal/poll/error_stub_test.go | 1 + src/internal/poll/export_posix_test.go | 1 + src/internal/poll/fcntl_js.go | 1 + src/internal/poll/fcntl_libc.go | 1 + src/internal/poll/fcntl_syscall.go | 1 + src/internal/poll/fd_fsync_posix.go | 1 + src/internal/poll/fd_poll_js.go | 1 + src/internal/poll/fd_poll_runtime.go | 1 + src/internal/poll/fd_posix.go | 1 + src/internal/poll/fd_posix_test.go | 1 + src/internal/poll/fd_unix.go | 1 + src/internal/poll/fd_writev_darwin.go | 1 + src/internal/poll/fd_writev_illumos.go | 1 + src/internal/poll/fd_writev_unix.go | 1 + src/internal/poll/hook_cloexec.go | 1 + src/internal/poll/hook_unix.go | 1 + src/internal/poll/iovec_illumos.go | 1 + src/internal/poll/iovec_unix.go | 1 + src/internal/poll/sendfile_bsd.go | 1 + src/internal/poll/sock_cloexec.go | 1 + src/internal/poll/sockopt.go | 1 + src/internal/poll/sockopt_unix.go | 1 + src/internal/poll/sockoptip.go | 1 + src/internal/poll/strconv.go | 1 + src/internal/poll/sys_cloexec.go | 1 + src/internal/poll/writev.go | 1 + src/internal/race/norace.go | 1 + src/internal/race/race.go | 1 + .../syscall/execenv/execenv_default.go | 1 + .../syscall/execenv/execenv_windows.go | 1 + src/internal/syscall/unix/at.go | 1 + src/internal/syscall/unix/at_libc.go | 1 + .../syscall/unix/at_sysnum_fstatat64_linux.go | 1 + .../syscall/unix/at_sysnum_fstatat_linux.go | 1 + .../unix/at_sysnum_newfstatat_linux.go | 1 + .../syscall/unix/fcntl_linux_32bit.go | 1 + src/internal/syscall/unix/nonblocking.go | 1 + src/internal/syscall/unix/nonblocking_js.go | 1 + src/internal/syscall/unix/nonblocking_libc.go | 1 + src/internal/syscall/unix/pipe2_illumos.go | 1 + .../syscall/unix/sysnum_linux_generic.go | 1 + .../syscall/unix/sysnum_linux_mips64x.go | 1 + .../syscall/unix/sysnum_linux_mipsx.go | 1 + .../syscall/unix/sysnum_linux_ppc64x.go | 1 + src/internal/syscall/unix/writev_illumos.go | 1 + src/internal/testenv/testenv_cgo.go | 1 + src/internal/testenv/testenv_notwin.go | 1 + src/log/syslog/example_test.go | 1 + src/log/syslog/syslog.go | 1 + src/log/syslog/syslog_test.go | 1 + src/log/syslog/syslog_unix.go | 1 + src/math/big/arith_amd64.go | 1 + src/math/big/arith_decl.go | 1 + src/math/big/arith_decl_pure.go | 1 + src/math/big/arith_decl_s390x.go | 1 + src/math/big/arith_s390x_test.go | 1 + src/math/bits/bits_errors.go | 1 + src/math/bits/bits_errors_bootstrap.go | 1 + src/math/bits/make_examples.go | 1 + src/math/bits/make_tables.go | 1 + src/math/cmplx/huge_test.go | 1 + src/math/exp_asm.go | 1 + src/math/huge_test.go | 1 + src/math/rand/gen_cooked.go | 1 + src/mime/type_unix.go | 1 + src/net/addrselect.go | 1 + src/net/addrselect_test.go | 1 + src/net/cgo_aix.go | 1 + src/net/cgo_android.go | 1 + src/net/cgo_bsd.go | 4 +++- src/net/cgo_linux.go | 1 + src/net/cgo_netbsd.go | 1 + src/net/cgo_openbsd.go | 1 + src/net/cgo_resnew.go | 4 +++- src/net/cgo_resold.go | 4 +++- src/net/cgo_socknew.go | 4 +++- src/net/cgo_sockold.go | 4 +++- src/net/cgo_solaris.go | 1 + src/net/cgo_stub.go | 1 + src/net/cgo_unix.go | 4 +++- src/net/cgo_unix_test.go | 4 +++- src/net/cgo_windows.go | 1 + src/net/conf.go | 1 + src/net/conf_netcgo.go | 1 + src/net/conf_test.go | 1 + src/net/conn_test.go | 1 + src/net/dial_test.go | 1 + src/net/dial_unix_test.go | 1 + src/net/dnsclient_unix.go | 1 + src/net/dnsclient_unix_test.go | 1 + src/net/dnsconfig_unix.go | 1 + src/net/dnsconfig_unix_test.go | 1 + src/net/dnsname_test.go | 1 + src/net/error_posix.go | 1 + src/net/error_posix_test.go | 1 + src/net/error_test.go | 1 + src/net/error_unix.go | 1 + src/net/error_unix_test.go | 1 + src/net/external_test.go | 1 + src/net/fd_posix.go | 1 + src/net/fd_unix.go | 1 + src/net/file_stub.go | 1 + src/net/file_test.go | 1 + src/net/file_unix.go | 1 + src/net/hook_unix.go | 1 + src/net/http/cgi/plan9_test.go | 1 + src/net/http/cgi/posix_test.go | 1 + src/net/http/h2_bundle.go | 1 + src/net/http/omithttp2.go | 1 + src/net/http/roundtrip.go | 1 + src/net/http/roundtrip_js.go | 1 + src/net/http/triv.go | 1 + src/net/interface_bsd.go | 1 + src/net/interface_bsd_test.go | 1 + src/net/interface_bsdvar.go | 1 + src/net/interface_stub.go | 1 + src/net/interface_test.go | 1 + src/net/interface_unix_test.go | 1 + src/net/internal/socktest/main_test.go | 1 + src/net/internal/socktest/main_unix_test.go | 1 + src/net/internal/socktest/switch_posix.go | 1 + src/net/internal/socktest/switch_stub.go | 1 + src/net/internal/socktest/switch_unix.go | 1 + src/net/internal/socktest/sys_cloexec.go | 1 + src/net/internal/socktest/sys_unix.go | 1 + src/net/ip_test.go | 1 + src/net/iprawsock_posix.go | 1 + src/net/iprawsock_test.go | 1 + src/net/ipsock_posix.go | 1 + src/net/listen_test.go | 1 + src/net/lookup_fake.go | 1 + src/net/lookup_test.go | 1 + src/net/lookup_unix.go | 1 + src/net/main_cloexec_test.go | 1 + src/net/main_conf_test.go | 1 + src/net/main_noconf_test.go | 1 + src/net/main_posix_test.go | 1 + src/net/main_test.go | 1 + src/net/main_unix_test.go | 1 + src/net/mockserver_test.go | 1 + src/net/net_fake.go | 1 + src/net/net_test.go | 1 + src/net/netgo_unix_test.go | 1 + src/net/nss.go | 1 + src/net/nss_test.go | 1 + src/net/packetconn_test.go | 1 + src/net/port_unix.go | 1 + src/net/protoconn_test.go | 1 + src/net/rawconn_stub_test.go | 1 + src/net/rawconn_test.go | 1 + src/net/rawconn_unix_test.go | 1 + src/net/sendfile_stub.go | 1 + src/net/sendfile_test.go | 1 + src/net/sendfile_unix_alt.go | 1 + src/net/server_test.go | 1 + src/net/sock_bsd.go | 1 + src/net/sock_cloexec.go | 1 + src/net/sock_posix.go | 1 + src/net/sock_stub.go | 1 + src/net/sockaddr_posix.go | 1 + src/net/sockopt_bsd.go | 1 + src/net/sockopt_posix.go | 1 + src/net/sockopt_stub.go | 1 + src/net/sockoptip_bsdvar.go | 1 + src/net/sockoptip_posix.go | 1 + src/net/sockoptip_stub.go | 1 + src/net/splice_stub.go | 1 + src/net/splice_test.go | 1 + src/net/sys_cloexec.go | 1 + src/net/tcpsock_posix.go | 1 + src/net/tcpsock_test.go | 1 + src/net/tcpsock_unix_test.go | 1 + src/net/tcpsockopt_posix.go | 1 + src/net/tcpsockopt_stub.go | 1 + src/net/tcpsockopt_unix.go | 1 + src/net/timeout_test.go | 1 + src/net/udpsock_posix.go | 1 + src/net/udpsock_test.go | 1 + src/net/unixsock_posix.go | 1 + src/net/unixsock_test.go | 1 + src/net/unixsock_windows_test.go | 1 + src/net/write_unix_test.go | 1 + src/net/writev_test.go | 1 + src/net/writev_unix.go | 1 + src/os/dir_unix.go | 1 + src/os/endian_big.go | 1 + src/os/endian_little.go | 1 + src/os/env_unix_test.go | 1 + src/os/error_errno.go | 1 + src/os/error_posix.go | 1 + src/os/error_unix_test.go | 1 + src/os/error_windows_test.go | 1 + src/os/exec/exec_linux_test.go | 1 + src/os/exec/exec_posix_test.go | 1 + src/os/exec/exec_unix.go | 1 + src/os/exec/lp_js.go | 1 + src/os/exec/lp_unix.go | 1 + src/os/exec/lp_unix_test.go | 1 + src/os/exec/read3.go | 1 + src/os/exec_posix.go | 1 + src/os/exec_unix.go | 1 + src/os/exec_unix_test.go | 1 + src/os/executable_path.go | 1 + src/os/executable_plan9.go | 1 + src/os/executable_procfs.go | 1 + src/os/executable_sysctl.go | 1 + src/os/export_unix_test.go | 1 + src/os/fifo_test.go | 1 + src/os/file_posix.go | 1 + src/os/file_unix.go | 1 + src/os/os_unix_test.go | 1 + src/os/path_unix.go | 1 + src/os/pipe2_bsd.go | 1 + src/os/pipe2_illumos.go | 1 + src/os/pipe_bsd.go | 1 + src/os/pipe_test.go | 1 + src/os/rawconn.go | 1 + src/os/rawconn_test.go | 1 + src/os/readfrom_stub.go | 1 + src/os/removeall_at.go | 1 + src/os/removeall_noat.go | 1 + src/os/signal/example_unix_test.go | 1 + src/os/signal/internal/pty/pty.go | 1 + src/os/signal/signal_cgo_test.go | 1 + src/os/signal/signal_linux_test.go | 1 + src/os/signal/signal_test.go | 1 + src/os/signal/signal_unix.go | 1 + src/os/stat_js.go | 1 + src/os/stat_unix.go | 1 + src/os/sticky_bsd.go | 1 + src/os/sticky_notbsd.go | 1 + src/os/sys_bsd.go | 1 + src/os/sys_js.go | 1 + src/os/sys_unix.go | 1 + src/os/timeout_test.go | 5 ++--- src/os/types_unix.go | 4 ++-- src/os/user/cgo_lookup_unix.go | 4 +++- src/os/user/cgo_unix_test.go | 4 +++- src/os/user/getgrouplist_darwin.go | 1 + src/os/user/getgrouplist_unix.go | 4 +++- src/os/user/listgroups_aix.go | 1 + src/os/user/listgroups_solaris.go | 1 + src/os/user/listgroups_unix.go | 4 +++- src/os/user/lookup_android.go | 1 + src/os/user/lookup_stubs.go | 1 + src/os/user/lookup_unix.go | 1 + src/os/user/lookup_unix_test.go | 1 + src/os/wait_unimp.go | 1 + src/os/wait_wait6.go | 1 + src/os/wait_waitid.go | 1 + src/path/filepath/example_unix_test.go | 1 + src/path/filepath/example_unix_walk_test.go | 1 + src/path/filepath/path_unix.go | 1 + src/path/filepath/symlink_unix.go | 1 + src/plugin/plugin_dlopen.go | 1 + src/plugin/plugin_stubs.go | 1 + src/plugin/plugin_test.go | 1 + src/regexp/exec2_test.go | 1 + src/runtime/auxv_none.go | 8 ++------ src/runtime/cgo/callbacks_traceback.go | 1 + src/runtime/cgo/dragonfly.go | 1 + src/runtime/cgo/freebsd.go | 1 + src/runtime/cgo/linux.go | 1 + src/runtime/cgo/mmap.go | 1 + src/runtime/cgo/netbsd.go | 1 + src/runtime/cgo/openbsd.go | 1 + src/runtime/cgo/setenv.go | 1 + src/runtime/cgo/sigaction.go | 1 + src/runtime/cgo_mmap.go | 1 + src/runtime/cgo_ppc64x.go | 1 + src/runtime/cgo_sigaction.go | 1 + src/runtime/cputicks.go | 9 ++------- src/runtime/crash_cgo_test.go | 1 + src/runtime/crash_nonunix_test.go | 1 + src/runtime/crash_unix_test.go | 1 + src/runtime/debug/panic_test.go | 1 + src/runtime/debug_test.go | 5 ++--- src/runtime/debugcall.go | 1 + src/runtime/debuglog_off.go | 1 + src/runtime/debuglog_on.go | 1 + src/runtime/defs1_linux.go | 1 + src/runtime/defs2_linux.go | 1 + src/runtime/defs3_linux.go | 1 + src/runtime/defs_aix.go | 1 + src/runtime/defs_aix_ppc64.go | 1 + src/runtime/defs_arm_linux.go | 1 + src/runtime/defs_darwin.go | 1 + src/runtime/defs_dragonfly.go | 1 + src/runtime/defs_freebsd.go | 1 + src/runtime/defs_linux.go | 1 + src/runtime/defs_linux_mips64x.go | 1 + src/runtime/defs_linux_mipsx.go | 1 + src/runtime/defs_netbsd.go | 1 + src/runtime/defs_netbsd_386.go | 1 + src/runtime/defs_netbsd_amd64.go | 1 + src/runtime/defs_netbsd_arm.go | 1 + src/runtime/defs_openbsd.go | 1 + src/runtime/defs_solaris.go | 1 + src/runtime/defs_solaris_amd64.go | 1 + src/runtime/env_posix.go | 1 + src/runtime/export_debug_test.go | 4 ++-- src/runtime/export_futex_test.go | 1 + src/runtime/export_mmap_test.go | 1 + src/runtime/export_pipe2_test.go | 1 + src/runtime/export_pipe_test.go | 1 + src/runtime/export_unix_test.go | 1 + src/runtime/futex_test.go | 1 + src/runtime/hash32.go | 1 + src/runtime/hash64.go | 1 + src/runtime/internal/atomic/atomic_386.go | 1 + src/runtime/internal/atomic/atomic_arm.go | 1 + src/runtime/internal/atomic/atomic_arm64.go | 1 + src/runtime/internal/atomic/atomic_mips64x.go | 1 + src/runtime/internal/atomic/atomic_mipsx.go | 1 + src/runtime/internal/atomic/atomic_ppc64x.go | 1 + src/runtime/internal/atomic/stubs.go | 1 + src/runtime/internal/sys/gengoos.go | 1 + src/runtime/internal/sys/intrinsics.go | 1 + src/runtime/internal/sys/intrinsics_stubs.go | 1 + src/runtime/internal/sys/zgoarch_386.go | 1 + src/runtime/internal/sys/zgoarch_amd64.go | 1 + src/runtime/internal/sys/zgoarch_arm.go | 1 + src/runtime/internal/sys/zgoarch_arm64.go | 1 + src/runtime/internal/sys/zgoarch_arm64be.go | 1 + src/runtime/internal/sys/zgoarch_armbe.go | 1 + src/runtime/internal/sys/zgoarch_mips.go | 1 + src/runtime/internal/sys/zgoarch_mips64.go | 1 + src/runtime/internal/sys/zgoarch_mips64le.go | 1 + src/runtime/internal/sys/zgoarch_mips64p32.go | 1 + .../internal/sys/zgoarch_mips64p32le.go | 1 + src/runtime/internal/sys/zgoarch_mipsle.go | 1 + src/runtime/internal/sys/zgoarch_ppc.go | 1 + src/runtime/internal/sys/zgoarch_ppc64.go | 1 + src/runtime/internal/sys/zgoarch_ppc64le.go | 1 + src/runtime/internal/sys/zgoarch_riscv.go | 1 + src/runtime/internal/sys/zgoarch_riscv64.go | 1 + src/runtime/internal/sys/zgoarch_s390.go | 1 + src/runtime/internal/sys/zgoarch_s390x.go | 1 + src/runtime/internal/sys/zgoarch_sparc.go | 1 + src/runtime/internal/sys/zgoarch_sparc64.go | 1 + src/runtime/internal/sys/zgoarch_wasm.go | 1 + src/runtime/internal/sys/zgoos_aix.go | 1 + src/runtime/internal/sys/zgoos_android.go | 1 + src/runtime/internal/sys/zgoos_darwin.go | 4 ++-- src/runtime/internal/sys/zgoos_dragonfly.go | 1 + src/runtime/internal/sys/zgoos_freebsd.go | 1 + src/runtime/internal/sys/zgoos_hurd.go | 1 + src/runtime/internal/sys/zgoos_illumos.go | 1 + src/runtime/internal/sys/zgoos_ios.go | 1 + src/runtime/internal/sys/zgoos_js.go | 1 + src/runtime/internal/sys/zgoos_linux.go | 4 ++-- src/runtime/internal/sys/zgoos_netbsd.go | 1 + src/runtime/internal/sys/zgoos_openbsd.go | 1 + src/runtime/internal/sys/zgoos_plan9.go | 1 + src/runtime/internal/sys/zgoos_solaris.go | 4 ++-- src/runtime/internal/sys/zgoos_windows.go | 1 + src/runtime/internal/sys/zgoos_zos.go | 1 + src/runtime/lfstack_32bit.go | 1 + src/runtime/lfstack_64bit.go | 1 + src/runtime/libfuzzer.go | 1 + src/runtime/lock_futex.go | 1 + src/runtime/lock_js.go | 1 + src/runtime/lock_sema.go | 1 + src/runtime/lockrank_off.go | 1 + src/runtime/lockrank_on.go | 1 + src/runtime/mem_bsd.go | 1 + src/runtime/mem_js.go | 1 + src/runtime/mkduff.go | 1 + src/runtime/mkfastlog2table.go | 1 + src/runtime/mkpreempt.go | 1 + src/runtime/mksizeclasses.go | 1 + src/runtime/mmap.go | 1 + src/runtime/mpagealloc_32bit.go | 1 + src/runtime/mpagealloc_64bit.go | 1 + src/runtime/msan.go | 1 + src/runtime/msan0.go | 1 + src/runtime/nbpipe_fcntl_libc_test.go | 1 + src/runtime/nbpipe_fcntl_unix_test.go | 1 + src/runtime/nbpipe_pipe.go | 1 + src/runtime/nbpipe_pipe2.go | 1 + src/runtime/nbpipe_test.go | 1 + src/runtime/netpoll.go | 1 + src/runtime/netpoll_epoll.go | 1 + src/runtime/netpoll_fake.go | 1 + src/runtime/netpoll_kqueue.go | 1 + src/runtime/netpoll_stub.go | 1 + src/runtime/norace_linux_test.go | 1 + src/runtime/norace_test.go | 1 + src/runtime/os_aix.go | 1 + src/runtime/os_freebsd2.go | 1 + src/runtime/os_freebsd_noauxv.go | 4 ++-- src/runtime/os_js.go | 1 + src/runtime/os_linux_arm64.go | 1 + src/runtime/os_linux_be64.go | 1 + src/runtime/os_linux_generic.go | 9 ++------- src/runtime/os_linux_mips64x.go | 1 + src/runtime/os_linux_mipsx.go | 1 + src/runtime/os_linux_noauxv.go | 4 ++-- src/runtime/os_linux_novdso.go | 4 ++-- src/runtime/os_linux_ppc64x.go | 1 + src/runtime/os_linux_x86.go | 1 + src/runtime/os_nonopenbsd.go | 1 + src/runtime/os_only_solaris.go | 1 + src/runtime/os_openbsd_libc.go | 1 + src/runtime/os_openbsd_syscall.go | 4 ++-- src/runtime/os_openbsd_syscall1.go | 1 + src/runtime/os_openbsd_syscall2.go | 1 + src/runtime/panic32.go | 1 + src/runtime/pprof/mprof_test.go | 19 ++++++++++--------- src/runtime/pprof/pprof_norusage.go | 1 + src/runtime/pprof/pprof_rusage.go | 1 + src/runtime/pprof/pprof_test.go | 1 + src/runtime/preempt_nonwindows.go | 1 + src/runtime/race.go | 1 + src/runtime/race/output_test.go | 1 + src/runtime/race/race.go | 1 + src/runtime/race/race_linux_test.go | 1 + src/runtime/race/race_test.go | 1 + src/runtime/race/race_unix_test.go | 1 + src/runtime/race/race_windows_test.go | 1 + src/runtime/race/sched_test.go | 1 + src/runtime/race/syso_test.go | 1 + src/runtime/race/timer_test.go | 1 + src/runtime/race0.go | 1 + src/runtime/relax_stub.go | 1 + src/runtime/runtime_mmap_test.go | 1 + src/runtime/runtime_unix_test.go | 1 + src/runtime/semasleep_test.go | 1 + src/runtime/sigaction.go | 1 + src/runtime/signal_386.go | 1 + src/runtime/signal_aix_ppc64.go | 1 + src/runtime/signal_amd64.go | 1 + src/runtime/signal_arm.go | 1 + src/runtime/signal_arm64.go | 1 + src/runtime/signal_linux_mips64x.go | 1 + src/runtime/signal_linux_mipsx.go | 1 + src/runtime/signal_linux_ppc64x.go | 1 + src/runtime/signal_mips64x.go | 1 + src/runtime/signal_mipsx.go | 1 + src/runtime/signal_ppc64x.go | 1 + src/runtime/signal_riscv64.go | 1 + src/runtime/signal_unix.go | 1 + src/runtime/signal_windows_test.go | 1 + src/runtime/sigqueue.go | 1 + src/runtime/sigqueue_note.go | 4 ++-- src/runtime/sigtab_linux_generic.go | 7 ++----- src/runtime/sigtab_linux_mipsx.go | 1 + src/runtime/stubs2.go | 9 ++------- src/runtime/stubs3.go | 8 ++------ src/runtime/stubs_linux.go | 1 + src/runtime/stubs_mips64x.go | 1 + src/runtime/stubs_mipsx.go | 1 + src/runtime/stubs_nonlinux.go | 1 + src/runtime/stubs_ppc64x.go | 1 + src/runtime/sys_libc.go | 1 + src/runtime/sys_mips64x.go | 1 + src/runtime/sys_mipsx.go | 1 + src/runtime/sys_nonppc64x.go | 1 + src/runtime/sys_openbsd.go | 1 + src/runtime/sys_openbsd1.go | 1 + src/runtime/sys_openbsd2.go | 1 + src/runtime/sys_openbsd3.go | 1 + src/runtime/sys_ppc64x.go | 1 + src/runtime/sys_x86.go | 1 + src/runtime/time_fake.go | 4 ++-- src/runtime/time_nofake.go | 1 + src/runtime/timeasm.go | 1 + src/runtime/timestub.go | 1 + src/runtime/timestub2.go | 8 ++------ src/runtime/vdso_elf32.go | 1 + src/runtime/vdso_elf64.go | 1 + src/runtime/vdso_freebsd.go | 1 + src/runtime/vdso_freebsd_x86.go | 1 + src/runtime/vdso_in_none.go | 1 + src/runtime/vdso_linux.go | 1 + src/runtime/vdso_linux_mips64x.go | 1 + src/runtime/vdso_linux_ppc64x.go | 1 + src/runtime/vlrt.go | 1 + src/runtime/wincallback.go | 1 + src/runtime/write_err.go | 1 + src/sort/genzfunc.go | 1 + src/sort/slice_go113.go | 1 + src/sort/slice_go14.go | 1 + src/sort/slice_go18.go | 1 + src/strconv/bytealg.go | 1 + src/strconv/bytealg_bootstrap.go | 1 + src/strconv/makeisprint.go | 1 + src/sync/pool_test.go | 1 + src/sync/runtime2.go | 1 + src/sync/runtime2_lockrank.go | 1 + src/syscall/bpf_bsd.go | 1 + src/syscall/creds_test.go | 1 + src/syscall/dirent.go | 1 + src/syscall/dirent_test.go | 1 + src/syscall/endian_big.go | 1 + src/syscall/endian_little.go | 1 + src/syscall/env_unix.go | 1 + src/syscall/exec_aix_test.go | 1 + src/syscall/exec_bsd.go | 1 + src/syscall/exec_libc.go | 1 + src/syscall/exec_libc2.go | 1 + src/syscall/exec_linux.go | 1 + src/syscall/exec_linux_test.go | 1 + src/syscall/exec_solaris_test.go | 1 + src/syscall/exec_unix.go | 1 + src/syscall/exec_unix_test.go | 1 + src/syscall/export_unix_test.go | 1 + src/syscall/flock.go | 1 + src/syscall/flock_linux_32bit.go | 1 + src/syscall/forkpipe.go | 1 + src/syscall/forkpipe2.go | 1 + src/syscall/fs_js.go | 1 + src/syscall/getdirentries_test.go | 1 + src/syscall/mkasm.go | 1 + src/syscall/mkpost.go | 1 + src/syscall/mksyscall_windows.go | 1 + src/syscall/mmap_unix_test.go | 1 + src/syscall/msan.go | 1 + src/syscall/msan0.go | 1 + src/syscall/net_js.go | 1 + src/syscall/ptrace_darwin.go | 1 + src/syscall/route_bsd.go | 1 + src/syscall/route_freebsd_32bit.go | 1 + src/syscall/route_freebsd_64bit.go | 1 + src/syscall/setuidgid_32_linux.go | 1 + src/syscall/setuidgid_linux.go | 4 ++-- src/syscall/sockcmsg_unix.go | 1 + src/syscall/sockcmsg_unix_other.go | 1 + src/syscall/syscall_bsd.go | 1 + src/syscall/syscall_bsd_test.go | 1 + src/syscall/syscall_dup2_linux.go | 1 + src/syscall/syscall_dup3_linux.go | 1 + src/syscall/syscall_freebsd_test.go | 1 + src/syscall/syscall_illumos.go | 1 + src/syscall/syscall_js.go | 1 + src/syscall/syscall_linux_mips64x.go | 1 + src/syscall/syscall_linux_mipsx.go | 1 + src/syscall/syscall_linux_ppc64x.go | 1 + src/syscall/syscall_openbsd1.go | 1 + src/syscall/syscall_openbsd_libc.go | 1 + src/syscall/syscall_ptrace_test.go | 1 + src/syscall/syscall_unix.go | 1 + src/syscall/syscall_unix_test.go | 1 + src/syscall/tables_js.go | 1 + src/syscall/time_fake.go | 1 + src/syscall/time_nofake.go | 1 + src/syscall/timestruct.go | 1 + src/syscall/types_aix.go | 1 + src/syscall/types_darwin.go | 1 + src/syscall/types_dragonfly.go | 1 + src/syscall/types_freebsd.go | 1 + src/syscall/types_illumos_amd64.go | 1 + src/syscall/types_linux.go | 1 + src/syscall/types_netbsd.go | 1 + src/syscall/types_openbsd.go | 1 + src/syscall/types_solaris.go | 1 + src/syscall/zerrors_darwin_amd64.go | 1 + src/syscall/zerrors_darwin_arm64.go | 1 + src/syscall/zerrors_dragonfly_amd64.go | 1 + src/syscall/zerrors_freebsd_386.go | 1 + src/syscall/zerrors_freebsd_amd64.go | 1 + src/syscall/zerrors_freebsd_arm.go | 1 + src/syscall/zerrors_freebsd_arm64.go | 1 + src/syscall/zerrors_linux_386.go | 1 + src/syscall/zerrors_linux_amd64.go | 1 + src/syscall/zerrors_linux_arm.go | 1 + src/syscall/zerrors_linux_arm64.go | 1 + src/syscall/zerrors_linux_ppc64.go | 1 + src/syscall/zerrors_linux_ppc64le.go | 1 + src/syscall/zerrors_netbsd_386.go | 1 + src/syscall/zerrors_netbsd_amd64.go | 1 + src/syscall/zerrors_netbsd_arm.go | 1 + src/syscall/zerrors_netbsd_arm64.go | 1 + src/syscall/zerrors_openbsd_386.go | 1 + src/syscall/zerrors_openbsd_amd64.go | 1 + src/syscall/zerrors_openbsd_arm.go | 1 + src/syscall/zerrors_solaris_amd64.go | 1 + src/syscall/zsyscall_aix_ppc64.go | 1 + src/syscall/zsyscall_darwin_amd64.go | 1 + src/syscall/zsyscall_darwin_arm64.go | 1 + src/syscall/zsyscall_dragonfly_amd64.go | 1 + src/syscall/zsyscall_freebsd_386.go | 1 + src/syscall/zsyscall_freebsd_amd64.go | 1 + src/syscall/zsyscall_freebsd_arm.go | 1 + src/syscall/zsyscall_freebsd_arm64.go | 1 + src/syscall/zsyscall_linux_386.go | 1 + src/syscall/zsyscall_linux_amd64.go | 1 + src/syscall/zsyscall_linux_arm.go | 1 + src/syscall/zsyscall_linux_arm64.go | 1 + src/syscall/zsyscall_linux_mips.go | 1 + src/syscall/zsyscall_linux_mips64.go | 1 + src/syscall/zsyscall_linux_mips64le.go | 1 + src/syscall/zsyscall_linux_mipsle.go | 1 + src/syscall/zsyscall_linux_ppc64.go | 1 + src/syscall/zsyscall_linux_ppc64le.go | 1 + src/syscall/zsyscall_linux_riscv64.go | 1 + src/syscall/zsyscall_linux_s390x.go | 1 + src/syscall/zsyscall_netbsd_386.go | 1 + src/syscall/zsyscall_netbsd_amd64.go | 1 + src/syscall/zsyscall_netbsd_arm.go | 1 + src/syscall/zsyscall_netbsd_arm64.go | 1 + src/syscall/zsyscall_openbsd_386.go | 1 + src/syscall/zsyscall_openbsd_amd64.go | 1 + src/syscall/zsyscall_openbsd_arm.go | 1 + src/syscall/zsyscall_openbsd_arm64.go | 1 + src/syscall/zsyscall_openbsd_mips64.go | 1 + src/syscall/zsyscall_plan9_386.go | 1 + src/syscall/zsyscall_plan9_amd64.go | 1 + src/syscall/zsyscall_plan9_arm.go | 1 + src/syscall/zsyscall_solaris_amd64.go | 1 + src/syscall/zsysnum_darwin_amd64.go | 1 + src/syscall/zsysnum_darwin_arm64.go | 1 + src/syscall/zsysnum_dragonfly_amd64.go | 1 + src/syscall/zsysnum_freebsd_386.go | 1 + src/syscall/zsysnum_freebsd_amd64.go | 1 + src/syscall/zsysnum_freebsd_arm.go | 1 + src/syscall/zsysnum_freebsd_arm64.go | 1 + src/syscall/zsysnum_linux_386.go | 1 + src/syscall/zsysnum_linux_amd64.go | 1 + src/syscall/zsysnum_linux_arm.go | 1 + src/syscall/zsysnum_linux_arm64.go | 1 + src/syscall/zsysnum_linux_ppc64.go | 1 + src/syscall/zsysnum_linux_ppc64le.go | 1 + src/syscall/zsysnum_netbsd_386.go | 1 + src/syscall/zsysnum_netbsd_amd64.go | 1 + src/syscall/zsysnum_netbsd_arm.go | 1 + src/syscall/zsysnum_netbsd_arm64.go | 1 + src/syscall/zsysnum_openbsd_386.go | 1 + src/syscall/zsysnum_openbsd_amd64.go | 1 + src/syscall/zsysnum_openbsd_arm.go | 1 + src/syscall/zsysnum_solaris_amd64.go | 1 + src/syscall/ztypes_darwin_amd64.go | 1 + src/syscall/ztypes_darwin_arm64.go | 1 + src/syscall/ztypes_dragonfly_amd64.go | 1 + src/syscall/ztypes_freebsd_386.go | 1 + src/syscall/ztypes_freebsd_amd64.go | 1 + src/syscall/ztypes_freebsd_arm.go | 1 + src/syscall/ztypes_freebsd_arm64.go | 1 + src/syscall/ztypes_linux_386.go | 1 + src/syscall/ztypes_linux_amd64.go | 1 + src/syscall/ztypes_linux_arm.go | 1 + src/syscall/ztypes_linux_arm64.go | 1 + src/syscall/ztypes_linux_ppc64.go | 1 + src/syscall/ztypes_linux_ppc64le.go | 1 + src/syscall/ztypes_netbsd_386.go | 1 + src/syscall/ztypes_netbsd_amd64.go | 1 + src/syscall/ztypes_netbsd_arm.go | 1 + src/syscall/ztypes_netbsd_arm64.go | 1 + src/syscall/ztypes_openbsd_386.go | 1 + src/syscall/ztypes_openbsd_amd64.go | 1 + src/syscall/ztypes_solaris_amd64.go | 1 + src/testing/run_example.go | 1 + src/testing/run_example_js.go | 1 + src/time/embed.go | 1 + src/time/genzabbrs.go | 1 + src/time/sys_plan9.go | 1 + src/time/sys_unix.go | 1 + src/time/tzdata/generate_zipdata.go | 1 + src/time/zoneinfo_ios.go | 1 + src/time/zoneinfo_js.go | 1 + src/time/zoneinfo_unix.go | 1 + src/time/zoneinfo_unix_test.go | 1 + 826 files changed, 883 insertions(+), 106 deletions(-) diff --git a/src/archive/tar/stat_actime1.go b/src/archive/tar/stat_actime1.go index 1bdd1c9dcb..4fdf2a04b3 100644 --- a/src/archive/tar/stat_actime1.go +++ b/src/archive/tar/stat_actime1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || linux || dragonfly || openbsd || solaris // +build aix linux dragonfly openbsd solaris package tar diff --git a/src/archive/tar/stat_actime2.go b/src/archive/tar/stat_actime2.go index 6f17dbe307..5a9a35cbb4 100644 --- a/src/archive/tar/stat_actime2.go +++ b/src/archive/tar/stat_actime2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || freebsd || netbsd // +build darwin freebsd netbsd package tar diff --git a/src/archive/tar/stat_unix.go b/src/archive/tar/stat_unix.go index 581d87dca9..3957349d6e 100644 --- a/src/archive/tar/stat_unix.go +++ b/src/archive/tar/stat_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris // +build aix linux darwin dragonfly freebsd openbsd netbsd solaris package tar diff --git a/src/bytes/boundary_test.go b/src/bytes/boundary_test.go index ea84f1e40f..5a47526593 100644 --- a/src/bytes/boundary_test.go +++ b/src/bytes/boundary_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +//go:build linux // +build linux package bytes_test diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index ecb1d0f81a..8c9fb723a5 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // The run program is invoked via the dist tool. diff --git a/src/cmd/compile/internal/gc/bootstrap.go b/src/cmd/compile/internal/gc/bootstrap.go index 2e13d6b57a..37b0d59ede 100644 --- a/src/cmd/compile/internal/gc/bootstrap.go +++ b/src/cmd/compile/internal/gc/bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.8 // +build !go1.8 package gc diff --git a/src/cmd/compile/internal/gc/pprof.go b/src/cmd/compile/internal/gc/pprof.go index 256c659259..5f9b030621 100644 --- a/src/cmd/compile/internal/gc/pprof.go +++ b/src/cmd/compile/internal/gc/pprof.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.8 // +build go1.8 package gc diff --git a/src/cmd/compile/internal/gc/trace.go b/src/cmd/compile/internal/gc/trace.go index c6eb23a090..8cdbd4b0f3 100644 --- a/src/cmd/compile/internal/gc/trace.go +++ b/src/cmd/compile/internal/gc/trace.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.7 // +build go1.7 package gc diff --git a/src/cmd/compile/internal/ir/mknode.go b/src/cmd/compile/internal/ir/mknode.go index 326f491a69..5a0aaadf16 100644 --- a/src/cmd/compile/internal/ir/mknode.go +++ b/src/cmd/compile/internal/ir/mknode.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/compile/internal/logopt/escape.go b/src/cmd/compile/internal/logopt/escape.go index 802f967aa6..9660e938b4 100644 --- a/src/cmd/compile/internal/logopt/escape.go +++ b/src/cmd/compile/internal/logopt/escape.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.8 // +build go1.8 package logopt diff --git a/src/cmd/compile/internal/logopt/escape_bootstrap.go b/src/cmd/compile/internal/logopt/escape_bootstrap.go index 66ff0b8f22..cc04eaadfd 100644 --- a/src/cmd/compile/internal/logopt/escape_bootstrap.go +++ b/src/cmd/compile/internal/logopt/escape_bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.8 // +build !go1.8 package logopt diff --git a/src/cmd/compile/internal/ssa/flags_test.go b/src/cmd/compile/internal/ssa/flags_test.go index d64abf652c..0bc1097199 100644 --- a/src/cmd/compile/internal/ssa/flags_test.go +++ b/src/cmd/compile/internal/ssa/flags_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 // +build amd64 arm64 package ssa diff --git a/src/cmd/compile/internal/typecheck/mapfile_mmap.go b/src/cmd/compile/internal/typecheck/mapfile_mmap.go index 2f3aa16dec..298b385bcb 100644 --- a/src/cmd/compile/internal/typecheck/mapfile_mmap.go +++ b/src/cmd/compile/internal/typecheck/mapfile_mmap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package typecheck diff --git a/src/cmd/compile/internal/typecheck/mapfile_read.go b/src/cmd/compile/internal/typecheck/mapfile_read.go index 4059f261d4..9637ab97ab 100644 --- a/src/cmd/compile/internal/typecheck/mapfile_read.go +++ b/src/cmd/compile/internal/typecheck/mapfile_read.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd package typecheck diff --git a/src/cmd/compile/internal/typecheck/mkbuiltin.go b/src/cmd/compile/internal/typecheck/mkbuiltin.go index bef510a578..6dbd1869b3 100644 --- a/src/cmd/compile/internal/typecheck/mkbuiltin.go +++ b/src/cmd/compile/internal/typecheck/mkbuiltin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate builtin.go from builtin/runtime.go. diff --git a/src/cmd/compile/internal/types2/example_test.go b/src/cmd/compile/internal/types2/example_test.go index ffd54fe459..974acb82ef 100644 --- a/src/cmd/compile/internal/types2/example_test.go +++ b/src/cmd/compile/internal/types2/example_test.go @@ -6,6 +6,7 @@ // Only run where builders (build.golang.org) have // access to compiled packages for import. // +//go:build !arm && !arm64 // +build !arm,!arm64 package types2_test diff --git a/src/cmd/dist/sys_default.go b/src/cmd/dist/sys_default.go index 821dc273d6..e87c84ce3e 100644 --- a/src/cmd/dist/sys_default.go +++ b/src/cmd/dist/sys_default.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package main diff --git a/src/cmd/dist/test_linux.go b/src/cmd/dist/test_linux.go index b6d0aedbbf..43d28dc661 100644 --- a/src/cmd/dist/test_linux.go +++ b/src/cmd/dist/test_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package main diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go index 17a0e6fbb5..2db6d3a25e 100644 --- a/src/cmd/dist/util_gc.go +++ b/src/cmd/dist/util_gc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !gccgo // +build !gccgo package main diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go index dc897236fb..3255b80365 100644 --- a/src/cmd/dist/util_gccgo.go +++ b/src/cmd/dist/util_gccgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gccgo // +build gccgo package main diff --git a/src/cmd/go/go11.go b/src/cmd/go/go11.go index 7e383f4b5b..a1f2727825 100644 --- a/src/cmd/go/go11.go +++ b/src/cmd/go/go11.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.1 // +build go1.1 package main diff --git a/src/cmd/go/go_unix_test.go b/src/cmd/go/go_unix_test.go index f6e10ca59c..7d5ff9bbb7 100644 --- a/src/cmd/go/go_unix_test.go +++ b/src/cmd/go/go_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package main_test diff --git a/src/cmd/go/internal/base/signal_notunix.go b/src/cmd/go/internal/base/signal_notunix.go index 9e869b03ea..5cc0b0f101 100644 --- a/src/cmd/go/internal/base/signal_notunix.go +++ b/src/cmd/go/internal/base/signal_notunix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 || windows // +build plan9 windows package base diff --git a/src/cmd/go/internal/base/signal_unix.go b/src/cmd/go/internal/base/signal_unix.go index 342775a118..cdc2658372 100644 --- a/src/cmd/go/internal/base/signal_unix.go +++ b/src/cmd/go/internal/base/signal_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || js || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris package base diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go index 1fa4327a89..a37b2ad6d1 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || (solaris && !illumos) // +build aix solaris,!illumos // This code implements the filelock API using POSIX 'fcntl' locks, which attach diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go index bc480343fc..70f5d7a688 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !plan9 && !solaris && !windows // +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows package filelock diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go index 0798ee469a..908afb6c8c 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package filelock diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go index 2ac2052b8f..640d4406f4 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 // +build !js,!plan9 package filelock_test diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go index ed07bac608..878a1e770d 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build darwin dragonfly freebsd illumos linux netbsd openbsd package filelock diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go index 19de27eb9b..dd27ce92bd 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package filelock diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go index efc66461ed..729df5c681 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package lockedfile diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go index 70d6eddf2d..3d4b97d78e 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package lockedfile diff --git a/src/cmd/go/internal/lockedfile/lockedfile_test.go b/src/cmd/go/internal/lockedfile/lockedfile_test.go index 34327dd841..3acc6695a7 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_test.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // js does not support inter-process file locking. +//go:build !js // +build !js package lockedfile_test diff --git a/src/cmd/go/internal/lockedfile/transform_test.go b/src/cmd/go/internal/lockedfile/transform_test.go index 407d48ea4a..b753346e7d 100644 --- a/src/cmd/go/internal/lockedfile/transform_test.go +++ b/src/cmd/go/internal/lockedfile/transform_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // js does not support inter-process file locking. +//go:build !js // +build !js package lockedfile_test diff --git a/src/cmd/go/internal/modfetch/bootstrap.go b/src/cmd/go/internal/modfetch/bootstrap.go index e4020b0b41..ed694581a7 100644 --- a/src/cmd/go/internal/modfetch/bootstrap.go +++ b/src/cmd/go/internal/modfetch/bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cmd_go_bootstrap // +build cmd_go_bootstrap package modfetch diff --git a/src/cmd/go/internal/modfetch/codehost/shell.go b/src/cmd/go/internal/modfetch/codehost/shell.go index ce8b501d53..0e9f381966 100644 --- a/src/cmd/go/internal/modfetch/codehost/shell.go +++ b/src/cmd/go/internal/modfetch/codehost/shell.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Interactive debugging shell for codehost.Repo implementations. diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index 4fbc54d15c..fbe2bda2e5 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -4,6 +4,7 @@ // Go checksum database lookup +//go:build !cmd_go_bootstrap // +build !cmd_go_bootstrap package modfetch diff --git a/src/cmd/go/internal/modload/stat_openfile.go b/src/cmd/go/internal/modload/stat_openfile.go index 5842b858f0..368f893198 100644 --- a/src/cmd/go/internal/modload/stat_openfile.go +++ b/src/cmd/go/internal/modload/stat_openfile.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (js && wasm) || plan9 // +build js,wasm plan9 // On plan9, per http://9p.io/magic/man2html/2/access: “Since file permissions diff --git a/src/cmd/go/internal/modload/stat_unix.go b/src/cmd/go/internal/modload/stat_unix.go index f49278ec3a..e079d73990 100644 --- a/src/cmd/go/internal/modload/stat_unix.go +++ b/src/cmd/go/internal/modload/stat_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package modload diff --git a/src/cmd/go/internal/modload/stat_windows.go b/src/cmd/go/internal/modload/stat_windows.go index 0ac2391347..825e60b27a 100644 --- a/src/cmd/go/internal/modload/stat_windows.go +++ b/src/cmd/go/internal/modload/stat_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package modload diff --git a/src/cmd/go/internal/renameio/renameio_test.go b/src/cmd/go/internal/renameio/renameio_test.go index 5b2ed83624..dc3c1415db 100644 --- a/src/cmd/go/internal/renameio/renameio_test.go +++ b/src/cmd/go/internal/renameio/renameio_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package renameio diff --git a/src/cmd/go/internal/renameio/umask_test.go b/src/cmd/go/internal/renameio/umask_test.go index 65e4fa587b..bed45af6ed 100644 --- a/src/cmd/go/internal/renameio/umask_test.go +++ b/src/cmd/go/internal/renameio/umask_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 && !windows && !js // +build !plan9,!windows,!js package renameio diff --git a/src/cmd/go/internal/robustio/robustio_flaky.go b/src/cmd/go/internal/robustio/robustio_flaky.go index 5bd44bd345..d5c241857b 100644 --- a/src/cmd/go/internal/robustio/robustio_flaky.go +++ b/src/cmd/go/internal/robustio/robustio_flaky.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows || darwin // +build windows darwin package robustio diff --git a/src/cmd/go/internal/robustio/robustio_other.go b/src/cmd/go/internal/robustio/robustio_other.go index 6fe7b7e4e4..3a20cac6cf 100644 --- a/src/cmd/go/internal/robustio/robustio_other.go +++ b/src/cmd/go/internal/robustio/robustio_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !darwin // +build !windows,!darwin package robustio diff --git a/src/cmd/go/internal/test/genflags.go b/src/cmd/go/internal/test/genflags.go index 30334b0f30..9277de7fee 100644 --- a/src/cmd/go/internal/test/genflags.go +++ b/src/cmd/go/internal/test/genflags.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/cmd/go/internal/web/bootstrap.go b/src/cmd/go/internal/web/bootstrap.go index 781702100a..08686cdfcf 100644 --- a/src/cmd/go/internal/web/bootstrap.go +++ b/src/cmd/go/internal/web/bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cmd_go_bootstrap // +build cmd_go_bootstrap // This code is compiled only into the bootstrap 'go' binary. diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go index 72fa2b2ca6..a77e0f9317 100644 --- a/src/cmd/go/internal/web/http.go +++ b/src/cmd/go/internal/web/http.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !cmd_go_bootstrap // +build !cmd_go_bootstrap // This code is compiled into the real 'go' binary, but it is not diff --git a/src/cmd/go/internal/web/url_other.go b/src/cmd/go/internal/web/url_other.go index 2641ee62bf..453af402b4 100644 --- a/src/cmd/go/internal/web/url_other.go +++ b/src/cmd/go/internal/web/url_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package web diff --git a/src/cmd/go/internal/web/url_other_test.go b/src/cmd/go/internal/web/url_other_test.go index aa5663355e..4d6ed2ec7f 100644 --- a/src/cmd/go/internal/web/url_other_test.go +++ b/src/cmd/go/internal/web/url_other_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package web diff --git a/src/cmd/go/internal/work/testgo.go b/src/cmd/go/internal/work/testgo.go index 931f49a069..8b77871b23 100644 --- a/src/cmd/go/internal/work/testgo.go +++ b/src/cmd/go/internal/work/testgo.go @@ -4,6 +4,7 @@ // This file contains extra hooks for testing the go command. +//go:build testgo // +build testgo package work diff --git a/src/cmd/internal/bio/buf_mmap.go b/src/cmd/internal/bio/buf_mmap.go index 4b43d74f26..b9755c7e50 100644 --- a/src/cmd/internal/bio/buf_mmap.go +++ b/src/cmd/internal/bio/buf_mmap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package bio diff --git a/src/cmd/internal/bio/buf_nommap.go b/src/cmd/internal/bio/buf_nommap.go index f43c67ac2d..533a93180c 100644 --- a/src/cmd/internal/bio/buf_nommap.go +++ b/src/cmd/internal/bio/buf_nommap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd package bio diff --git a/src/cmd/internal/goobj/mkbuiltin.go b/src/cmd/internal/goobj/mkbuiltin.go index 22608e7e69..4e46970648 100644 --- a/src/cmd/internal/goobj/mkbuiltin.go +++ b/src/cmd/internal/goobj/mkbuiltin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate builtinlist.go from cmd/compile/internal/gc/builtin/runtime.go. diff --git a/src/cmd/internal/obj/stringer.go b/src/cmd/internal/obj/stringer.go index f67b89091c..a4d507d49a 100644 --- a/src/cmd/internal/obj/stringer.go +++ b/src/cmd/internal/obj/stringer.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This is a mini version of the stringer tool customized for the Anames table diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index 20754d09f5..b4441297e6 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package main diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index 776fc1b4f9..70e743fa65 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -1,3 +1,4 @@ +//go:build cgo // +build cgo // Copyright 2019 The Go Authors. All rights reserved. diff --git a/src/cmd/link/internal/ld/execarchive.go b/src/cmd/link/internal/ld/execarchive.go index 4687c624de..918b86cdc5 100644 --- a/src/cmd/link/internal/ld/execarchive.go +++ b/src/cmd/link/internal/ld/execarchive.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !wasm && !windows // +build !wasm,!windows package ld diff --git a/src/cmd/link/internal/ld/execarchive_noexec.go b/src/cmd/link/internal/ld/execarchive_noexec.go index a70dea9fda..5e1f2669d3 100644 --- a/src/cmd/link/internal/ld/execarchive_noexec.go +++ b/src/cmd/link/internal/ld/execarchive_noexec.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build wasm || windows // +build wasm windows package ld diff --git a/src/cmd/link/internal/ld/fallocate_test.go b/src/cmd/link/internal/ld/fallocate_test.go index 244b70f061..56d2321826 100644 --- a/src/cmd/link/internal/ld/fallocate_test.go +++ b/src/cmd/link/internal/ld/fallocate_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || linux // +build darwin linux package ld diff --git a/src/cmd/link/internal/ld/outbuf_mmap.go b/src/cmd/link/internal/ld/outbuf_mmap.go index 807fe24375..40a3222788 100644 --- a/src/cmd/link/internal/ld/outbuf_mmap.go +++ b/src/cmd/link/internal/ld/outbuf_mmap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build aix darwin dragonfly freebsd linux netbsd openbsd package ld diff --git a/src/cmd/link/internal/ld/outbuf_nofallocate.go b/src/cmd/link/internal/ld/outbuf_nofallocate.go index 6bf96bcb2b..6564bd54a3 100644 --- a/src/cmd/link/internal/ld/outbuf_nofallocate.go +++ b/src/cmd/link/internal/ld/outbuf_nofallocate.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin && !linux // +build !darwin,!linux package ld diff --git a/src/cmd/link/internal/ld/outbuf_nommap.go b/src/cmd/link/internal/ld/outbuf_nommap.go index 6b4025384b..c870fa2c18 100644 --- a/src/cmd/link/internal/ld/outbuf_nommap.go +++ b/src/cmd/link/internal/ld/outbuf_nommap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !windows // +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!windows package ld diff --git a/src/cmd/link/internal/ld/outbuf_notdarwin.go b/src/cmd/link/internal/ld/outbuf_notdarwin.go index 8c5666f216..f9caa413e3 100644 --- a/src/cmd/link/internal/ld/outbuf_notdarwin.go +++ b/src/cmd/link/internal/ld/outbuf_notdarwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin // +build !darwin package ld diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go index e0414e6b22..536e87e4ae 100644 --- a/src/cmd/nm/nm_cgo_test.go +++ b/src/cmd/nm/nm_cgo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo // +build cgo package main diff --git a/src/cmd/pprof/readlineui.go b/src/cmd/pprof/readlineui.go index 0c9fafdad7..dbbb9c2787 100644 --- a/src/cmd/pprof/readlineui.go +++ b/src/cmd/pprof/readlineui.go @@ -5,6 +5,7 @@ // This file contains a driver.UI implementation // that provides the readline functionality if possible. +//go:build (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows) && !appengine && !android // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows // +build !appengine // +build !android diff --git a/src/cmd/trace/annotations_test.go b/src/cmd/trace/annotations_test.go index 9c2d027366..acd5693c7d 100644 --- a/src/cmd/trace/annotations_test.go +++ b/src/cmd/trace/annotations_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package main diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go index ea0cc6f880..2b1a68d7f3 100644 --- a/src/cmd/trace/trace_test.go +++ b/src/cmd/trace/trace_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package main diff --git a/src/cmd/trace/trace_unix_test.go b/src/cmd/trace/trace_unix_test.go index c569b40bb2..8dc56a8c7b 100644 --- a/src/cmd/trace/trace_unix_test.go +++ b/src/cmd/trace/trace_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package main diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go index 49b78c3a8b..1de0e457a2 100644 --- a/src/crypto/aes/aes_gcm.go +++ b/src/crypto/aes/aes_gcm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 // +build amd64 arm64 package aes diff --git a/src/crypto/aes/cipher_asm.go b/src/crypto/aes/cipher_asm.go index 646bdfa5c0..4251805ef9 100644 --- a/src/crypto/aes/cipher_asm.go +++ b/src/crypto/aes/cipher_asm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 // +build amd64 arm64 package aes diff --git a/src/crypto/aes/cipher_generic.go b/src/crypto/aes/cipher_generic.go index 80a68b4ef0..22ce3be7f3 100644 --- a/src/crypto/aes/cipher_generic.go +++ b/src/crypto/aes/cipher_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !s390x && !ppc64le && !arm64 // +build !amd64,!s390x,!ppc64le,!arm64 package aes diff --git a/src/crypto/aes/gcm_ppc64le.go b/src/crypto/aes/gcm_ppc64le.go index 084edddc4d..01b4e08757 100644 --- a/src/crypto/aes/gcm_ppc64le.go +++ b/src/crypto/aes/gcm_ppc64le.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64le // +build ppc64le package aes diff --git a/src/crypto/cipher/xor_generic.go b/src/crypto/cipher/xor_generic.go index ca9c4bbf39..03208402d7 100644 --- a/src/crypto/cipher/xor_generic.go +++ b/src/crypto/cipher/xor_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !ppc64 && !ppc64le && !arm64 // +build !amd64,!ppc64,!ppc64le,!arm64 package cipher diff --git a/src/crypto/cipher/xor_ppc64x.go b/src/crypto/cipher/xor_ppc64x.go index 8d2e43d327..f520208a37 100644 --- a/src/crypto/cipher/xor_ppc64x.go +++ b/src/crypto/cipher/xor_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package cipher diff --git a/src/crypto/ecdsa/ecdsa_noasm.go b/src/crypto/ecdsa/ecdsa_noasm.go index 72196211e5..68670a4f93 100644 --- a/src/crypto/ecdsa/ecdsa_noasm.go +++ b/src/crypto/ecdsa/ecdsa_noasm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !s390x // +build !s390x package ecdsa diff --git a/src/crypto/ecdsa/ecdsa_s390x_test.go b/src/crypto/ecdsa/ecdsa_s390x_test.go index a434575dbc..e8b16b3668 100644 --- a/src/crypto/ecdsa/ecdsa_s390x_test.go +++ b/src/crypto/ecdsa/ecdsa_s390x_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x // +build s390x package ecdsa diff --git a/src/crypto/elliptic/fuzz_test.go b/src/crypto/elliptic/fuzz_test.go index b9209a789b..f5c9841a12 100644 --- a/src/crypto/elliptic/fuzz_test.go +++ b/src/crypto/elliptic/fuzz_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 || ppc64le // +build amd64 arm64 ppc64le package elliptic diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go index c23e414156..3bb7bb70b6 100644 --- a/src/crypto/elliptic/p256.go +++ b/src/crypto/elliptic/p256.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !arm64 // +build !amd64,!arm64 package elliptic diff --git a/src/crypto/elliptic/p256_asm.go b/src/crypto/elliptic/p256_asm.go index 6cf7742e1b..c405718b5e 100644 --- a/src/crypto/elliptic/p256_asm.go +++ b/src/crypto/elliptic/p256_asm.go @@ -10,6 +10,7 @@ // https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf +//go:build amd64 || arm64 // +build amd64 arm64 package elliptic diff --git a/src/crypto/elliptic/p256_generic.go b/src/crypto/elliptic/p256_generic.go index f74c607a88..8ad56638e9 100644 --- a/src/crypto/elliptic/p256_generic.go +++ b/src/crypto/elliptic/p256_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !s390x && !arm64 && !ppc64le // +build !amd64,!s390x,!arm64,!ppc64le package elliptic diff --git a/src/crypto/elliptic/p256_ppc64le.go b/src/crypto/elliptic/p256_ppc64le.go index 160bdb12e3..40d9ed9d40 100644 --- a/src/crypto/elliptic/p256_ppc64le.go +++ b/src/crypto/elliptic/p256_ppc64le.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64le // +build ppc64le package elliptic diff --git a/src/crypto/elliptic/p256_s390x.go b/src/crypto/elliptic/p256_s390x.go index 0d9478bfd6..91e613b631 100644 --- a/src/crypto/elliptic/p256_s390x.go +++ b/src/crypto/elliptic/p256_s390x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x // +build s390x package elliptic diff --git a/src/crypto/internal/subtle/aliasing.go b/src/crypto/internal/subtle/aliasing.go index 812ce3c655..86e0f3cfe7 100644 --- a/src/crypto/internal/subtle/aliasing.go +++ b/src/crypto/internal/subtle/aliasing.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !appengine // +build !appengine // Package subtle implements functions that are often useful in cryptographic diff --git a/src/crypto/internal/subtle/aliasing_appengine.go b/src/crypto/internal/subtle/aliasing_appengine.go index 844f901d18..35b442f7a2 100644 --- a/src/crypto/internal/subtle/aliasing_appengine.go +++ b/src/crypto/internal/subtle/aliasing_appengine.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build appengine // +build appengine // Package subtle implements functions that are often useful in cryptographic diff --git a/src/crypto/md5/gen.go b/src/crypto/md5/gen.go index 1468924cbc..29729fad01 100644 --- a/src/crypto/md5/gen.go +++ b/src/crypto/md5/gen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program generates md5block.go diff --git a/src/crypto/md5/md5block_decl.go b/src/crypto/md5/md5block_decl.go index f251e03d7f..bc2d58c069 100644 --- a/src/crypto/md5/md5block_decl.go +++ b/src/crypto/md5/md5block_decl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64 // +build amd64 386 arm ppc64le ppc64 s390x arm64 package md5 diff --git a/src/crypto/md5/md5block_generic.go b/src/crypto/md5/md5block_generic.go index 0b46e70b60..ea4fbcd0b4 100644 --- a/src/crypto/md5/md5block_generic.go +++ b/src/crypto/md5/md5block_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64 // +build !amd64,!386,!arm,!ppc64le,!ppc64,!s390x,!arm64 package md5 diff --git a/src/crypto/rand/eagain.go b/src/crypto/rand/eagain.go index c9499715dc..85d4d9d47f 100644 --- a/src/crypto/rand/eagain.go +++ b/src/crypto/rand/eagain.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package rand diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go index 60267fd4bc..45e9351a31 100644 --- a/src/crypto/rand/rand_batched.go +++ b/src/crypto/rand/rand_batched.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux || freebsd // +build linux freebsd package rand diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go index 837db83f77..fd50735c7d 100644 --- a/src/crypto/rand/rand_batched_test.go +++ b/src/crypto/rand/rand_batched_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux || freebsd // +build linux freebsd package rand diff --git a/src/crypto/rand/rand_js.go b/src/crypto/rand/rand_js.go index 7e939742ac..7ddc2b6169 100644 --- a/src/crypto/rand/rand_js.go +++ b/src/crypto/rand/rand_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package rand diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go index 548a5e4cb9..81277eb6a5 100644 --- a/src/crypto/rand/rand_unix.go +++ b/src/crypto/rand/rand_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || plan9 || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd plan9 solaris // Unix cryptographically secure pseudorandom number diff --git a/src/crypto/sha1/fallback_test.go b/src/crypto/sha1/fallback_test.go index 08acd044d0..4bb8b3324f 100644 --- a/src/crypto/sha1/fallback_test.go +++ b/src/crypto/sha1/fallback_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x // +build s390x package sha1 diff --git a/src/crypto/sha1/issue15617_test.go b/src/crypto/sha1/issue15617_test.go index 98038e5807..436f78c745 100644 --- a/src/crypto/sha1/issue15617_test.go +++ b/src/crypto/sha1/issue15617_test.go @@ -1,3 +1,4 @@ +//go:build amd64 && (linux || darwin) // +build amd64 // +build linux darwin diff --git a/src/crypto/sha1/sha1block_decl.go b/src/crypto/sha1/sha1block_decl.go index 9c7df4e40a..93054efa7c 100644 --- a/src/crypto/sha1/sha1block_decl.go +++ b/src/crypto/sha1/sha1block_decl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm || 386 || s390x // +build arm 386 s390x package sha1 diff --git a/src/crypto/sha1/sha1block_generic.go b/src/crypto/sha1/sha1block_generic.go index f95ea0eee4..feaba5a23a 100644 --- a/src/crypto/sha1/sha1block_generic.go +++ b/src/crypto/sha1/sha1block_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !386 && !arm && !s390x && !arm64 // +build !amd64,!386,!arm,!s390x,!arm64 package sha1 diff --git a/src/crypto/sha256/fallback_test.go b/src/crypto/sha256/fallback_test.go index 5917a4862a..7ce88cbb2a 100644 --- a/src/crypto/sha256/fallback_test.go +++ b/src/crypto/sha256/fallback_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x // +build s390x package sha256 diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go index fe07e53b84..a6bb396f13 100644 --- a/src/crypto/sha256/sha256block_decl.go +++ b/src/crypto/sha256/sha256block_decl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 || s390x || ppc64le // +build 386 amd64 s390x ppc64le package sha256 diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go index 61362f4126..620c048b93 100644 --- a/src/crypto/sha256/sha256block_generic.go +++ b/src/crypto/sha256/sha256block_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !386 && !s390x && !ppc64le && !arm64 // +build !amd64,!386,!s390x,!ppc64le,!arm64 package sha256 diff --git a/src/crypto/sha512/fallback_test.go b/src/crypto/sha512/fallback_test.go index 9024ce668a..faf732670a 100644 --- a/src/crypto/sha512/fallback_test.go +++ b/src/crypto/sha512/fallback_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x // +build s390x package sha512 diff --git a/src/crypto/sha512/sha512block_amd64.go b/src/crypto/sha512/sha512block_amd64.go index 18151cea24..e2386f29ab 100644 --- a/src/crypto/sha512/sha512block_amd64.go +++ b/src/crypto/sha512/sha512block_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 // +build amd64 package sha512 diff --git a/src/crypto/sha512/sha512block_decl.go b/src/crypto/sha512/sha512block_decl.go index 613d1e02a3..6c22f44801 100644 --- a/src/crypto/sha512/sha512block_decl.go +++ b/src/crypto/sha512/sha512block_decl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x || ppc64le // +build s390x ppc64le package sha512 diff --git a/src/crypto/sha512/sha512block_generic.go b/src/crypto/sha512/sha512block_generic.go index 3eabd2c7c0..865a7356f1 100644 --- a/src/crypto/sha512/sha512block_generic.go +++ b/src/crypto/sha512/sha512block_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !s390x && !ppc64le // +build !amd64,!s390x,!ppc64le package sha512 diff --git a/src/crypto/tls/generate_cert.go b/src/crypto/tls/generate_cert.go index 1857185fe4..7ea90f8a7b 100644 --- a/src/crypto/tls/generate_cert.go +++ b/src/crypto/tls/generate_cert.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate a self-signed X.509 certificate for a TLS server. Outputs to diff --git a/src/crypto/tls/handshake_unix_test.go b/src/crypto/tls/handshake_unix_test.go index 72718544ae..19fc698676 100644 --- a/src/crypto/tls/handshake_unix_test.go +++ b/src/crypto/tls/handshake_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package tls diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go index 0572c6ccd8..abcdcdd91e 100644 --- a/src/crypto/x509/internal/macos/corefoundation.go +++ b/src/crypto/x509/internal/macos/corefoundation.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && !ios // +build darwin,!ios // Package macOS provides cgo-less wrappers for Core Foundation and diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go index 3163e3a4f7..f346ff4c7f 100644 --- a/src/crypto/x509/internal/macos/security.go +++ b/src/crypto/x509/internal/macos/security.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin && !ios // +build darwin,!ios package macOS diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go index f04b6bd0d6..822e8573ff 100644 --- a/src/crypto/x509/root_bsd.go +++ b/src/crypto/x509/root_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || netbsd || openbsd // +build dragonfly freebsd netbsd openbsd package x509 diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go index c9ea7e80f3..05593bb105 100644 --- a/src/crypto/x509/root_darwin.go +++ b/src/crypto/x509/root_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !ios // +build !ios package x509 diff --git a/src/crypto/x509/root_ios.go b/src/crypto/x509/root_ios.go index d2dfb62b77..50432f3d2c 100644 --- a/src/crypto/x509/root_ios.go +++ b/src/crypto/x509/root_ios.go @@ -1,8 +1,8 @@ // Code generated by root_ios_gen.go -version 55188.40.9; DO NOT EDIT. // Update the version in root.go and regenerate with "go generate". -// +build ios -// +build !x509omitbundledroots +//go:build ios && !x509omitbundledroots +// +build ios,!x509omitbundledroots package x509 diff --git a/src/crypto/x509/root_ios_gen.go b/src/crypto/x509/root_ios_gen.go index 8bc6e7d9c4..05bd672d5d 100644 --- a/src/crypto/x509/root_ios_gen.go +++ b/src/crypto/x509/root_ios_gen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generates root_ios.go. diff --git a/src/crypto/x509/root_js.go b/src/crypto/x509/root_js.go index 4e537a4fe5..f2c2c0af38 100644 --- a/src/crypto/x509/root_js.go +++ b/src/crypto/x509/root_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package x509 diff --git a/src/crypto/x509/root_omit.go b/src/crypto/x509/root_omit.go index 0055b3b862..81f2f112d0 100644 --- a/src/crypto/x509/root_omit.go +++ b/src/crypto/x509/root_omit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ((darwin && arm64) || (darwin && amd64 && ios)) && x509omitbundledroots // +build darwin,arm64 darwin,amd64,ios // +build x509omitbundledroots diff --git a/src/crypto/x509/root_omit_test.go b/src/crypto/x509/root_omit_test.go index 5ab6c931de..158bd7f91a 100644 --- a/src/crypto/x509/root_omit_test.go +++ b/src/crypto/x509/root_omit_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ((darwin && arm64) || (darwin && amd64 && ios)) && x509omitbundledroots // +build darwin,arm64 darwin,amd64,ios // +build x509omitbundledroots diff --git a/src/crypto/x509/root_plan9.go b/src/crypto/x509/root_plan9.go index 2dc4aaf5d7..2bdb2fe713 100644 --- a/src/crypto/x509/root_plan9.go +++ b/src/crypto/x509/root_plan9.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package x509 diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index 262fc079d5..dede825edd 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris package x509 diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go index 878ed7c2fa..38038a65f3 100644 --- a/src/crypto/x509/root_unix_test.go +++ b/src/crypto/x509/root_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build dragonfly freebsd linux netbsd openbsd solaris package x509 diff --git a/src/crypto/x509/x509_test_import.go b/src/crypto/x509/x509_test_import.go index b778df261a..ef3ee807bf 100644 --- a/src/crypto/x509/x509_test_import.go +++ b/src/crypto/x509/x509_test_import.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This file is run by the x509 tests to ensure that a program with minimal diff --git a/src/debug/pe/file_cgo_test.go b/src/debug/pe/file_cgo_test.go index 739671d73f..bba3a068d6 100644 --- a/src/debug/pe/file_cgo_test.go +++ b/src/debug/pe/file_cgo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo // +build cgo package pe diff --git a/src/encoding/csv/fuzz.go b/src/encoding/csv/fuzz.go index 8be21d5d28..a03fa83d8c 100644 --- a/src/encoding/csv/fuzz.go +++ b/src/encoding/csv/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package csv diff --git a/src/encoding/gob/debug.go b/src/encoding/gob/debug.go index 8f93742f49..5965fea921 100644 --- a/src/encoding/gob/debug.go +++ b/src/encoding/gob/debug.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Delete the next line to include in the gob package. +//go:build ignore // +build ignore package gob diff --git a/src/encoding/gob/decgen.go b/src/encoding/gob/decgen.go index 1c31e66625..994be877d9 100644 --- a/src/encoding/gob/decgen.go +++ b/src/encoding/gob/decgen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // encgen writes the helper functions for encoding. Intended to be diff --git a/src/encoding/gob/dump.go b/src/encoding/gob/dump.go index 17238c98df..8c0bbc4ff2 100644 --- a/src/encoding/gob/dump.go +++ b/src/encoding/gob/dump.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/encoding/gob/encgen.go b/src/encoding/gob/encgen.go index 409b8c9d95..b562da177d 100644 --- a/src/encoding/gob/encgen.go +++ b/src/encoding/gob/encgen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // encgen writes the helper functions for encoding. Intended to be diff --git a/src/encoding/json/fuzz.go b/src/encoding/json/fuzz.go index be03f0d7ff..d3fa2d1113 100644 --- a/src/encoding/json/fuzz.go +++ b/src/encoding/json/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package json diff --git a/src/go/build/gc.go b/src/go/build/gc.go index 3025cd5681..e16e186e0d 100644 --- a/src/go/build/gc.go +++ b/src/go/build/gc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc package build diff --git a/src/go/build/gccgo.go b/src/go/build/gccgo.go index c6aac9aa1b..c8ec7041fb 100644 --- a/src/go/build/gccgo.go +++ b/src/go/build/gccgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gccgo // +build gccgo package build diff --git a/src/go/doc/headscan.go b/src/go/doc/headscan.go index fe26a0ea84..28cb84f91d 100644 --- a/src/go/doc/headscan.go +++ b/src/go/doc/headscan.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/go/types/example_test.go b/src/go/types/example_test.go index 3747f3b15a..32a25a4117 100644 --- a/src/go/types/example_test.go +++ b/src/go/types/example_test.go @@ -5,6 +5,7 @@ // Only run where builders (build.golang.org) have // access to compiled packages for import. // +//go:build !arm && !arm64 // +build !arm,!arm64 package types_test diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go index 52709df17b..ca1d42c14d 100644 --- a/src/go/types/gotype.go +++ b/src/go/types/gotype.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Build this command explicitly: go build gotype.go diff --git a/src/hash/crc32/crc32_otherarch.go b/src/hash/crc32/crc32_otherarch.go index 1a5e542ab6..936e5bf3e0 100644 --- a/src/hash/crc32/crc32_otherarch.go +++ b/src/hash/crc32/crc32_otherarch.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !s390x && !ppc64le && !arm64 // +build !amd64,!s390x,!ppc64le,!arm64 package crc32 diff --git a/src/hash/crc32/gen_const_ppc64le.go b/src/hash/crc32/gen_const_ppc64le.go index d7af018af4..c98454c685 100644 --- a/src/hash/crc32/gen_const_ppc64le.go +++ b/src/hash/crc32/gen_const_ppc64le.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate the constant table associated with the poly used by the diff --git a/src/html/fuzz.go b/src/html/fuzz.go index ffa3e257f4..ecaf4f9069 100644 --- a/src/html/fuzz.go +++ b/src/html/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package html diff --git a/src/image/color/palette/gen.go b/src/image/color/palette/gen.go index 3243e53981..7bb257d865 100644 --- a/src/image/color/palette/gen.go +++ b/src/image/color/palette/gen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go index 36de5dc9cc..38f41303fa 100644 --- a/src/image/internal/imageutil/gen.go +++ b/src/image/internal/imageutil/gen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/image/png/fuzz.go b/src/image/png/fuzz.go index d9cb3921e5..6508533f44 100644 --- a/src/image/png/fuzz.go +++ b/src/image/png/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package png diff --git a/src/index/suffixarray/gen.go b/src/index/suffixarray/gen.go index 94184d71b6..3bc9b1e2ae 100644 --- a/src/index/suffixarray/gen.go +++ b/src/index/suffixarray/gen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Gen generates sais2.go by duplicating functions in sais.go diff --git a/src/internal/abi/abi_amd64.go b/src/internal/abi/abi_amd64.go index 70e2ed1feb..77589d4c34 100644 --- a/src/internal/abi/abi_amd64.go +++ b/src/internal/abi/abi_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build goexperiment.regabi // +build goexperiment.regabi package abi diff --git a/src/internal/abi/abi_generic.go b/src/internal/abi/abi_generic.go index 5ef9883dc6..1e36f36e80 100644 --- a/src/internal/abi/abi_generic.go +++ b/src/internal/abi/abi_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.regabi // +build !goexperiment.regabi package abi diff --git a/src/internal/bytealg/compare_generic.go b/src/internal/bytealg/compare_generic.go index bd4489a6b9..0690d0cf31 100644 --- a/src/internal/bytealg/compare_generic.go +++ b/src/internal/bytealg/compare_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !wasm && !mips64 && !mips64le // +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!wasm,!mips64,!mips64le package bytealg diff --git a/src/internal/bytealg/compare_native.go b/src/internal/bytealg/compare_native.go index b53ba97463..baa188ff7a 100644 --- a/src/internal/bytealg/compare_native.go +++ b/src/internal/bytealg/compare_native.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || wasm || mips64 || mips64le // +build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle wasm mips64 mips64le package bytealg diff --git a/src/internal/bytealg/count_generic.go b/src/internal/bytealg/count_generic.go index 5575e81ab8..1891d29b24 100644 --- a/src/internal/bytealg/count_generic.go +++ b/src/internal/bytealg/count_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !arm && !arm64 && !ppc64le && !ppc64 && !riscv64 && !s390x // +build !amd64,!arm,!arm64,!ppc64le,!ppc64,!riscv64,!s390x package bytealg diff --git a/src/internal/bytealg/count_native.go b/src/internal/bytealg/count_native.go index b1ff1d265a..a19a6f8223 100644 --- a/src/internal/bytealg/count_native.go +++ b/src/internal/bytealg/count_native.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm || arm64 || ppc64le || ppc64 || riscv64 || s390x // +build amd64 arm arm64 ppc64le ppc64 riscv64 s390x package bytealg diff --git a/src/internal/bytealg/index_generic.go b/src/internal/bytealg/index_generic.go index 98e859f925..2b8b139aeb 100644 --- a/src/internal/bytealg/index_generic.go +++ b/src/internal/bytealg/index_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 && !arm64 && !s390x // +build !amd64,!arm64,!s390x package bytealg diff --git a/src/internal/bytealg/index_native.go b/src/internal/bytealg/index_native.go index fde4214245..af56d8a294 100644 --- a/src/internal/bytealg/index_native.go +++ b/src/internal/bytealg/index_native.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 || s390x // +build amd64 arm64 s390x package bytealg diff --git a/src/internal/bytealg/indexbyte_generic.go b/src/internal/bytealg/indexbyte_generic.go index 0b012a8850..6ef639fafd 100644 --- a/src/internal/bytealg/indexbyte_generic.go +++ b/src/internal/bytealg/indexbyte_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !mips64 && !mips64le && !riscv64 && !wasm // +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!mips64,!mips64le,!riscv64,!wasm package bytealg diff --git a/src/internal/bytealg/indexbyte_native.go b/src/internal/bytealg/indexbyte_native.go index f96c5be491..965f38fe52 100644 --- a/src/internal/bytealg/indexbyte_native.go +++ b/src/internal/bytealg/indexbyte_native.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || mips64 || mips64le || riscv64 || wasm // +build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv64 wasm package bytealg diff --git a/src/internal/cpu/cpu_arm64_android.go b/src/internal/cpu/cpu_arm64_android.go index 3c9e57c52a..ac6eee54b2 100644 --- a/src/internal/cpu/cpu_arm64_android.go +++ b/src/internal/cpu/cpu_arm64_android.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package cpu diff --git a/src/internal/cpu/cpu_arm64_darwin.go b/src/internal/cpu/cpu_arm64_darwin.go index e094b97f97..ce1b250a18 100644 --- a/src/internal/cpu/cpu_arm64_darwin.go +++ b/src/internal/cpu/cpu_arm64_darwin.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build darwin -// +build !ios +//go:build arm64 && darwin && !ios +// +build arm64,darwin,!ios package cpu diff --git a/src/internal/cpu/cpu_arm64_freebsd.go b/src/internal/cpu/cpu_arm64_freebsd.go index 9de2005c2e..8c481370da 100644 --- a/src/internal/cpu/cpu_arm64_freebsd.go +++ b/src/internal/cpu/cpu_arm64_freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package cpu diff --git a/src/internal/cpu/cpu_arm64_hwcap.go b/src/internal/cpu/cpu_arm64_hwcap.go index fdaf43e1a2..8ac04fd8f9 100644 --- a/src/internal/cpu/cpu_arm64_hwcap.go +++ b/src/internal/cpu/cpu_arm64_hwcap.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build linux +//go:build arm64 && linux +// +build arm64,linux package cpu diff --git a/src/internal/cpu/cpu_arm64_linux.go b/src/internal/cpu/cpu_arm64_linux.go index 2f7411ff1e..c3a3f9a8e9 100644 --- a/src/internal/cpu/cpu_arm64_linux.go +++ b/src/internal/cpu/cpu_arm64_linux.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 -// +build linux -// +build !android +//go:build arm64 && linux && !android +// +build arm64,linux,!android package cpu diff --git a/src/internal/cpu/cpu_arm64_other.go b/src/internal/cpu/cpu_arm64_other.go index f191db28d2..e8b5d529a4 100644 --- a/src/internal/cpu/cpu_arm64_other.go +++ b/src/internal/cpu/cpu_arm64_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 && !linux && !freebsd && !android && (!darwin || ios) // +build arm64 // +build !linux // +build !freebsd diff --git a/src/internal/cpu/cpu_mips64x.go b/src/internal/cpu/cpu_mips64x.go index 0c4794a70a..d2f9d4499b 100644 --- a/src/internal/cpu/cpu_mips64x.go +++ b/src/internal/cpu/cpu_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package cpu diff --git a/src/internal/cpu/cpu_no_name.go b/src/internal/cpu/cpu_no_name.go index ce1c37a3c7..8d563b536c 100644 --- a/src/internal/cpu/cpu_no_name.go +++ b/src/internal/cpu/cpu_no_name.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !386 -// +build !amd64 +//go:build !386 && !amd64 +// +build !386,!amd64 package cpu diff --git a/src/internal/cpu/cpu_ppc64x.go b/src/internal/cpu/cpu_ppc64x.go index beb1765427..2e7fd3ebb9 100644 --- a/src/internal/cpu/cpu_ppc64x.go +++ b/src/internal/cpu/cpu_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package cpu diff --git a/src/internal/cpu/cpu_ppc64x_aix.go b/src/internal/cpu/cpu_ppc64x_aix.go index b840b823ba..3d17a9c730 100644 --- a/src/internal/cpu/cpu_ppc64x_aix.go +++ b/src/internal/cpu/cpu_ppc64x_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package cpu diff --git a/src/internal/cpu/cpu_ppc64x_linux.go b/src/internal/cpu/cpu_ppc64x_linux.go index 73b191436d..b7c7345111 100644 --- a/src/internal/cpu/cpu_ppc64x_linux.go +++ b/src/internal/cpu/cpu_ppc64x_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package cpu diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go index ba6bf69034..fd1217a05d 100644 --- a/src/internal/cpu/cpu_x86.go +++ b/src/internal/cpu/cpu_x86.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 // +build 386 amd64 package cpu diff --git a/src/internal/cpu/cpu_x86_test.go b/src/internal/cpu/cpu_x86_test.go index 61db93bd51..e3e16cc161 100644 --- a/src/internal/cpu/cpu_x86_test.go +++ b/src/internal/cpu/cpu_x86_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || amd64 // +build 386 amd64 package cpu_test diff --git a/src/internal/goroot/gc.go b/src/internal/goroot/gc.go index ce72bc3896..2338b78f3a 100644 --- a/src/internal/goroot/gc.go +++ b/src/internal/goroot/gc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc package goroot diff --git a/src/internal/goroot/gccgo.go b/src/internal/goroot/gccgo.go index 3530e59a15..b1041da11d 100644 --- a/src/internal/goroot/gccgo.go +++ b/src/internal/goroot/gccgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gccgo // +build gccgo package goroot diff --git a/src/internal/poll/errno_unix.go b/src/internal/poll/errno_unix.go index 0b23fc3210..55c548824f 100644 --- a/src/internal/poll/errno_unix.go +++ b/src/internal/poll/errno_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package poll diff --git a/src/internal/poll/errno_windows.go b/src/internal/poll/errno_windows.go index e3bddb4bb2..c55f5f0df5 100644 --- a/src/internal/poll/errno_windows.go +++ b/src/internal/poll/errno_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package poll diff --git a/src/internal/poll/error_stub_test.go b/src/internal/poll/error_stub_test.go index c40ffcd20f..bcc25dd666 100644 --- a/src/internal/poll/error_stub_test.go +++ b/src/internal/poll/error_stub_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package poll_test diff --git a/src/internal/poll/export_posix_test.go b/src/internal/poll/export_posix_test.go index abadf50930..f59c1f6dfa 100644 --- a/src/internal/poll/export_posix_test.go +++ b/src/internal/poll/export_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows // Export guts for testing on posix. diff --git a/src/internal/poll/fcntl_js.go b/src/internal/poll/fcntl_js.go index 120fc1195f..7bf0ddc792 100644 --- a/src/internal/poll/fcntl_js.go +++ b/src/internal/poll/fcntl_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package poll diff --git a/src/internal/poll/fcntl_libc.go b/src/internal/poll/fcntl_libc.go index 642472bc2b..cc609e48ad 100644 --- a/src/internal/poll/fcntl_libc.go +++ b/src/internal/poll/fcntl_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || solaris // +build aix darwin solaris package poll diff --git a/src/internal/poll/fcntl_syscall.go b/src/internal/poll/fcntl_syscall.go index 5ac814359a..8db5b66504 100644 --- a/src/internal/poll/fcntl_syscall.go +++ b/src/internal/poll/fcntl_syscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package poll diff --git a/src/internal/poll/fd_fsync_posix.go b/src/internal/poll/fd_fsync_posix.go index dd7956f14d..651a5ecd8b 100644 --- a/src/internal/poll/fd_fsync_posix.go +++ b/src/internal/poll/fd_fsync_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris package poll diff --git a/src/internal/poll/fd_poll_js.go b/src/internal/poll/fd_poll_js.go index d6b28e503c..760e24802e 100644 --- a/src/internal/poll/fd_poll_js.go +++ b/src/internal/poll/fd_poll_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package poll diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go index 222e5c6707..beb0f7d6a6 100644 --- a/src/internal/poll/fd_poll_runtime.go +++ b/src/internal/poll/fd_poll_runtime.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || windows || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd windows solaris package poll diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go index 4edfa953a4..487f3285ee 100644 --- a/src/internal/poll/fd_posix.go +++ b/src/internal/poll/fd_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package poll diff --git a/src/internal/poll/fd_posix_test.go b/src/internal/poll/fd_posix_test.go index 4449eb3a15..1dcf51d419 100644 --- a/src/internal/poll/fd_posix_test.go +++ b/src/internal/poll/fd_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package poll_test diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index 2e77e76c87..fe8a5c8ec0 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package poll diff --git a/src/internal/poll/fd_writev_darwin.go b/src/internal/poll/fd_writev_darwin.go index e2024471d4..805fa2ccd9 100644 --- a/src/internal/poll/fd_writev_darwin.go +++ b/src/internal/poll/fd_writev_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin // +build darwin package poll diff --git a/src/internal/poll/fd_writev_illumos.go b/src/internal/poll/fd_writev_illumos.go index 1fa47ab1a3..a0b11ed5ae 100644 --- a/src/internal/poll/fd_writev_illumos.go +++ b/src/internal/poll/fd_writev_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package poll diff --git a/src/internal/poll/fd_writev_unix.go b/src/internal/poll/fd_writev_unix.go index daeec96c38..87f284a56a 100644 --- a/src/internal/poll/fd_writev_unix.go +++ b/src/internal/poll/fd_writev_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package poll diff --git a/src/internal/poll/hook_cloexec.go b/src/internal/poll/hook_cloexec.go index 5fd5449bb0..d519f602c1 100644 --- a/src/internal/poll/hook_cloexec.go +++ b/src/internal/poll/hook_cloexec.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/src/internal/poll/hook_unix.go b/src/internal/poll/hook_unix.go index 11f90e9696..c88d65cdc8 100644 --- a/src/internal/poll/hook_unix.go +++ b/src/internal/poll/hook_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package poll diff --git a/src/internal/poll/iovec_illumos.go b/src/internal/poll/iovec_illumos.go index 057067465b..f4058b298f 100644 --- a/src/internal/poll/iovec_illumos.go +++ b/src/internal/poll/iovec_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package poll diff --git a/src/internal/poll/iovec_unix.go b/src/internal/poll/iovec_unix.go index 6f98947866..6fd5d86630 100644 --- a/src/internal/poll/iovec_unix.go +++ b/src/internal/poll/iovec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package poll diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go index 66005a9f5c..9eda85882c 100644 --- a/src/internal/poll/sendfile_bsd.go +++ b/src/internal/poll/sendfile_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd // +build dragonfly freebsd package poll diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go index ff7982ca9e..52191d85c6 100644 --- a/src/internal/poll/sock_cloexec.go +++ b/src/internal/poll/sock_cloexec.go @@ -5,6 +5,7 @@ // This file implements sysSocket and accept for platforms that // provide a fast path for setting SetNonblock and CloseOnExec. +//go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/src/internal/poll/sockopt.go b/src/internal/poll/sockopt.go index bb5ea02c0a..4f2e2fb455 100644 --- a/src/internal/poll/sockopt.go +++ b/src/internal/poll/sockopt.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package poll diff --git a/src/internal/poll/sockopt_unix.go b/src/internal/poll/sockopt_unix.go index bd942c2934..4fb9600dee 100644 --- a/src/internal/poll/sockopt_unix.go +++ b/src/internal/poll/sockopt_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package poll diff --git a/src/internal/poll/sockoptip.go b/src/internal/poll/sockoptip.go index c55a1e3c5b..d86c4c1f81 100644 --- a/src/internal/poll/sockoptip.go +++ b/src/internal/poll/sockoptip.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package poll diff --git a/src/internal/poll/strconv.go b/src/internal/poll/strconv.go index 21cb40db70..fd5e20f1f4 100644 --- a/src/internal/poll/strconv.go +++ b/src/internal/poll/strconv.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 // Simple conversions to avoid depending on strconv. diff --git a/src/internal/poll/sys_cloexec.go b/src/internal/poll/sys_cloexec.go index 4b3c642173..69207a4b89 100644 --- a/src/internal/poll/sys_cloexec.go +++ b/src/internal/poll/sys_cloexec.go @@ -5,6 +5,7 @@ // This file implements sysSocket and accept for platforms that do not // provide a fast path for setting SetNonblock and CloseOnExec. +//go:build aix || darwin || (js && wasm) || (solaris && !illumos) // +build aix darwin js,wasm solaris,!illumos package poll diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go index 0123fc33de..824de7569e 100644 --- a/src/internal/poll/writev.go +++ b/src/internal/poll/writev.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build darwin dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/src/internal/race/norace.go b/src/internal/race/norace.go index d83c0165b2..67b1305713 100644 --- a/src/internal/race/norace.go +++ b/src/internal/race/norace.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !race // +build !race package race diff --git a/src/internal/race/race.go b/src/internal/race/race.go index 2e7d97beaa..40f2c99383 100644 --- a/src/internal/race/race.go +++ b/src/internal/race/race.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package race diff --git a/src/internal/syscall/execenv/execenv_default.go b/src/internal/syscall/execenv/execenv_default.go index 4bdbb55edb..73289f1cd0 100644 --- a/src/internal/syscall/execenv/execenv_default.go +++ b/src/internal/syscall/execenv/execenv_default.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package execenv diff --git a/src/internal/syscall/execenv/execenv_windows.go b/src/internal/syscall/execenv/execenv_windows.go index b50029c198..6c0654943e 100644 --- a/src/internal/syscall/execenv/execenv_windows.go +++ b/src/internal/syscall/execenv/execenv_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package execenv diff --git a/src/internal/syscall/unix/at.go b/src/internal/syscall/unix/at.go index f857d68280..9b08864f7f 100644 --- a/src/internal/syscall/unix/at.go +++ b/src/internal/syscall/unix/at.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux || openbsd || netbsd || dragonfly // +build linux openbsd netbsd dragonfly package unix diff --git a/src/internal/syscall/unix/at_libc.go b/src/internal/syscall/unix/at_libc.go index 6c3a8c9160..4cc351ea27 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || solaris // +build aix solaris package unix diff --git a/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go b/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go index c6ea206c12..050d401bc0 100644 --- a/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go +++ b/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm || mips || mipsle || 386 // +build arm mips mipsle 386 package unix diff --git a/src/internal/syscall/unix/at_sysnum_fstatat_linux.go b/src/internal/syscall/unix/at_sysnum_fstatat_linux.go index 31fe6a5a7b..e53a2d1b75 100644 --- a/src/internal/syscall/unix/at_sysnum_fstatat_linux.go +++ b/src/internal/syscall/unix/at_sysnum_fstatat_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 || riscv64 // +build arm64 riscv64 package unix diff --git a/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go b/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go index e76c1cbdce..4cb4a5976b 100644 --- a/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go +++ b/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || mips64 || mips64le || ppc64 || ppc64le || s390x // +build amd64 mips64 mips64le ppc64 ppc64le s390x package unix diff --git a/src/internal/syscall/unix/fcntl_linux_32bit.go b/src/internal/syscall/unix/fcntl_linux_32bit.go index 6c75afc2ab..46a4f6b030 100644 --- a/src/internal/syscall/unix/fcntl_linux_32bit.go +++ b/src/internal/syscall/unix/fcntl_linux_32bit.go @@ -5,6 +5,7 @@ // On 32-bit Linux systems, use SYS_FCNTL64. // If you change the build tags here, see syscall/flock_linux_32bit.go. +//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) // +build linux,386 linux,arm linux,mips linux,mipsle package unix diff --git a/src/internal/syscall/unix/nonblocking.go b/src/internal/syscall/unix/nonblocking.go index db25fcca98..a22986cb8a 100644 --- a/src/internal/syscall/unix/nonblocking.go +++ b/src/internal/syscall/unix/nonblocking.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package unix diff --git a/src/internal/syscall/unix/nonblocking_js.go b/src/internal/syscall/unix/nonblocking_js.go index a360b53c3d..a5a5080d46 100644 --- a/src/internal/syscall/unix/nonblocking_js.go +++ b/src/internal/syscall/unix/nonblocking_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package unix diff --git a/src/internal/syscall/unix/nonblocking_libc.go b/src/internal/syscall/unix/nonblocking_libc.go index 37cc7943ee..d9565efcb6 100644 --- a/src/internal/syscall/unix/nonblocking_libc.go +++ b/src/internal/syscall/unix/nonblocking_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || solaris // +build aix darwin solaris package unix diff --git a/src/internal/syscall/unix/pipe2_illumos.go b/src/internal/syscall/unix/pipe2_illumos.go index f3ac8d29df..b0aac89580 100644 --- a/src/internal/syscall/unix/pipe2_illumos.go +++ b/src/internal/syscall/unix/pipe2_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package unix diff --git a/src/internal/syscall/unix/sysnum_linux_generic.go b/src/internal/syscall/unix/sysnum_linux_generic.go index f48da40188..a76025454c 100644 --- a/src/internal/syscall/unix/sysnum_linux_generic.go +++ b/src/internal/syscall/unix/sysnum_linux_generic.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (arm64 || riscv64) // +build linux // +build arm64 riscv64 diff --git a/src/internal/syscall/unix/sysnum_linux_mips64x.go b/src/internal/syscall/unix/sysnum_linux_mips64x.go index 6680942cb8..f353d4d73e 100644 --- a/src/internal/syscall/unix/sysnum_linux_mips64x.go +++ b/src/internal/syscall/unix/sysnum_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package unix diff --git a/src/internal/syscall/unix/sysnum_linux_mipsx.go b/src/internal/syscall/unix/sysnum_linux_mipsx.go index 185d8320c9..4ed471532a 100644 --- a/src/internal/syscall/unix/sysnum_linux_mipsx.go +++ b/src/internal/syscall/unix/sysnum_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle package unix diff --git a/src/internal/syscall/unix/sysnum_linux_ppc64x.go b/src/internal/syscall/unix/sysnum_linux_ppc64x.go index 576937e3f5..b484ffef80 100644 --- a/src/internal/syscall/unix/sysnum_linux_ppc64x.go +++ b/src/internal/syscall/unix/sysnum_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package unix diff --git a/src/internal/syscall/unix/writev_illumos.go b/src/internal/syscall/unix/writev_illumos.go index eb7973d65b..f60949f662 100644 --- a/src/internal/syscall/unix/writev_illumos.go +++ b/src/internal/syscall/unix/writev_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package unix diff --git a/src/internal/testenv/testenv_cgo.go b/src/internal/testenv/testenv_cgo.go index e3d4d16b33..02f08f57c7 100644 --- a/src/internal/testenv/testenv_cgo.go +++ b/src/internal/testenv/testenv_cgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo // +build cgo package testenv diff --git a/src/internal/testenv/testenv_notwin.go b/src/internal/testenv/testenv_notwin.go index ccb5d5585f..846ec93856 100644 --- a/src/internal/testenv/testenv_notwin.go +++ b/src/internal/testenv/testenv_notwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package testenv diff --git a/src/log/syslog/example_test.go b/src/log/syslog/example_test.go index 4288d37dee..993976569e 100644 --- a/src/log/syslog/example_test.go +++ b/src/log/syslog/example_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 // +build !windows,!plan9 package syslog_test diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go index 97c10f31df..6abd4ad124 100644 --- a/src/log/syslog/syslog.go +++ b/src/log/syslog/syslog.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 // +build !windows,!plan9 package syslog diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go index 207bcf57c1..62c6250845 100644 --- a/src/log/syslog/syslog_test.go +++ b/src/log/syslog/syslog_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 && !js // +build !windows,!plan9,!js package syslog diff --git a/src/log/syslog/syslog_unix.go b/src/log/syslog/syslog_unix.go index a64eed29f1..2e45f0764f 100644 --- a/src/log/syslog/syslog_unix.go +++ b/src/log/syslog/syslog_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 // +build !windows,!plan9 package syslog diff --git a/src/math/big/arith_amd64.go b/src/math/big/arith_amd64.go index 1d2d37cf93..89108fe149 100644 --- a/src/math/big/arith_amd64.go +++ b/src/math/big/arith_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go package big diff --git a/src/math/big/arith_decl.go b/src/math/big/arith_decl.go index d519bdc87b..eea3d6b325 100644 --- a/src/math/big/arith_decl.go +++ b/src/math/big/arith_decl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go package big diff --git a/src/math/big/arith_decl_pure.go b/src/math/big/arith_decl_pure.go index 5faa3bd281..059f6f1325 100644 --- a/src/math/big/arith_decl_pure.go +++ b/src/math/big/arith_decl_pure.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build math_big_pure_go // +build math_big_pure_go package big diff --git a/src/math/big/arith_decl_s390x.go b/src/math/big/arith_decl_s390x.go index f1a69e1df0..4193f3231c 100644 --- a/src/math/big/arith_decl_s390x.go +++ b/src/math/big/arith_decl_s390x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !math_big_pure_go // +build !math_big_pure_go package big diff --git a/src/math/big/arith_s390x_test.go b/src/math/big/arith_s390x_test.go index ce6bca8885..8375ddbdd4 100644 --- a/src/math/big/arith_s390x_test.go +++ b/src/math/big/arith_s390x_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build s390x && !math_big_pure_go // +build s390x,!math_big_pure_go package big diff --git a/src/math/bits/bits_errors.go b/src/math/bits/bits_errors.go index 192b4bee00..61cb5c9457 100644 --- a/src/math/bits/bits_errors.go +++ b/src/math/bits/bits_errors.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !compiler_bootstrap // +build !compiler_bootstrap package bits diff --git a/src/math/bits/bits_errors_bootstrap.go b/src/math/bits/bits_errors_bootstrap.go index 5df5738848..4d610d33b8 100644 --- a/src/math/bits/bits_errors_bootstrap.go +++ b/src/math/bits/bits_errors_bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build compiler_bootstrap // +build compiler_bootstrap // This version used only for bootstrap (on this path we want diff --git a/src/math/bits/make_examples.go b/src/math/bits/make_examples.go index 1d3ad53fe6..ac4004df41 100644 --- a/src/math/bits/make_examples.go +++ b/src/math/bits/make_examples.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program generates example_test.go. diff --git a/src/math/bits/make_tables.go b/src/math/bits/make_tables.go index b068d5e0e3..5ab0b5fc57 100644 --- a/src/math/bits/make_tables.go +++ b/src/math/bits/make_tables.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program generates bits_tables.go. diff --git a/src/math/cmplx/huge_test.go b/src/math/cmplx/huge_test.go index f8e60c265f..78b42316de 100644 --- a/src/math/cmplx/huge_test.go +++ b/src/math/cmplx/huge_test.go @@ -5,6 +5,7 @@ // Disabled for s390x because it uses assembly routines that are not // accurate for huge arguments. +//go:build !s390x // +build !s390x package cmplx diff --git a/src/math/exp_asm.go b/src/math/exp_asm.go index 8dad3c810b..654ccce481 100644 --- a/src/math/exp_asm.go +++ b/src/math/exp_asm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 // +build amd64 package math diff --git a/src/math/huge_test.go b/src/math/huge_test.go index 9448edc339..ec81a4a31d 100644 --- a/src/math/huge_test.go +++ b/src/math/huge_test.go @@ -5,6 +5,7 @@ // Disabled for s390x because it uses assembly routines that are not // accurate for huge arguments. +//go:build !s390x // +build !s390x package math_test diff --git a/src/math/rand/gen_cooked.go b/src/math/rand/gen_cooked.go index 0afc10d727..7950e09fd7 100644 --- a/src/math/rand/gen_cooked.go +++ b/src/math/rand/gen_cooked.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program computes the value of rngCooked in rng.go, diff --git a/src/mime/type_unix.go b/src/mime/type_unix.go index 3a25002842..851d5a0fb0 100644 --- a/src/mime/type_unix.go +++ b/src/mime/type_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package mime diff --git a/src/net/addrselect.go b/src/net/addrselect.go index 7c0dfe261c..ae93c595af 100644 --- a/src/net/addrselect.go +++ b/src/net/addrselect.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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/addrselect_test.go b/src/net/addrselect_test.go index d6e0e63c3b..dc13917018 100644 --- a/src/net/addrselect_test.go +++ b/src/net/addrselect_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/cgo_aix.go b/src/net/cgo_aix.go index d0ad414a32..a94405ecc0 100644 --- a/src/net/cgo_aix.go +++ b/src/net/cgo_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/cgo_android.go b/src/net/cgo_android.go index ab0368d14b..4b1a2e3e1d 100644 --- a/src/net/cgo_android.go +++ b/src/net/cgo_android.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/cgo_bsd.go b/src/net/cgo_bsd.go index a923c556d3..23be72140b 100644 --- a/src/net/cgo_bsd.go +++ b/src/net/cgo_bsd.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (darwin || dragonfly || freebsd) +// +build cgo +// +build !netgo // +build darwin dragonfly freebsd package net diff --git a/src/net/cgo_linux.go b/src/net/cgo_linux.go index 86d8f4dc1e..1bd6be93f7 100644 --- a/src/net/cgo_linux.go +++ b/src/net/cgo_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !android && cgo && !netgo // +build !android,cgo,!netgo package net diff --git a/src/net/cgo_netbsd.go b/src/net/cgo_netbsd.go index 4610246561..3714793a52 100644 --- a/src/net/cgo_netbsd.go +++ b/src/net/cgo_netbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/cgo_openbsd.go b/src/net/cgo_openbsd.go index 4610246561..3714793a52 100644 --- a/src/net/cgo_openbsd.go +++ b/src/net/cgo_openbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/cgo_resnew.go b/src/net/cgo_resnew.go index 3e3e77e17d..154405270f 100644 --- a/src/net/cgo_resnew.go +++ b/src/net/cgo_resnew.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (darwin || (linux && !android) || netbsd || solaris) +// +build cgo +// +build !netgo // +build darwin linux,!android netbsd solaris package net diff --git a/src/net/cgo_resold.go b/src/net/cgo_resold.go index abd04a814d..c4aab33eaa 100644 --- a/src/net/cgo_resold.go +++ b/src/net/cgo_resold.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (android || freebsd || dragonfly || openbsd) +// +build cgo +// +build !netgo // +build android freebsd dragonfly openbsd package net diff --git a/src/net/cgo_socknew.go b/src/net/cgo_socknew.go index 3b13926107..f9cfad9909 100644 --- a/src/net/cgo_socknew.go +++ b/src/net/cgo_socknew.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (android || linux || solaris) +// +build cgo +// +build !netgo // +build android linux solaris package net diff --git a/src/net/cgo_sockold.go b/src/net/cgo_sockold.go index e1e642bb41..22c67252f5 100644 --- a/src/net/cgo_sockold.go +++ b/src/net/cgo_sockold.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || netbsd || openbsd) +// +build cgo +// +build !netgo // +build aix darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/cgo_solaris.go b/src/net/cgo_solaris.go index 25c0721242..a84f5b0d34 100644 --- a/src/net/cgo_solaris.go +++ b/src/net/cgo_solaris.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go index 041f8af129..039e4be88b 100644 --- a/src/net/cgo_stub.go +++ b/src/net/cgo_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !cgo || netgo // +build !cgo netgo package net diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index 69c99fe7db..2ea86e074f 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) +// +build cgo +// +build !netgo // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go index 99d79a60c4..1f3d9ea207 100644 --- a/src/net/cgo_unix_test.go +++ b/src/net/cgo_unix_test.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo,!netgo +//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) +// +build cgo +// +build !netgo // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/cgo_windows.go b/src/net/cgo_windows.go index 8968b757a9..1fd1f29787 100644 --- a/src/net/cgo_windows.go +++ b/src/net/cgo_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !netgo // +build cgo,!netgo package net diff --git a/src/net/conf.go b/src/net/conf.go index f1bbfedad0..6b9569cd92 100644 --- a/src/net/conf.go +++ b/src/net/conf.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/conf_netcgo.go b/src/net/conf_netcgo.go index db4c703b06..8f387ebc03 100644 --- a/src/net/conf_netcgo.go +++ b/src/net/conf_netcgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build netcgo // +build netcgo package net diff --git a/src/net/conf_test.go b/src/net/conf_test.go index 1fe3cf41b1..b1f2c55ea5 100644 --- a/src/net/conf_test.go +++ b/src/net/conf_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/conn_test.go b/src/net/conn_test.go index 771cabcd3c..45e271c264 100644 --- a/src/net/conn_test.go +++ b/src/net/conn_test.go @@ -5,6 +5,7 @@ // This file implements API tests across platforms and will never have a build // tag. +//go:build !js // +build !js package net diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 57cf5554ad..394bdb047e 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/dial_unix_test.go b/src/net/dial_unix_test.go index 3cfc9d81b8..108b973099 100644 --- a/src/net/dial_unix_test.go +++ b/src/net/dial_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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 d7db0c8133..a3242ff3b2 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // DNS client: see RFC 1035. diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 0530c92c2e..b47b83af15 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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 877e77c049..db9213a13f 100644 --- a/src/net/dnsconfig_unix.go +++ b/src/net/dnsconfig_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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 0d7897a813..0e2317c469 100644 --- a/src/net/dnsconfig_unix_test.go +++ b/src/net/dnsconfig_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go index 2964982311..d851bf7566 100644 --- a/src/net/dnsname_test.go +++ b/src/net/dnsname_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/error_posix.go b/src/net/error_posix.go index d709a273b7..50eb66fc61 100644 --- a/src/net/error_posix.go +++ b/src/net/error_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go index b411a378df..ea52a45ee8 100644 --- a/src/net/error_posix_test.go +++ b/src/net/error_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package net diff --git a/src/net/error_test.go b/src/net/error_test.go index 556eb8c8d4..c304390819 100644 --- a/src/net/error_test.go +++ b/src/net/error_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/error_unix.go b/src/net/error_unix.go index e615330388..d0b5e2ce96 100644 --- a/src/net/error_unix.go +++ b/src/net/error_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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/error_unix_test.go b/src/net/error_unix_test.go index 9ce9e12c5e..533a45e648 100644 --- a/src/net/error_unix_test.go +++ b/src/net/error_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 && !windows // +build !plan9,!windows package net diff --git a/src/net/external_test.go b/src/net/external_test.go index f3c69c407f..b8753cc092 100644 --- a/src/net/external_test.go +++ b/src/net/external_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go index 53abd152c7..2945e46a48 100644 --- a/src/net/fd_posix.go +++ b/src/net/fd_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go index 1c9bba3b19..a7bbdd26b4 100644 --- a/src/net/fd_unix.go +++ b/src/net/fd_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/file_stub.go b/src/net/file_stub.go index bfb8100f53..9f988fe899 100644 --- a/src/net/file_stub.go +++ b/src/net/file_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/file_test.go b/src/net/file_test.go index 8c09c0da1b..a70ef1b312 100644 --- a/src/net/file_test.go +++ b/src/net/file_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/file_unix.go b/src/net/file_unix.go index dba69554ca..4520d4b839 100644 --- a/src/net/file_unix.go +++ b/src/net/file_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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 a28f1e066d..b9153d1947 100644 --- a/src/net/hook_unix.go +++ b/src/net/hook_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package net diff --git a/src/net/http/cgi/plan9_test.go b/src/net/http/cgi/plan9_test.go index cc20fe03e4..f998bac6ea 100644 --- a/src/net/http/cgi/plan9_test.go +++ b/src/net/http/cgi/plan9_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package cgi diff --git a/src/net/http/cgi/posix_test.go b/src/net/http/cgi/posix_test.go index 9396ce036a..bc58ea94cc 100644 --- a/src/net/http/cgi/posix_test.go +++ b/src/net/http/cgi/posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package cgi diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 6bef310feb..0379848e70 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1,3 +1,4 @@ +//go:build !nethttpomithttp2 // +build !nethttpomithttp2 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. diff --git a/src/net/http/omithttp2.go b/src/net/http/omithttp2.go index 30c6e48cfc..79599d006a 100644 --- a/src/net/http/omithttp2.go +++ b/src/net/http/omithttp2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build nethttpomithttp2 // +build nethttpomithttp2 package http diff --git a/src/net/http/roundtrip.go b/src/net/http/roundtrip.go index 2ec736bfb1..eef7c79293 100644 --- a/src/net/http/roundtrip.go +++ b/src/net/http/roundtrip.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js || !wasm // +build !js !wasm package http diff --git a/src/net/http/roundtrip_js.go b/src/net/http/roundtrip_js.go index c6a221ac62..74c83a9172 100644 --- a/src/net/http/roundtrip_js.go +++ b/src/net/http/roundtrip_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package http diff --git a/src/net/http/triv.go b/src/net/http/triv.go index 23e65d56e8..4dc62407c6 100644 --- a/src/net/http/triv.go +++ b/src/net/http/triv.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index d791cb3016..7578b1a16a 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/interface_bsd_test.go b/src/net/interface_bsd_test.go index 947dde71e6..8d0d9c3671 100644 --- a/src/net/interface_bsd_test.go +++ b/src/net/interface_bsd_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/interface_bsdvar.go b/src/net/interface_bsdvar.go index a809b5f5ce..6230e0bfee 100644 --- a/src/net/interface_bsdvar.go +++ b/src/net/interface_bsdvar.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || netbsd || openbsd // +build dragonfly netbsd openbsd package net diff --git a/src/net/interface_stub.go b/src/net/interface_stub.go index ec58665e19..efe67c24d3 100644 --- a/src/net/interface_stub.go +++ b/src/net/interface_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/interface_test.go b/src/net/interface_test.go index b2ef21e8ac..754db36e3c 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go index bf41a0fb82..0d69fa5da4 100644 --- a/src/net/interface_unix_test.go +++ b/src/net/interface_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package net diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go index 3b0a48aef4..8af85d382e 100644 --- a/src/net/internal/socktest/main_test.go +++ b/src/net/internal/socktest/main_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 // +build !js,!plan9 package socktest_test diff --git a/src/net/internal/socktest/main_unix_test.go b/src/net/internal/socktest/main_unix_test.go index 4d9d414356..6aa8875b66 100644 --- a/src/net/internal/socktest/main_unix_test.go +++ b/src/net/internal/socktest/main_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 && !windows // +build !js,!plan9,!windows package socktest_test diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go index 863edef0d3..cda74e8639 100644 --- a/src/net/internal/socktest/switch_posix.go +++ b/src/net/internal/socktest/switch_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package socktest diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go index 28ce72cb85..5aa2ecec08 100644 --- a/src/net/internal/socktest/switch_stub.go +++ b/src/net/internal/socktest/switch_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package socktest diff --git a/src/net/internal/socktest/switch_unix.go b/src/net/internal/socktest/switch_unix.go index 7dc3518410..bfe9d4dbd3 100644 --- a/src/net/internal/socktest/switch_unix.go +++ b/src/net/internal/socktest/switch_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package socktest diff --git a/src/net/internal/socktest/sys_cloexec.go b/src/net/internal/socktest/sys_cloexec.go index 421352c7b4..c7f8331c2e 100644 --- a/src/net/internal/socktest/sys_cloexec.go +++ b/src/net/internal/socktest/sys_cloexec.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd illumos linux netbsd openbsd package socktest diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go index 0525512bff..e7cc45922e 100644 --- a/src/net/internal/socktest/sys_unix.go +++ b/src/net/internal/socktest/sys_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package socktest diff --git a/src/net/ip_test.go b/src/net/ip_test.go index a5fc5e644a..1e09ae9db4 100644 --- a/src/net/ip_test.go +++ b/src/net/ip_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go index e653f6ae17..c1514f1698 100644 --- a/src/net/iprawsock_posix.go +++ b/src/net/iprawsock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/iprawsock_test.go b/src/net/iprawsock_test.go index 8e3543dfc7..a96448ee6c 100644 --- a/src/net/iprawsock_test.go +++ b/src/net/iprawsock_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go index 8763d579fb..8d8a896501 100644 --- a/src/net/ipsock_posix.go +++ b/src/net/ipsock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/listen_test.go b/src/net/listen_test.go index d8c72096ed..b1dce29ac2 100644 --- a/src/net/listen_test.go +++ b/src/net/listen_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 // +build !js,!plan9 package net diff --git a/src/net/lookup_fake.go b/src/net/lookup_fake.go index 3b3c39bc7d..f4fcaed5cf 100644 --- a/src/net/lookup_fake.go +++ b/src/net/lookup_fake.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 32a0d377da..3faaf00710 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index 9055826d40..c09afb300f 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/main_cloexec_test.go b/src/net/main_cloexec_test.go index 46b9ba5008..742be2fcd8 100644 --- a/src/net/main_cloexec_test.go +++ b/src/net/main_cloexec_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd illumos linux netbsd openbsd package net diff --git a/src/net/main_conf_test.go b/src/net/main_conf_test.go index a92dff56c2..645b267b78 100644 --- a/src/net/main_conf_test.go +++ b/src/net/main_conf_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 && !windows // +build !js,!plan9,!windows package net diff --git a/src/net/main_noconf_test.go b/src/net/main_noconf_test.go index bac84aa300..bcea630cd3 100644 --- a/src/net/main_noconf_test.go +++ b/src/net/main_noconf_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (js && wasm) || plan9 || windows // +build js,wasm plan9 windows package net diff --git a/src/net/main_posix_test.go b/src/net/main_posix_test.go index f2484f306d..c9ab25a4ad 100644 --- a/src/net/main_posix_test.go +++ b/src/net/main_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 // +build !js,!plan9 package net diff --git a/src/net/main_test.go b/src/net/main_test.go index 2d5be2ee5f..dc17d3fbb8 100644 --- a/src/net/main_test.go +++ b/src/net/main_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go index 8b9897699c..c8cff2d305 100644 --- a/src/net/main_unix_test.go +++ b/src/net/main_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go index 867e31e9ae..b50a1e59a1 100644 --- a/src/net/mockserver_test.go +++ b/src/net/mockserver_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/net_fake.go b/src/net/net_fake.go index 0c48dd5c03..49dc57c6ff 100644 --- a/src/net/net_fake.go +++ b/src/net/net_fake.go @@ -4,6 +4,7 @@ // Fake networking for js/wasm. It is intended to allow tests of other package to pass. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/net_test.go b/src/net/net_test.go index 409e1400af..6d6299e74a 100644 --- a/src/net/net_test.go +++ b/src/net/net_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go index c672d3e8eb..0dfd6c2cd7 100644 --- a/src/net/netgo_unix_test.go +++ b/src/net/netgo_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (!cgo || netgo) && (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) // +build !cgo netgo // +build darwin dragonfly freebsd linux netbsd openbsd solaris diff --git a/src/net/nss.go b/src/net/nss.go index 96b9cdd121..85177cab9b 100644 --- a/src/net/nss.go +++ b/src/net/nss.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/nss_test.go b/src/net/nss_test.go index 371deb502d..4b73886c51 100644 --- a/src/net/nss_test.go +++ b/src/net/nss_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go index a377d333d6..aeb9845fa7 100644 --- a/src/net/packetconn_test.go +++ b/src/net/packetconn_test.go @@ -5,6 +5,7 @@ // This file implements API tests across platforms and will never have a build // tag. +//go:build !js // +build !js package net diff --git a/src/net/port_unix.go b/src/net/port_unix.go index 4fdd9a37bc..a9a96a2323 100644 --- a/src/net/port_unix.go +++ b/src/net/port_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris // Read system port mappings from /etc/services diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go index 6f83f52681..fc9b386256 100644 --- a/src/net/protoconn_test.go +++ b/src/net/protoconn_test.go @@ -5,6 +5,7 @@ // This file implements API tests across platforms and will never have a build // tag. +//go:build !js // +build !js package net diff --git a/src/net/rawconn_stub_test.go b/src/net/rawconn_stub_test.go index cec977f75d..975aa8d956 100644 --- a/src/net/rawconn_stub_test.go +++ b/src/net/rawconn_stub_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (js && wasm) || plan9 // +build js,wasm plan9 package net diff --git a/src/net/rawconn_test.go b/src/net/rawconn_test.go index a08ff89d1a..3ef7af33b7 100644 --- a/src/net/rawconn_test.go +++ b/src/net/rawconn_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/rawconn_unix_test.go b/src/net/rawconn_unix_test.go index 0194ba67c8..75bbab8b27 100644 --- a/src/net/rawconn_unix_test.go +++ b/src/net/rawconn_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go index 53bc53af43..5753bc0289 100644 --- a/src/net/sendfile_stub.go +++ b/src/net/sendfile_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || (js && wasm) || netbsd || openbsd // +build aix darwin js,wasm netbsd openbsd package net diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index d6057fd839..db72daa328 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/sendfile_unix_alt.go b/src/net/sendfile_unix_alt.go index 8cededce58..54667d672f 100644 --- a/src/net/sendfile_unix_alt.go +++ b/src/net/sendfile_unix_alt.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || solaris // +build dragonfly freebsd solaris package net diff --git a/src/net/server_test.go b/src/net/server_test.go index 4ac5443e6a..8d4db7233d 100644 --- a/src/net/server_test.go +++ b/src/net/server_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/sock_bsd.go b/src/net/sock_bsd.go index 73fb6be814..4c883ada78 100644 --- a/src/net/sock_bsd.go +++ b/src/net/sock_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go index 5f345f0f4a..efc91fdb53 100644 --- a/src/net/sock_cloexec.go +++ b/src/net/sock_cloexec.go @@ -5,6 +5,7 @@ // This file implements sysSocket and accept for platforms that // provide a fast path for setting SetNonblock and CloseOnExec. +//go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build dragonfly freebsd illumos linux netbsd openbsd package net diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go index 80b4169ec6..9b1e7880ae 100644 --- a/src/net/sock_posix.go +++ b/src/net/sock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/sock_stub.go b/src/net/sock_stub.go index c9f86af4e7..d804bfaacc 100644 --- a/src/net/sock_stub.go +++ b/src/net/sock_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || (js && wasm) || solaris // +build aix js,wasm solaris package net diff --git a/src/net/sockaddr_posix.go b/src/net/sockaddr_posix.go index a3710dd3f7..9d77cb569b 100644 --- a/src/net/sockaddr_posix.go +++ b/src/net/sockaddr_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go index 8fd1e882c6..216e5d52f1 100644 --- a/src/net/sockopt_bsd.go +++ b/src/net/sockopt_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go index de7255667f..50b9bfa0a7 100644 --- a/src/net/sockopt_posix.go +++ b/src/net/sockopt_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/sockopt_stub.go b/src/net/sockopt_stub.go index 52624a35d8..99b5277ed0 100644 --- a/src/net/sockopt_stub.go +++ b/src/net/sockopt_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/sockoptip_bsdvar.go b/src/net/sockoptip_bsdvar.go index 20a6dc9549..56022fd1a5 100644 --- a/src/net/sockoptip_bsdvar.go +++ b/src/net/sockoptip_bsdvar.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd netbsd openbsd solaris package net diff --git a/src/net/sockoptip_posix.go b/src/net/sockoptip_posix.go index b14963ff32..a2143aec2c 100644 --- a/src/net/sockoptip_posix.go +++ b/src/net/sockoptip_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/sockoptip_stub.go b/src/net/sockoptip_stub.go index 57cd289040..4175922cec 100644 --- a/src/net/sockoptip_stub.go +++ b/src/net/sockoptip_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/splice_stub.go b/src/net/splice_stub.go index 9106cb2c18..ce2e9046a9 100644 --- a/src/net/splice_stub.go +++ b/src/net/splice_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package net diff --git a/src/net/splice_test.go b/src/net/splice_test.go index 8a0cda6564..be13cc924d 100644 --- a/src/net/splice_test.go +++ b/src/net/splice_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package net diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go index 967b8bea9d..4d7112051f 100644 --- a/src/net/sys_cloexec.go +++ b/src/net/sys_cloexec.go @@ -5,6 +5,7 @@ // This file implements sysSocket and accept for platforms that do not // provide a fast path for setting SetNonblock and CloseOnExec. +//go:build aix || darwin || (solaris && !illumos) // +build aix darwin solaris,!illumos package net diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go index 257c11976f..7c4523c5ee 100644 --- a/src/net/tcpsock_posix.go +++ b/src/net/tcpsock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go index d6172bc503..9c9f1eae93 100644 --- a/src/net/tcpsock_test.go +++ b/src/net/tcpsock_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/tcpsock_unix_test.go b/src/net/tcpsock_unix_test.go index 2bd591b594..41bd229132 100644 --- a/src/net/tcpsock_unix_test.go +++ b/src/net/tcpsock_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 && !windows // +build !js,!plan9,!windows package net diff --git a/src/net/tcpsockopt_posix.go b/src/net/tcpsockopt_posix.go index 5e00ba1564..d08832adc0 100644 --- a/src/net/tcpsockopt_posix.go +++ b/src/net/tcpsockopt_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/tcpsockopt_stub.go b/src/net/tcpsockopt_stub.go index d043da123d..028d5fd29c 100644 --- a/src/net/tcpsockopt_stub.go +++ b/src/net/tcpsockopt_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package net diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go index fb0ecb8dc7..a945889e00 100644 --- a/src/net/tcpsockopt_unix.go +++ b/src/net/tcpsockopt_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || freebsd || linux || netbsd // +build aix freebsd linux netbsd package net diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go index 205aaa430b..e1cf1467c3 100644 --- a/src/net/timeout_test.go +++ b/src/net/timeout_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go index bbfa4ed9c7..58c69f18ad 100644 --- a/src/net/udpsock_posix.go +++ b/src/net/udpsock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go index 327eba6541..7a1ed4eb18 100644 --- a/src/net/udpsock_test.go +++ b/src/net/udpsock_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go index 275c7c936d..1d1f27449f 100644 --- a/src/net/unixsock_posix.go +++ b/src/net/unixsock_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package net diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go index 0b13bf655f..71092e88fb 100644 --- a/src/net/unixsock_test.go +++ b/src/net/unixsock_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js && !plan9 && !windows // +build !js,!plan9,!windows package net diff --git a/src/net/unixsock_windows_test.go b/src/net/unixsock_windows_test.go index 5dccc14653..29244f6471 100644 --- a/src/net/unixsock_windows_test.go +++ b/src/net/unixsock_windows_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package net diff --git a/src/net/write_unix_test.go b/src/net/write_unix_test.go index 6d8cb6a6f8..f79f2d0865 100644 --- a/src/net/write_unix_test.go +++ b/src/net/write_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/writev_test.go b/src/net/writev_test.go index d603b7f70a..bf40ca2023 100644 --- a/src/net/writev_test.go +++ b/src/net/writev_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package net diff --git a/src/net/writev_unix.go b/src/net/writev_unix.go index 8b20f42b34..a0fedc2f99 100644 --- a/src/net/writev_unix.go +++ b/src/net/writev_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd // +build darwin dragonfly freebsd illumos linux netbsd openbsd package net diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go index 0e1eab1c96..ef5c00aee0 100644 --- a/src/os/dir_unix.go +++ b/src/os/dir_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/endian_big.go b/src/os/endian_big.go index c98f124782..0529dccd6f 100644 --- a/src/os/endian_big.go +++ b/src/os/endian_big.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +//go:build ppc64 || s390x || mips || mips64 // +build ppc64 s390x mips mips64 package os diff --git a/src/os/endian_little.go b/src/os/endian_little.go index 3efc5e0d8d..6be6020f53 100644 --- a/src/os/endian_little.go +++ b/src/os/endian_little.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +//go:build 386 || amd64 || arm || arm64 || ppc64le || mips64le || mipsle || riscv64 || wasm // +build 386 amd64 arm arm64 ppc64le mips64le mipsle riscv64 wasm package os diff --git a/src/os/env_unix_test.go b/src/os/env_unix_test.go index 89430b3e20..d45e1deb83 100644 --- a/src/os/env_unix_test.go +++ b/src/os/env_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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_errno.go b/src/os/error_errno.go index 31ae05a21e..580e915b73 100644 --- a/src/os/error_errno.go +++ b/src/os/error_errno.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package os diff --git a/src/os/error_posix.go b/src/os/error_posix.go index 2aeca82304..268b3a923a 100644 --- a/src/os/error_posix.go +++ b/src/os/error_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package os diff --git a/src/os/error_unix_test.go b/src/os/error_unix_test.go index 18bcf3f4e4..e45282a0fd 100644 --- a/src/os/error_unix_test.go +++ b/src/os/error_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os_test diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go index b8191c5ebc..aa0c14b7d4 100644 --- a/src/os/error_windows_test.go +++ b/src/os/error_windows_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package os_test diff --git a/src/os/exec/exec_linux_test.go b/src/os/exec/exec_linux_test.go index 6f850204d6..3cfa30ee72 100644 --- a/src/os/exec/exec_linux_test.go +++ b/src/os/exec/exec_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && cgo // +build linux,cgo // On systems that use glibc, calling malloc can create a new arena, diff --git a/src/os/exec/exec_posix_test.go b/src/os/exec/exec_posix_test.go index d4d67ac933..7b2c0c0c11 100644 --- a/src/os/exec/exec_posix_test.go +++ b/src/os/exec/exec_posix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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/exec_unix.go b/src/os/exec/exec_unix.go index 51c52427c2..467c069e1c 100644 --- a/src/os/exec/exec_unix.go +++ b/src/os/exec/exec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 && !windows // +build !plan9,!windows package exec diff --git a/src/os/exec/lp_js.go b/src/os/exec/lp_js.go index 6750fb99b0..4eac25fe6f 100644 --- a/src/os/exec/lp_js.go +++ b/src/os/exec/lp_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package exec diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go index 66c1df76fb..d1d246accf 100644 --- a/src/os/exec/lp_unix.go +++ b/src/os/exec/lp_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package exec diff --git a/src/os/exec/lp_unix_test.go b/src/os/exec/lp_unix_test.go index 296480fd04..75bcdb1fdd 100644 --- a/src/os/exec/lp_unix_test.go +++ b/src/os/exec/lp_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package exec diff --git a/src/os/exec/read3.go b/src/os/exec/read3.go index 8cc24da8cb..a8c71831d8 100644 --- a/src/os/exec/read3.go +++ b/src/os/exec/read3.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This is a test program that verifies that it can read from diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go index 8aa1e5e499..443d4e0218 100644 --- a/src/os/exec_posix.go +++ b/src/os/exec_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package os diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index a1703a1259..d1bbeb7529 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/exec_unix_test.go b/src/os/exec_unix_test.go index d942cdb5e5..f14b3519fb 100644 --- a/src/os/exec_unix_test.go +++ b/src/os/exec_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package os_test diff --git a/src/os/executable_path.go b/src/os/executable_path.go index 7b8b83652c..625430ecfc 100644 --- a/src/os/executable_path.go +++ b/src/os/executable_path.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || openbsd // +build aix openbsd package os diff --git a/src/os/executable_plan9.go b/src/os/executable_plan9.go index a5947eaae1..105c03f0c1 100644 --- a/src/os/executable_plan9.go +++ b/src/os/executable_plan9.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package os diff --git a/src/os/executable_procfs.go b/src/os/executable_procfs.go index 5ee41a4b2e..9c64a0d474 100644 --- a/src/os/executable_procfs.go +++ b/src/os/executable_procfs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux || netbsd || (js && wasm) // +build linux netbsd js,wasm package os diff --git a/src/os/executable_sysctl.go b/src/os/executable_sysctl.go index f9a4b18f60..039448b557 100644 --- a/src/os/executable_sysctl.go +++ b/src/os/executable_sysctl.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || dragonfly // +build freebsd dragonfly package os diff --git a/src/os/export_unix_test.go b/src/os/export_unix_test.go index 39866a68de..10f8312831 100644 --- a/src/os/export_unix_test.go +++ b/src/os/export_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/fifo_test.go b/src/os/fifo_test.go index 2439192a9d..c3607344ec 100644 --- a/src/os/fifo_test.go +++ b/src/os/fifo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package os_test diff --git a/src/os/file_posix.go b/src/os/file_posix.go index 795c547856..211f2a1798 100644 --- a/src/os/file_posix.go +++ b/src/os/file_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package os diff --git a/src/os/file_unix.go b/src/os/file_unix.go index f88450018e..e8b286c9ee 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go index 51693fd82a..9b4c0ab290 100644 --- a/src/os/os_unix_test.go +++ b/src/os/os_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os_test diff --git a/src/os/path_unix.go b/src/os/path_unix.go index c99a8240c5..db38359492 100644 --- a/src/os/path_unix.go +++ b/src/os/path_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/pipe2_bsd.go b/src/os/pipe2_bsd.go index 0ef894b476..0af8019525 100644 --- a/src/os/pipe2_bsd.go +++ b/src/os/pipe2_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || netbsd || openbsd // +build freebsd netbsd openbsd package os diff --git a/src/os/pipe2_illumos.go b/src/os/pipe2_illumos.go index 026ce62b9a..71b8cb8e25 100644 --- a/src/os/pipe2_illumos.go +++ b/src/os/pipe2_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos package os diff --git a/src/os/pipe_bsd.go b/src/os/pipe_bsd.go index 115d6baa19..57959a2ea4 100644 --- a/src/os/pipe_bsd.go +++ b/src/os/pipe_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || (js && wasm) || (solaris && !illumos) // +build aix darwin dragonfly js,wasm solaris,!illumos package os diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index b98e53845c..b663618502 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Test broken pipes on Unix systems. +//go:build !plan9 && !js // +build !plan9,!js package os_test diff --git a/src/os/rawconn.go b/src/os/rawconn.go index 9e11cda8c9..ffc598b061 100644 --- a/src/os/rawconn.go +++ b/src/os/rawconn.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 // +build !plan9 package os diff --git a/src/os/rawconn_test.go b/src/os/rawconn_test.go index 2554f5b087..8aebaf87a6 100644 --- a/src/os/rawconn_test.go +++ b/src/os/rawconn_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Test use of raw connections. +//go:build !plan9 && !js // +build !plan9,!js package os_test diff --git a/src/os/readfrom_stub.go b/src/os/readfrom_stub.go index 65429d0cab..826760f3df 100644 --- a/src/os/readfrom_stub.go +++ b/src/os/readfrom_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package os diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go index c1a1b726af..d04540bc63 100644 --- a/src/os/removeall_at.go +++ b/src/os/removeall_at.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package os diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go index 7c888baaa9..853e0eddfc 100644 --- a/src/os/removeall_noat.go +++ b/src/os/removeall_noat.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris // +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris package os diff --git a/src/os/signal/example_unix_test.go b/src/os/signal/example_unix_test.go index a0af37a5bb..3f7795b8cf 100644 --- a/src/os/signal/example_unix_test.go +++ b/src/os/signal/example_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package signal_test diff --git a/src/os/signal/internal/pty/pty.go b/src/os/signal/internal/pty/pty.go index f8813ce6be..8d2eac7103 100644 --- a/src/os/signal/internal/pty/pty.go +++ b/src/os/signal/internal/pty/pty.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo // +build aix darwin dragonfly freebsd linux,!android netbsd openbsd // +build cgo diff --git a/src/os/signal/signal_cgo_test.go b/src/os/signal/signal_cgo_test.go index a8a485613f..e1e4509e2a 100644 --- a/src/os/signal/signal_cgo_test.go +++ b/src/os/signal/signal_cgo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo // +build darwin dragonfly freebsd linux,!android netbsd openbsd // +build cgo diff --git a/src/os/signal/signal_linux_test.go b/src/os/signal/signal_linux_test.go index 2e553d0b0f..7abe1ec5a0 100644 --- a/src/os/signal/signal_linux_test.go +++ b/src/os/signal/signal_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package signal diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index bbc68af9fb..292d24c6f1 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || 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 90a1eca156..9e241c43ac 100644 --- a/src/os/signal/signal_unix.go +++ b/src/os/signal/signal_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package signal diff --git a/src/os/stat_js.go b/src/os/stat_js.go index 8d20ccddfc..3badf5ba57 100644 --- a/src/os/stat_js.go +++ b/src/os/stat_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package os diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go index 66c356fc62..8c17805f71 100644 --- a/src/os/stat_unix.go +++ b/src/os/stat_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package os diff --git a/src/os/sticky_bsd.go b/src/os/sticky_bsd.go index c09b1ac202..ab23d8111d 100644 --- a/src/os/sticky_bsd.go +++ b/src/os/sticky_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm netbsd openbsd solaris package os diff --git a/src/os/sticky_notbsd.go b/src/os/sticky_notbsd.go index c15850692c..9979b43e8e 100644 --- a/src/os/sticky_notbsd.go +++ b/src/os/sticky_notbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !dragonfly && !freebsd && (!js || !wasm) && !netbsd && !openbsd && !solaris // +build !aix // +build !darwin // +build !dragonfly diff --git a/src/os/sys_bsd.go b/src/os/sys_bsd.go index b1698f5d4c..1e245eb53a 100644 --- a/src/os/sys_bsd.go +++ b/src/os/sys_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd // +build darwin dragonfly freebsd js,wasm netbsd openbsd package os diff --git a/src/os/sys_js.go b/src/os/sys_js.go index e860654f81..4d6a64e8eb 100644 --- a/src/os/sys_js.go +++ b/src/os/sys_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package os diff --git a/src/os/sys_unix.go b/src/os/sys_unix.go index 8491bad242..e316eaf06c 100644 --- a/src/os/sys_unix.go +++ b/src/os/sys_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package os diff --git a/src/os/timeout_test.go b/src/os/timeout_test.go index 0a39f46333..6d65e420f0 100644 --- a/src/os/timeout_test.go +++ b/src/os/timeout_test.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !js -// +build !plan9 -// +build !windows +//go:build !js && !plan9 && !windows +// +build !js,!plan9,!windows package os_test diff --git a/src/os/types_unix.go b/src/os/types_unix.go index c0259ae0e8..e9b8b8ba3a 100644 --- a/src/os/types_unix.go +++ b/src/os/types_unix.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows -// +build !plan9 +//go:build !windows && !plan9 +// +build !windows,!plan9 package os diff --git a/src/os/user/cgo_lookup_unix.go b/src/os/user/cgo_lookup_unix.go index 3307f790ea..abc9e9ce6d 100644 --- a/src/os/user/cgo_lookup_unix.go +++ b/src/os/user/cgo_lookup_unix.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo // +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/src/os/user/cgo_unix_test.go b/src/os/user/cgo_unix_test.go index 1d341aa427..9ec32b3a78 100644 --- a/src/os/user/cgo_unix_test.go +++ b/src/os/user/cgo_unix_test.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo // +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/src/os/user/getgrouplist_darwin.go b/src/os/user/getgrouplist_darwin.go index e8fe26c47f..23d12e3247 100644 --- a/src/os/user/getgrouplist_darwin.go +++ b/src/os/user/getgrouplist_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !osusergo // +build cgo,!osusergo package user diff --git a/src/os/user/getgrouplist_unix.go b/src/os/user/getgrouplist_unix.go index 9685414fc0..8393c5a474 100644 --- a/src/os/user/getgrouplist_unix.go +++ b/src/os/user/getgrouplist_unix.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (dragonfly || freebsd || (!android && linux) || netbsd || openbsd) && cgo && !osusergo // +build dragonfly freebsd !android,linux netbsd openbsd -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/src/os/user/listgroups_aix.go b/src/os/user/listgroups_aix.go index 17de3e98d4..d2fdfdc6b1 100644 --- a/src/os/user/listgroups_aix.go +++ b/src/os/user/listgroups_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !osusergo // +build cgo,!osusergo package user diff --git a/src/os/user/listgroups_solaris.go b/src/os/user/listgroups_solaris.go index f3cbf6ce4a..d993d30570 100644 --- a/src/os/user/listgroups_solaris.go +++ b/src/os/user/listgroups_solaris.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo && !osusergo // +build cgo,!osusergo // Even though this file requires no C, it is used to provide a diff --git a/src/os/user/listgroups_unix.go b/src/os/user/listgroups_unix.go index 70f7af7f97..c7b72062d5 100644 --- a/src/os/user/listgroups_unix.go +++ b/src/os/user/listgroups_unix.go @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (dragonfly || darwin || freebsd || (!android && linux) || netbsd || openbsd) && cgo && !osusergo // +build dragonfly darwin freebsd !android,linux netbsd openbsd -// +build cgo,!osusergo +// +build cgo +// +build !osusergo package user diff --git a/src/os/user/lookup_android.go b/src/os/user/lookup_android.go index 8ca30b8c27..151aab49c2 100644 --- a/src/os/user/lookup_android.go +++ b/src/os/user/lookup_android.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build android // +build android package user diff --git a/src/os/user/lookup_stubs.go b/src/os/user/lookup_stubs.go index 178d814dda..c975a11964 100644 --- a/src/os/user/lookup_stubs.go +++ b/src/os/user/lookup_stubs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (!cgo && !windows && !plan9) || android || (osusergo && !windows && !plan9) // +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9 package user diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go index 0890cd8f2b..ed8c2dee9d 100644 --- a/src/os/user/lookup_unix.go +++ b/src/os/user/lookup_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo) // +build aix darwin dragonfly freebsd js,wasm !android,linux netbsd openbsd solaris // +build !cgo osusergo diff --git a/src/os/user/lookup_unix_test.go b/src/os/user/lookup_unix_test.go index 72d3b47534..c697802171 100644 --- a/src/os/user/lookup_unix_test.go +++ b/src/os/user/lookup_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && !cgo // +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris // +build !cgo diff --git a/src/os/wait_unimp.go b/src/os/wait_unimp.go index 0f4cdc4533..28dc2a5939 100644 --- a/src/os/wait_unimp.go +++ b/src/os/wait_unimp.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || (js && wasm) || netbsd || openbsd || solaris // +build aix darwin dragonfly js,wasm netbsd openbsd solaris package os diff --git a/src/os/wait_wait6.go b/src/os/wait_wait6.go index 5420b2db73..895f21069a 100644 --- a/src/os/wait_wait6.go +++ b/src/os/wait_wait6.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd // +build freebsd package os diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go index 9c56eb2d41..1f3cb1cfe2 100644 --- a/src/os/wait_waitid.go +++ b/src/os/wait_waitid.go @@ -5,6 +5,7 @@ // We used to used this code for Darwin, but according to issue #19314 // waitid returns if the process is stopped, even when using WEXITED. +//go:build linux // +build linux package os diff --git a/src/path/filepath/example_unix_test.go b/src/path/filepath/example_unix_test.go index c9d6944518..4ce10095e6 100644 --- a/src/path/filepath/example_unix_test.go +++ b/src/path/filepath/example_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 // +build !windows,!plan9 package filepath_test diff --git a/src/path/filepath/example_unix_walk_test.go b/src/path/filepath/example_unix_walk_test.go index c8a818fd6e..d72efcebe6 100644 --- a/src/path/filepath/example_unix_walk_test.go +++ b/src/path/filepath/example_unix_walk_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows && !plan9 // +build !windows,!plan9 package filepath_test diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go index ec497d9e26..d4b6f967a3 100644 --- a/src/path/filepath/path_unix.go +++ b/src/path/filepath/path_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package filepath diff --git a/src/path/filepath/symlink_unix.go b/src/path/filepath/symlink_unix.go index d20e63a987..657945a81a 100644 --- a/src/path/filepath/symlink_unix.go +++ b/src/path/filepath/symlink_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package filepath diff --git a/src/plugin/plugin_dlopen.go b/src/plugin/plugin_dlopen.go index 9200fdc3cb..aa85d4831c 100644 --- a/src/plugin/plugin_dlopen.go +++ b/src/plugin/plugin_dlopen.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux && cgo) || (darwin && cgo) || (freebsd && cgo) // +build linux,cgo darwin,cgo freebsd,cgo package plugin diff --git a/src/plugin/plugin_stubs.go b/src/plugin/plugin_stubs.go index 1893203017..67855bed4b 100644 --- a/src/plugin/plugin_stubs.go +++ b/src/plugin/plugin_stubs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (!linux && !freebsd && !darwin) || !cgo // +build !linux,!freebsd,!darwin !cgo package plugin diff --git a/src/plugin/plugin_test.go b/src/plugin/plugin_test.go index 30b79edaad..4ce912132c 100644 --- a/src/plugin/plugin_test.go +++ b/src/plugin/plugin_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux || (linux && !arm64) // +build !linux linux,!arm64 package plugin_test diff --git a/src/regexp/exec2_test.go b/src/regexp/exec2_test.go index 7b86b41156..6444bc12f9 100644 --- a/src/regexp/exec2_test.go +++ b/src/regexp/exec2_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !race // +build !race package regexp diff --git a/src/runtime/auxv_none.go b/src/runtime/auxv_none.go index 3ca617b21e..3178f1a154 100644 --- a/src/runtime/auxv_none.go +++ b/src/runtime/auxv_none.go @@ -2,12 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !linux -// +build !darwin -// +build !dragonfly -// +build !freebsd -// +build !netbsd -// +build !solaris +//go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !solaris +// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!solaris package runtime diff --git a/src/runtime/cgo/callbacks_traceback.go b/src/runtime/cgo/callbacks_traceback.go index cdadf9e66f..7302c1eedf 100644 --- a/src/runtime/cgo/callbacks_traceback.go +++ b/src/runtime/cgo/callbacks_traceback.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || linux // +build darwin linux package cgo diff --git a/src/runtime/cgo/dragonfly.go b/src/runtime/cgo/dragonfly.go index d6d69187b8..cfa6fe86e2 100644 --- a/src/runtime/cgo/dragonfly.go +++ b/src/runtime/cgo/dragonfly.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly // +build dragonfly package cgo diff --git a/src/runtime/cgo/freebsd.go b/src/runtime/cgo/freebsd.go index 5c9ddbdc71..d56702ec70 100644 --- a/src/runtime/cgo/freebsd.go +++ b/src/runtime/cgo/freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd // +build freebsd package cgo diff --git a/src/runtime/cgo/linux.go b/src/runtime/cgo/linux.go index 76c0192c20..070d531bee 100644 --- a/src/runtime/cgo/linux.go +++ b/src/runtime/cgo/linux.go @@ -5,6 +5,7 @@ // Linux system call wrappers that provide POSIX semantics through the // corresponding cgo->libc (nptl) wrappers for various system calls. +//go:build linux // +build linux package cgo diff --git a/src/runtime/cgo/mmap.go b/src/runtime/cgo/mmap.go index 00fb7fced6..347ae6b363 100644 --- a/src/runtime/cgo/mmap.go +++ b/src/runtime/cgo/mmap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux && amd64) || (linux && arm64) // +build linux,amd64 linux,arm64 package cgo diff --git a/src/runtime/cgo/netbsd.go b/src/runtime/cgo/netbsd.go index 74d0aed014..7e17d1fcd2 100644 --- a/src/runtime/cgo/netbsd.go +++ b/src/runtime/cgo/netbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build netbsd // +build netbsd package cgo diff --git a/src/runtime/cgo/openbsd.go b/src/runtime/cgo/openbsd.go index 81c73bf399..f6215613c3 100644 --- a/src/runtime/cgo/openbsd.go +++ b/src/runtime/cgo/openbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build openbsd // +build openbsd package cgo diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go index 6495fcb5f8..e6e8040ae0 100644 --- a/src/runtime/cgo/setenv.go +++ b/src/runtime/cgo/setenv.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package cgo diff --git a/src/runtime/cgo/sigaction.go b/src/runtime/cgo/sigaction.go index 076fbc1a0a..ee63ea4c09 100644 --- a/src/runtime/cgo/sigaction.go +++ b/src/runtime/cgo/sigaction.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) // +build linux,amd64 freebsd,amd64 linux,arm64 package cgo diff --git a/src/runtime/cgo_mmap.go b/src/runtime/cgo_mmap.go index d5e0cc1e3e..17d26b4cc8 100644 --- a/src/runtime/cgo_mmap.go +++ b/src/runtime/cgo_mmap.go @@ -4,6 +4,7 @@ // Support for memory sanitizer. See runtime/cgo/mmap.go. +//go:build (linux && amd64) || (linux && arm64) // +build linux,amd64 linux,arm64 package runtime diff --git a/src/runtime/cgo_ppc64x.go b/src/runtime/cgo_ppc64x.go index fb2da32c7e..4dc92ea321 100644 --- a/src/runtime/cgo_ppc64x.go +++ b/src/runtime/cgo_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package runtime diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go index de634dc957..15690ecb0b 100644 --- a/src/runtime/cgo_sigaction.go +++ b/src/runtime/cgo_sigaction.go @@ -4,6 +4,7 @@ // Support for memory sanitizer. See runtime/cgo/sigaction.go. +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) // +build linux,amd64 freebsd,amd64 linux,arm64 package runtime diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go index 7beb57ea12..7c926f4a2b 100644 --- a/src/runtime/cputicks.go +++ b/src/runtime/cputicks.go @@ -2,13 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !arm -// +build !arm64 -// +build !mips64 -// +build !mips64le -// +build !mips -// +build !mipsle -// +build !wasm +//go:build !arm && !arm64 && !mips64 && !mips64le && !mips && !mipsle && !wasm +// +build !arm,!arm64,!mips64,!mips64le,!mips,!mipsle,!wasm package runtime diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 140c170ddc..7d25c51aa2 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo // +build cgo package runtime_test diff --git a/src/runtime/crash_nonunix_test.go b/src/runtime/crash_nonunix_test.go index 06c197ec2b..5f61476f21 100644 --- a/src/runtime/crash_nonunix_test.go +++ b/src/runtime/crash_nonunix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows || plan9 || (js && wasm) // +build windows plan9 js,wasm package runtime_test diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 803b031873..341c35ca56 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package runtime_test diff --git a/src/runtime/debug/panic_test.go b/src/runtime/debug/panic_test.go index b67a3de4f9..b93631e1d8 100644 --- a/src/runtime/debug/panic_test.go +++ b/src/runtime/debug/panic_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build aix darwin dragonfly freebsd linux netbsd openbsd // TODO: test on Windows? diff --git a/src/runtime/debug_test.go b/src/runtime/debug_test.go index a0b3f84382..c4c41f95f2 100644 --- a/src/runtime/debug_test.go +++ b/src/runtime/debug_test.go @@ -9,9 +9,8 @@ // spends all of its time in the race runtime, which isn't a safe // point. -// +build amd64 -// +build linux -// +build !race +//go:build amd64 && linux && !race +// +build amd64,linux,!race package runtime_test diff --git a/src/runtime/debugcall.go b/src/runtime/debugcall.go index efc68a767d..2fe0b1d12f 100644 --- a/src/runtime/debugcall.go +++ b/src/runtime/debugcall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 // +build amd64 package runtime diff --git a/src/runtime/debuglog_off.go b/src/runtime/debuglog_off.go index bb3e172498..dd38156999 100644 --- a/src/runtime/debuglog_off.go +++ b/src/runtime/debuglog_off.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !debuglog // +build !debuglog package runtime diff --git a/src/runtime/debuglog_on.go b/src/runtime/debuglog_on.go index 3d477e8ef5..2fcdbe70d1 100644 --- a/src/runtime/debuglog_on.go +++ b/src/runtime/debuglog_on.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build debuglog // +build debuglog package runtime diff --git a/src/runtime/defs1_linux.go b/src/runtime/defs1_linux.go index 4085d6f418..df9c05dd5e 100644 --- a/src/runtime/defs1_linux.go +++ b/src/runtime/defs1_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs2_linux.go b/src/runtime/defs2_linux.go index 87e19c1598..d016db7d02 100644 --- a/src/runtime/defs2_linux.go +++ b/src/runtime/defs2_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs3_linux.go b/src/runtime/defs3_linux.go index 31f2191c76..0a06aa2370 100644 --- a/src/runtime/defs3_linux.go +++ b/src/runtime/defs3_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_aix.go b/src/runtime/defs_aix.go index 23a6cac2bb..1605002ea2 100644 --- a/src/runtime/defs_aix.go +++ b/src/runtime/defs_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_aix_ppc64.go b/src/runtime/defs_aix_ppc64.go index a53fcc5933..f84ff1160d 100644 --- a/src/runtime/defs_aix_ppc64.go +++ b/src/runtime/defs_aix_ppc64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix // +build aix package runtime diff --git a/src/runtime/defs_arm_linux.go b/src/runtime/defs_arm_linux.go index e51dd32b5b..f6b6dd2c09 100644 --- a/src/runtime/defs_arm_linux.go +++ b/src/runtime/defs_arm_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go index cc8c475387..2d41a97b57 100644 --- a/src/runtime/defs_darwin.go +++ b/src/runtime/defs_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_dragonfly.go b/src/runtime/defs_dragonfly.go index 95014fe6e7..225258901f 100644 --- a/src/runtime/defs_dragonfly.go +++ b/src/runtime/defs_dragonfly.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_freebsd.go b/src/runtime/defs_freebsd.go index e196dff076..c258759549 100644 --- a/src/runtime/defs_freebsd.go +++ b/src/runtime/defs_freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_linux.go b/src/runtime/defs_linux.go index 7b14063386..022ef19427 100644 --- a/src/runtime/defs_linux.go +++ b/src/runtime/defs_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_linux_mips64x.go b/src/runtime/defs_linux_mips64x.go index 1fb423b198..2cafad20cf 100644 --- a/src/runtime/defs_linux_mips64x.go +++ b/src/runtime/defs_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (mips64 || mips64le) && linux // +build mips64 mips64le // +build linux diff --git a/src/runtime/defs_linux_mipsx.go b/src/runtime/defs_linux_mipsx.go index 9315ba9346..3a8dfe2e99 100644 --- a/src/runtime/defs_linux_mipsx.go +++ b/src/runtime/defs_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (mips || mipsle) && linux // +build mips mipsle // +build linux diff --git a/src/runtime/defs_netbsd.go b/src/runtime/defs_netbsd.go index 3f5ce5adca..755992d18e 100644 --- a/src/runtime/defs_netbsd.go +++ b/src/runtime/defs_netbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_netbsd_386.go b/src/runtime/defs_netbsd_386.go index c26f246077..03c9c2de59 100644 --- a/src/runtime/defs_netbsd_386.go +++ b/src/runtime/defs_netbsd_386.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_netbsd_amd64.go b/src/runtime/defs_netbsd_amd64.go index f18a7b1fe3..9fda1d7d22 100644 --- a/src/runtime/defs_netbsd_amd64.go +++ b/src/runtime/defs_netbsd_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_netbsd_arm.go b/src/runtime/defs_netbsd_arm.go index cb0dce66b4..e7f4f6cece 100644 --- a/src/runtime/defs_netbsd_arm.go +++ b/src/runtime/defs_netbsd_arm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_openbsd.go b/src/runtime/defs_openbsd.go index ff7e21c71e..8d323449d1 100644 --- a/src/runtime/defs_openbsd.go +++ b/src/runtime/defs_openbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_solaris.go b/src/runtime/defs_solaris.go index 22df59094d..e644f9c6dd 100644 --- a/src/runtime/defs_solaris.go +++ b/src/runtime/defs_solaris.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/defs_solaris_amd64.go b/src/runtime/defs_solaris_amd64.go index 0493178880..a0b38319a5 100644 --- a/src/runtime/defs_solaris_amd64.go +++ b/src/runtime/defs_solaris_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go index af353bbcd9..95517b2a95 100644 --- a/src/runtime/env_posix.go +++ b/src/runtime/env_posix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows || plan9 // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows plan9 package runtime diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go index ed4242ef24..18ccecd5cd 100644 --- a/src/runtime/export_debug_test.go +++ b/src/runtime/export_debug_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 -// +build linux +//go:build amd64 && linux +// +build amd64,linux package runtime diff --git a/src/runtime/export_futex_test.go b/src/runtime/export_futex_test.go index a727a93114..34c970d6d2 100644 --- a/src/runtime/export_futex_test.go +++ b/src/runtime/export_futex_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux // +build dragonfly freebsd linux package runtime diff --git a/src/runtime/export_mmap_test.go b/src/runtime/export_mmap_test.go index aeaf37f64b..bf4a815899 100644 --- a/src/runtime/export_mmap_test.go +++ b/src/runtime/export_mmap_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Export guts for testing. diff --git a/src/runtime/export_pipe2_test.go b/src/runtime/export_pipe2_test.go index 9d580d3313..31c8e43b3f 100644 --- a/src/runtime/export_pipe2_test.go +++ b/src/runtime/export_pipe2_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || linux || netbsd || openbsd || solaris // +build freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/export_pipe_test.go b/src/runtime/export_pipe_test.go index 8f66770fb9..82032e6bfb 100644 --- a/src/runtime/export_pipe_test.go +++ b/src/runtime/export_pipe_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly // +build aix darwin dragonfly package runtime diff --git a/src/runtime/export_unix_test.go b/src/runtime/export_unix_test.go index 307c63fd68..215e234286 100644 --- a/src/runtime/export_unix_test.go +++ b/src/runtime/export_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/futex_test.go b/src/runtime/futex_test.go index 3051bd5880..10a735327a 100644 --- a/src/runtime/futex_test.go +++ b/src/runtime/futex_test.go @@ -6,6 +6,7 @@ // The race detector emits calls to split stack functions so it breaks // the test. +//go:build (dragonfly || freebsd || linux) && !race // +build dragonfly freebsd linux // +build !race diff --git a/src/runtime/hash32.go b/src/runtime/hash32.go index 966f70e1aa..7fa8eb7cab 100644 --- a/src/runtime/hash32.go +++ b/src/runtime/hash32.go @@ -6,6 +6,7 @@ // xxhash: https://code.google.com/p/xxhash/ // cityhash: https://code.google.com/p/cityhash/ +//go:build 386 || arm || mips || mipsle // +build 386 arm mips mipsle package runtime diff --git a/src/runtime/hash64.go b/src/runtime/hash64.go index d1283824ad..1bee666bd7 100644 --- a/src/runtime/hash64.go +++ b/src/runtime/hash64.go @@ -6,6 +6,7 @@ // xxhash: https://code.google.com/p/xxhash/ // cityhash: https://code.google.com/p/cityhash/ +//go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm // +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm package runtime diff --git a/src/runtime/internal/atomic/atomic_386.go b/src/runtime/internal/atomic/atomic_386.go index 1bfcb1143d..d4aed6b671 100644 --- a/src/runtime/internal/atomic/atomic_386.go +++ b/src/runtime/internal/atomic/atomic_386.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 // +build 386 package atomic diff --git a/src/runtime/internal/atomic/atomic_arm.go b/src/runtime/internal/atomic/atomic_arm.go index 546b3d6120..2e9374ca26 100644 --- a/src/runtime/internal/atomic/atomic_arm.go +++ b/src/runtime/internal/atomic/atomic_arm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm // +build arm package atomic diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go index d49bee8936..131c687e1b 100644 --- a/src/runtime/internal/atomic/atomic_arm64.go +++ b/src/runtime/internal/atomic/atomic_arm64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package atomic diff --git a/src/runtime/internal/atomic/atomic_mips64x.go b/src/runtime/internal/atomic/atomic_mips64x.go index b0109d72b0..5b407ebc7a 100644 --- a/src/runtime/internal/atomic/atomic_mips64x.go +++ b/src/runtime/internal/atomic/atomic_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package atomic diff --git a/src/runtime/internal/atomic/atomic_mipsx.go b/src/runtime/internal/atomic/atomic_mipsx.go index 1336b50121..80cd65b333 100644 --- a/src/runtime/internal/atomic/atomic_mipsx.go +++ b/src/runtime/internal/atomic/atomic_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle // Export some functions via linkname to assembly in sync/atomic. diff --git a/src/runtime/internal/atomic/atomic_ppc64x.go b/src/runtime/internal/atomic/atomic_ppc64x.go index e4b109f0ec..98101e3287 100644 --- a/src/runtime/internal/atomic/atomic_ppc64x.go +++ b/src/runtime/internal/atomic/atomic_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package atomic diff --git a/src/runtime/internal/atomic/stubs.go b/src/runtime/internal/atomic/stubs.go index 62e30d1788..1275884b2f 100644 --- a/src/runtime/internal/atomic/stubs.go +++ b/src/runtime/internal/atomic/stubs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !wasm // +build !wasm package atomic diff --git a/src/runtime/internal/sys/gengoos.go b/src/runtime/internal/sys/gengoos.go index 9bbc48d94f..51f64a6e5c 100644 --- a/src/runtime/internal/sys/gengoos.go +++ b/src/runtime/internal/sys/gengoos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main diff --git a/src/runtime/internal/sys/intrinsics.go b/src/runtime/internal/sys/intrinsics.go index 3c8898236c..e76d8dd064 100644 --- a/src/runtime/internal/sys/intrinsics.go +++ b/src/runtime/internal/sys/intrinsics.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !386 // +build !386 // TODO finish intrinsifying 386, deadcode the assembly, remove build tags, merge w/ intrinsics_common diff --git a/src/runtime/internal/sys/intrinsics_stubs.go b/src/runtime/internal/sys/intrinsics_stubs.go index 9cbf48216c..bf1494d48a 100644 --- a/src/runtime/internal/sys/intrinsics_stubs.go +++ b/src/runtime/internal/sys/intrinsics_stubs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 // +build 386 package sys diff --git a/src/runtime/internal/sys/zgoarch_386.go b/src/runtime/internal/sys/zgoarch_386.go index c286d0df2b..98a2401bfe 100644 --- a/src/runtime/internal/sys/zgoarch_386.go +++ b/src/runtime/internal/sys/zgoarch_386.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build 386 // +build 386 package sys diff --git a/src/runtime/internal/sys/zgoarch_amd64.go b/src/runtime/internal/sys/zgoarch_amd64.go index d21c1d7d2a..d8faa5c786 100644 --- a/src/runtime/internal/sys/zgoarch_amd64.go +++ b/src/runtime/internal/sys/zgoarch_amd64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build amd64 // +build amd64 package sys diff --git a/src/runtime/internal/sys/zgoarch_arm.go b/src/runtime/internal/sys/zgoarch_arm.go index 9085fb0ea8..b64a69c9b4 100644 --- a/src/runtime/internal/sys/zgoarch_arm.go +++ b/src/runtime/internal/sys/zgoarch_arm.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build arm // +build arm package sys diff --git a/src/runtime/internal/sys/zgoarch_arm64.go b/src/runtime/internal/sys/zgoarch_arm64.go index ed7ef2ebcb..de6f85347b 100644 --- a/src/runtime/internal/sys/zgoarch_arm64.go +++ b/src/runtime/internal/sys/zgoarch_arm64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build arm64 // +build arm64 package sys diff --git a/src/runtime/internal/sys/zgoarch_arm64be.go b/src/runtime/internal/sys/zgoarch_arm64be.go index faf3111053..b762bb069f 100644 --- a/src/runtime/internal/sys/zgoarch_arm64be.go +++ b/src/runtime/internal/sys/zgoarch_arm64be.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build arm64be // +build arm64be package sys diff --git a/src/runtime/internal/sys/zgoarch_armbe.go b/src/runtime/internal/sys/zgoarch_armbe.go index cb28301e0b..e5297e4b16 100644 --- a/src/runtime/internal/sys/zgoarch_armbe.go +++ b/src/runtime/internal/sys/zgoarch_armbe.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build armbe // +build armbe package sys diff --git a/src/runtime/internal/sys/zgoarch_mips.go b/src/runtime/internal/sys/zgoarch_mips.go index 315dea1c84..b5f4ed390c 100644 --- a/src/runtime/internal/sys/zgoarch_mips.go +++ b/src/runtime/internal/sys/zgoarch_mips.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mips // +build mips package sys diff --git a/src/runtime/internal/sys/zgoarch_mips64.go b/src/runtime/internal/sys/zgoarch_mips64.go index 5258cbfbe7..73777cceb2 100644 --- a/src/runtime/internal/sys/zgoarch_mips64.go +++ b/src/runtime/internal/sys/zgoarch_mips64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mips64 // +build mips64 package sys diff --git a/src/runtime/internal/sys/zgoarch_mips64le.go b/src/runtime/internal/sys/zgoarch_mips64le.go index 1721698518..0c81c36c09 100644 --- a/src/runtime/internal/sys/zgoarch_mips64le.go +++ b/src/runtime/internal/sys/zgoarch_mips64le.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mips64le // +build mips64le package sys diff --git a/src/runtime/internal/sys/zgoarch_mips64p32.go b/src/runtime/internal/sys/zgoarch_mips64p32.go index 44c4624da9..d63ce27d24 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32.go +++ b/src/runtime/internal/sys/zgoarch_mips64p32.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mips64p32 // +build mips64p32 package sys diff --git a/src/runtime/internal/sys/zgoarch_mips64p32le.go b/src/runtime/internal/sys/zgoarch_mips64p32le.go index eb63225430..2d577890b2 100644 --- a/src/runtime/internal/sys/zgoarch_mips64p32le.go +++ b/src/runtime/internal/sys/zgoarch_mips64p32le.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mips64p32le // +build mips64p32le package sys diff --git a/src/runtime/internal/sys/zgoarch_mipsle.go b/src/runtime/internal/sys/zgoarch_mipsle.go index e0ebfbf038..8af919d03a 100644 --- a/src/runtime/internal/sys/zgoarch_mipsle.go +++ b/src/runtime/internal/sys/zgoarch_mipsle.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build mipsle // +build mipsle package sys diff --git a/src/runtime/internal/sys/zgoarch_ppc.go b/src/runtime/internal/sys/zgoarch_ppc.go index ef26aa3201..f6f12a5ddc 100644 --- a/src/runtime/internal/sys/zgoarch_ppc.go +++ b/src/runtime/internal/sys/zgoarch_ppc.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build ppc // +build ppc package sys diff --git a/src/runtime/internal/sys/zgoarch_ppc64.go b/src/runtime/internal/sys/zgoarch_ppc64.go index 32c2d46d4c..a8379601f4 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64.go +++ b/src/runtime/internal/sys/zgoarch_ppc64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build ppc64 // +build ppc64 package sys diff --git a/src/runtime/internal/sys/zgoarch_ppc64le.go b/src/runtime/internal/sys/zgoarch_ppc64le.go index 3a6e56763c..f2ec5dcba7 100644 --- a/src/runtime/internal/sys/zgoarch_ppc64le.go +++ b/src/runtime/internal/sys/zgoarch_ppc64le.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build ppc64le // +build ppc64le package sys diff --git a/src/runtime/internal/sys/zgoarch_riscv.go b/src/runtime/internal/sys/zgoarch_riscv.go index d8f6b49093..83a3312f5f 100644 --- a/src/runtime/internal/sys/zgoarch_riscv.go +++ b/src/runtime/internal/sys/zgoarch_riscv.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build riscv // +build riscv package sys diff --git a/src/runtime/internal/sys/zgoarch_riscv64.go b/src/runtime/internal/sys/zgoarch_riscv64.go index 0ba843b5ac..1dfcc84997 100644 --- a/src/runtime/internal/sys/zgoarch_riscv64.go +++ b/src/runtime/internal/sys/zgoarch_riscv64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build riscv64 // +build riscv64 package sys diff --git a/src/runtime/internal/sys/zgoarch_s390.go b/src/runtime/internal/sys/zgoarch_s390.go index 20a1b234a6..91aba5a0f6 100644 --- a/src/runtime/internal/sys/zgoarch_s390.go +++ b/src/runtime/internal/sys/zgoarch_s390.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build s390 // +build s390 package sys diff --git a/src/runtime/internal/sys/zgoarch_s390x.go b/src/runtime/internal/sys/zgoarch_s390x.go index ffdda0c827..edce50234e 100644 --- a/src/runtime/internal/sys/zgoarch_s390x.go +++ b/src/runtime/internal/sys/zgoarch_s390x.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build s390x // +build s390x package sys diff --git a/src/runtime/internal/sys/zgoarch_sparc.go b/src/runtime/internal/sys/zgoarch_sparc.go index b4949510d5..5ae9560ab0 100644 --- a/src/runtime/internal/sys/zgoarch_sparc.go +++ b/src/runtime/internal/sys/zgoarch_sparc.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build sparc // +build sparc package sys diff --git a/src/runtime/internal/sys/zgoarch_sparc64.go b/src/runtime/internal/sys/zgoarch_sparc64.go index 0f6df411ce..e2a0134aff 100644 --- a/src/runtime/internal/sys/zgoarch_sparc64.go +++ b/src/runtime/internal/sys/zgoarch_sparc64.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build sparc64 // +build sparc64 package sys diff --git a/src/runtime/internal/sys/zgoarch_wasm.go b/src/runtime/internal/sys/zgoarch_wasm.go index e69afb0cb3..52e85dea37 100644 --- a/src/runtime/internal/sys/zgoarch_wasm.go +++ b/src/runtime/internal/sys/zgoarch_wasm.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build wasm // +build wasm package sys diff --git a/src/runtime/internal/sys/zgoos_aix.go b/src/runtime/internal/sys/zgoos_aix.go index 0631d02aa5..f3b907471f 100644 --- a/src/runtime/internal/sys/zgoos_aix.go +++ b/src/runtime/internal/sys/zgoos_aix.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build aix // +build aix package sys diff --git a/src/runtime/internal/sys/zgoos_android.go b/src/runtime/internal/sys/zgoos_android.go index d356a40bec..e28baf7c48 100644 --- a/src/runtime/internal/sys/zgoos_android.go +++ b/src/runtime/internal/sys/zgoos_android.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build android // +build android package sys diff --git a/src/runtime/internal/sys/zgoos_darwin.go b/src/runtime/internal/sys/zgoos_darwin.go index 6aa2db7e3a..3c7f7b543e 100644 --- a/src/runtime/internal/sys/zgoos_darwin.go +++ b/src/runtime/internal/sys/zgoos_darwin.go @@ -1,7 +1,7 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. -// +build !ios -// +build darwin +//go:build !ios && darwin +// +build !ios,darwin package sys diff --git a/src/runtime/internal/sys/zgoos_dragonfly.go b/src/runtime/internal/sys/zgoos_dragonfly.go index 88ee1174f1..f844d29e2a 100644 --- a/src/runtime/internal/sys/zgoos_dragonfly.go +++ b/src/runtime/internal/sys/zgoos_dragonfly.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build dragonfly // +build dragonfly package sys diff --git a/src/runtime/internal/sys/zgoos_freebsd.go b/src/runtime/internal/sys/zgoos_freebsd.go index 8de2ec0559..8999a2797a 100644 --- a/src/runtime/internal/sys/zgoos_freebsd.go +++ b/src/runtime/internal/sys/zgoos_freebsd.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build freebsd // +build freebsd package sys diff --git a/src/runtime/internal/sys/zgoos_hurd.go b/src/runtime/internal/sys/zgoos_hurd.go index 183ccb02a1..a546488bf8 100644 --- a/src/runtime/internal/sys/zgoos_hurd.go +++ b/src/runtime/internal/sys/zgoos_hurd.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build hurd // +build hurd package sys diff --git a/src/runtime/internal/sys/zgoos_illumos.go b/src/runtime/internal/sys/zgoos_illumos.go index d04134e1df..02a4ca06e8 100644 --- a/src/runtime/internal/sys/zgoos_illumos.go +++ b/src/runtime/internal/sys/zgoos_illumos.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build illumos // +build illumos package sys diff --git a/src/runtime/internal/sys/zgoos_ios.go b/src/runtime/internal/sys/zgoos_ios.go index cf6e9d61f0..033eec623d 100644 --- a/src/runtime/internal/sys/zgoos_ios.go +++ b/src/runtime/internal/sys/zgoos_ios.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build ios // +build ios package sys diff --git a/src/runtime/internal/sys/zgoos_js.go b/src/runtime/internal/sys/zgoos_js.go index 1d9279ab38..28226ad60a 100644 --- a/src/runtime/internal/sys/zgoos_js.go +++ b/src/runtime/internal/sys/zgoos_js.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build js // +build js package sys diff --git a/src/runtime/internal/sys/zgoos_linux.go b/src/runtime/internal/sys/zgoos_linux.go index 0f718d704f..01546e4b9f 100644 --- a/src/runtime/internal/sys/zgoos_linux.go +++ b/src/runtime/internal/sys/zgoos_linux.go @@ -1,7 +1,7 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. -// +build !android -// +build linux +//go:build !android && linux +// +build !android,linux package sys diff --git a/src/runtime/internal/sys/zgoos_netbsd.go b/src/runtime/internal/sys/zgoos_netbsd.go index 2ae149ff13..9d658b20ee 100644 --- a/src/runtime/internal/sys/zgoos_netbsd.go +++ b/src/runtime/internal/sys/zgoos_netbsd.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build netbsd // +build netbsd package sys diff --git a/src/runtime/internal/sys/zgoos_openbsd.go b/src/runtime/internal/sys/zgoos_openbsd.go index 7d4d61e4ca..0f55454a95 100644 --- a/src/runtime/internal/sys/zgoos_openbsd.go +++ b/src/runtime/internal/sys/zgoos_openbsd.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build openbsd // +build openbsd package sys diff --git a/src/runtime/internal/sys/zgoos_plan9.go b/src/runtime/internal/sys/zgoos_plan9.go index 30aec46df3..d0347464d6 100644 --- a/src/runtime/internal/sys/zgoos_plan9.go +++ b/src/runtime/internal/sys/zgoos_plan9.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build plan9 // +build plan9 package sys diff --git a/src/runtime/internal/sys/zgoos_solaris.go b/src/runtime/internal/sys/zgoos_solaris.go index 4bb8c99bce..05c3007e2c 100644 --- a/src/runtime/internal/sys/zgoos_solaris.go +++ b/src/runtime/internal/sys/zgoos_solaris.go @@ -1,7 +1,7 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. -// +build !illumos -// +build solaris +//go:build !illumos && solaris +// +build !illumos,solaris package sys diff --git a/src/runtime/internal/sys/zgoos_windows.go b/src/runtime/internal/sys/zgoos_windows.go index d1f4290204..7d07fa3a45 100644 --- a/src/runtime/internal/sys/zgoos_windows.go +++ b/src/runtime/internal/sys/zgoos_windows.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build windows // +build windows package sys diff --git a/src/runtime/internal/sys/zgoos_zos.go b/src/runtime/internal/sys/zgoos_zos.go index d22be46fc0..d6e5b9b0cb 100644 --- a/src/runtime/internal/sys/zgoos_zos.go +++ b/src/runtime/internal/sys/zgoos_zos.go @@ -1,5 +1,6 @@ // Code generated by gengoos.go using 'go generate'. DO NOT EDIT. +//go:build zos // +build zos package sys diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go index f07ff1c06b..c00f0965bd 100644 --- a/src/runtime/lfstack_32bit.go +++ b/src/runtime/lfstack_32bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || arm || mips || mipsle // +build 386 arm mips mipsle package runtime diff --git a/src/runtime/lfstack_64bit.go b/src/runtime/lfstack_64bit.go index 9d821b989e..4812dd1156 100644 --- a/src/runtime/lfstack_64bit.go +++ b/src/runtime/lfstack_64bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm // +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm package runtime diff --git a/src/runtime/libfuzzer.go b/src/runtime/libfuzzer.go index 0161955f09..578bce0414 100644 --- a/src/runtime/libfuzzer.go +++ b/src/runtime/libfuzzer.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build libfuzzer // +build libfuzzer package runtime diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go index 91467fdfae..017b481c64 100644 --- a/src/runtime/lock_futex.go +++ b/src/runtime/lock_futex.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux // +build dragonfly freebsd linux package runtime diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go index 14bdc76842..04e7e85c12 100644 --- a/src/runtime/lock_js.go +++ b/src/runtime/lock_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package runtime diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go index 671e524e45..3c0a7ca67e 100644 --- a/src/runtime/lock_sema.go +++ b/src/runtime/lock_sema.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || netbsd || openbsd || plan9 || solaris || windows // +build aix darwin netbsd openbsd plan9 solaris windows package runtime diff --git a/src/runtime/lockrank_off.go b/src/runtime/lockrank_off.go index 7dcd8f5fe9..f3d2c00914 100644 --- a/src/runtime/lockrank_off.go +++ b/src/runtime/lockrank_off.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.staticlockranking // +build !goexperiment.staticlockranking package runtime diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go index 88ac95a004..702bf5f24c 100644 --- a/src/runtime/lockrank_on.go +++ b/src/runtime/lockrank_on.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build goexperiment.staticlockranking // +build goexperiment.staticlockranking package runtime diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go index bc672019fb..dcbb9a1d51 100644 --- a/src/runtime/mem_bsd.go +++ b/src/runtime/mem_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || netbsd || openbsd || solaris // +build dragonfly freebsd netbsd openbsd solaris package runtime diff --git a/src/runtime/mem_js.go b/src/runtime/mem_js.go index 957ed36ffa..fe940360c0 100644 --- a/src/runtime/mem_js.go +++ b/src/runtime/mem_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package runtime diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go index ef297f073e..8632fe08a3 100644 --- a/src/runtime/mkduff.go +++ b/src/runtime/mkduff.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // runtime·duffzero is a Duff's device for zeroing memory. diff --git a/src/runtime/mkfastlog2table.go b/src/runtime/mkfastlog2table.go index d650292394..8d78a3923a 100644 --- a/src/runtime/mkfastlog2table.go +++ b/src/runtime/mkfastlog2table.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // fastlog2Table contains log2 approximations for 5 binary digits. diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go index 1d614dd003..3069d6ed04 100644 --- a/src/runtime/mkpreempt.go +++ b/src/runtime/mkpreempt.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // mkpreempt generates the asyncPreempt functions for each diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go index b92d1fed5f..b4a117d343 100644 --- a/src/runtime/mksizeclasses.go +++ b/src/runtime/mksizeclasses.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate tables for small malloc size classes. diff --git a/src/runtime/mmap.go b/src/runtime/mmap.go index 1b1848b79e..7460eb3104 100644 --- a/src/runtime/mmap.go +++ b/src/runtime/mmap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !aix && !darwin && !js && (!linux || !amd64) && (!linux || !arm64) && !openbsd && !plan9 && !solaris && !windows // +build !aix // +build !darwin // +build !js diff --git a/src/runtime/mpagealloc_32bit.go b/src/runtime/mpagealloc_32bit.go index 331dadade9..fceb4e7a18 100644 --- a/src/runtime/mpagealloc_32bit.go +++ b/src/runtime/mpagealloc_32bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || arm || mips || mipsle || wasm || (ios && arm64) // +build 386 arm mips mipsle wasm ios,arm64 // wasm is a treated as a 32-bit architecture for the purposes of the page diff --git a/src/runtime/mpagealloc_64bit.go b/src/runtime/mpagealloc_64bit.go index ffacb46c18..16577346a7 100644 --- a/src/runtime/mpagealloc_64bit.go +++ b/src/runtime/mpagealloc_64bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || (!ios && arm64) || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x // +build amd64 !ios,arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x // See mpagealloc_32bit.go for why ios/arm64 is excluded here. diff --git a/src/runtime/msan.go b/src/runtime/msan.go index 6a5960b0a8..25aaf94e26 100644 --- a/src/runtime/msan.go +++ b/src/runtime/msan.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build msan // +build msan package runtime diff --git a/src/runtime/msan0.go b/src/runtime/msan0.go index 374d13f30b..b1096a6750 100644 --- a/src/runtime/msan0.go +++ b/src/runtime/msan0.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !msan // +build !msan // Dummy MSan support API, used when not built with -msan. diff --git a/src/runtime/nbpipe_fcntl_libc_test.go b/src/runtime/nbpipe_fcntl_libc_test.go index b38c58399b..076a722eb7 100644 --- a/src/runtime/nbpipe_fcntl_libc_test.go +++ b/src/runtime/nbpipe_fcntl_libc_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || solaris // +build aix darwin solaris package runtime_test diff --git a/src/runtime/nbpipe_fcntl_unix_test.go b/src/runtime/nbpipe_fcntl_unix_test.go index 75acdb62dd..6d5e4ff021 100644 --- a/src/runtime/nbpipe_fcntl_unix_test.go +++ b/src/runtime/nbpipe_fcntl_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package runtime_test diff --git a/src/runtime/nbpipe_pipe.go b/src/runtime/nbpipe_pipe.go index 822b2944db..d92cf97217 100644 --- a/src/runtime/nbpipe_pipe.go +++ b/src/runtime/nbpipe_pipe.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly // +build aix darwin dragonfly package runtime diff --git a/src/runtime/nbpipe_pipe2.go b/src/runtime/nbpipe_pipe2.go index e3639d99b1..f138d1f956 100644 --- a/src/runtime/nbpipe_pipe2.go +++ b/src/runtime/nbpipe_pipe2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || linux || netbsd || openbsd || solaris // +build freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/nbpipe_test.go b/src/runtime/nbpipe_test.go index d739f57864..1d6a9b525c 100644 --- a/src/runtime/nbpipe_test.go +++ b/src/runtime/nbpipe_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package runtime_test diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 77eb3aa4c6..afb208a455 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows package runtime diff --git a/src/runtime/netpoll_epoll.go b/src/runtime/netpoll_epoll.go index 58f4fa8754..371ac59f8e 100644 --- a/src/runtime/netpoll_epoll.go +++ b/src/runtime/netpoll_epoll.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package runtime diff --git a/src/runtime/netpoll_fake.go b/src/runtime/netpoll_fake.go index b2af3b89b2..8366f28914 100644 --- a/src/runtime/netpoll_fake.go +++ b/src/runtime/netpoll_fake.go @@ -5,6 +5,7 @@ // Fake network poller for wasm/js. // Should never be used, because wasm/js network connections do not honor "SetNonblock". +//go:build js && wasm // +build js,wasm package runtime diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go index 3bd93c1f20..80d1b0cf18 100644 --- a/src/runtime/netpoll_kqueue.go +++ b/src/runtime/netpoll_kqueue.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package runtime diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go index 3599f2d01b..33ab8eba58 100644 --- a/src/runtime/netpoll_stub.go +++ b/src/runtime/netpoll_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package runtime diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go index 3517a5ddbe..94b7c7a467 100644 --- a/src/runtime/norace_linux_test.go +++ b/src/runtime/norace_linux_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // The file contains tests that cannot run under race detector for some reason. +//go:build !race // +build !race package runtime_test diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go index e90128bb6d..9ad5dde382 100644 --- a/src/runtime/norace_test.go +++ b/src/runtime/norace_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // The file contains tests that cannot run under race detector for some reason. +//go:build !race // +build !race package runtime_test diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go index 303f0876de..557b17cc75 100644 --- a/src/runtime/os_aix.go +++ b/src/runtime/os_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix // +build aix package runtime diff --git a/src/runtime/os_freebsd2.go b/src/runtime/os_freebsd2.go index 6947a05d04..fde6fbf1b1 100644 --- a/src/runtime/os_freebsd2.go +++ b/src/runtime/os_freebsd2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd && !amd64 // +build freebsd,!amd64 package runtime diff --git a/src/runtime/os_freebsd_noauxv.go b/src/runtime/os_freebsd_noauxv.go index 01efb9b7c9..8fe0cb6718 100644 --- a/src/runtime/os_freebsd_noauxv.go +++ b/src/runtime/os_freebsd_noauxv.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build freebsd -// +build !arm +//go:build freebsd && !arm +// +build freebsd,!arm package runtime diff --git a/src/runtime/os_js.go b/src/runtime/os_js.go index 5b2c53795a..52b64e7602 100644 --- a/src/runtime/os_js.go +++ b/src/runtime/os_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package runtime diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go index c5fd742048..5260f22f57 100644 --- a/src/runtime/os_linux_arm64.go +++ b/src/runtime/os_linux_arm64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build arm64 // +build arm64 package runtime diff --git a/src/runtime/os_linux_be64.go b/src/runtime/os_linux_be64.go index 9860002ee4..806d02fee8 100644 --- a/src/runtime/os_linux_be64.go +++ b/src/runtime/os_linux_be64.go @@ -4,6 +4,7 @@ // The standard GNU/Linux sigset type on big-endian 64-bit machines. +//go:build linux && (ppc64 || s390x) // +build linux // +build ppc64 s390x diff --git a/src/runtime/os_linux_generic.go b/src/runtime/os_linux_generic.go index e1d0952ddf..fe1973dbde 100644 --- a/src/runtime/os_linux_generic.go +++ b/src/runtime/os_linux_generic.go @@ -2,13 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !mips -// +build !mipsle -// +build !mips64 -// +build !mips64le -// +build !s390x -// +build !ppc64 -// +build linux +//go:build !mips && !mipsle && !mips64 && !mips64le && !s390x && !ppc64 && linux +// +build !mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,linux package runtime diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go index 815a83a04b..bd76442dbd 100644 --- a/src/runtime/os_linux_mips64x.go +++ b/src/runtime/os_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/runtime/os_linux_mipsx.go b/src/runtime/os_linux_mipsx.go index 00fb02e4bf..ef8b3f7d43 100644 --- a/src/runtime/os_linux_mipsx.go +++ b/src/runtime/os_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/runtime/os_linux_noauxv.go b/src/runtime/os_linux_noauxv.go index 895b4cd5f4..59b5aacaeb 100644 --- a/src/runtime/os_linux_noauxv.go +++ b/src/runtime/os_linux_noauxv.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux -// +build !arm,!arm64,!mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,!ppc64le +//go:build linux && !arm && !arm64 && !mips && !mipsle && !mips64 && !mips64le && !s390x && !ppc64 && !ppc64le +// +build linux,!arm,!arm64,!mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,!ppc64le package runtime diff --git a/src/runtime/os_linux_novdso.go b/src/runtime/os_linux_novdso.go index 155f415e71..8104f63627 100644 --- a/src/runtime/os_linux_novdso.go +++ b/src/runtime/os_linux_novdso.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux -// +build !386,!amd64,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le +//go:build linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le +// +build linux,!386,!amd64,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le package runtime diff --git a/src/runtime/os_linux_ppc64x.go b/src/runtime/os_linux_ppc64x.go index 3aedc23ef9..c093d2ec0f 100644 --- a/src/runtime/os_linux_ppc64x.go +++ b/src/runtime/os_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/src/runtime/os_linux_x86.go b/src/runtime/os_linux_x86.go index d91fa1a0d1..5667774d82 100644 --- a/src/runtime/os_linux_x86.go +++ b/src/runtime/os_linux_x86.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (386 || amd64) // +build linux // +build 386 amd64 diff --git a/src/runtime/os_nonopenbsd.go b/src/runtime/os_nonopenbsd.go index e65697bdb3..6134b6c02f 100644 --- a/src/runtime/os_nonopenbsd.go +++ b/src/runtime/os_nonopenbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !openbsd // +build !openbsd package runtime diff --git a/src/runtime/os_only_solaris.go b/src/runtime/os_only_solaris.go index e2f5409354..3829683c80 100644 --- a/src/runtime/os_only_solaris.go +++ b/src/runtime/os_only_solaris.go @@ -4,6 +4,7 @@ // Solaris code that doesn't also apply to illumos. +//go:build !illumos // +build !illumos package runtime diff --git a/src/runtime/os_openbsd_libc.go b/src/runtime/os_openbsd_libc.go index 2edb0358b0..3f43ade558 100644 --- a/src/runtime/os_openbsd_libc.go +++ b/src/runtime/os_openbsd_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/os_openbsd_syscall.go b/src/runtime/os_openbsd_syscall.go index 16ff2b8e25..6facf31593 100644 --- a/src/runtime/os_openbsd_syscall.go +++ b/src/runtime/os_openbsd_syscall.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build openbsd,!amd64 -// +build openbsd,!arm64 +//go:build openbsd && !amd64 && openbsd && !arm64 +// +build openbsd,!amd64,openbsd,!arm64 package runtime diff --git a/src/runtime/os_openbsd_syscall1.go b/src/runtime/os_openbsd_syscall1.go index f37da04194..0f3d5f0b73 100644 --- a/src/runtime/os_openbsd_syscall1.go +++ b/src/runtime/os_openbsd_syscall1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build openbsd && !amd64 && !arm64 // +build openbsd,!amd64,!arm64 package runtime diff --git a/src/runtime/os_openbsd_syscall2.go b/src/runtime/os_openbsd_syscall2.go index 81cfb085aa..3b1707126b 100644 --- a/src/runtime/os_openbsd_syscall2.go +++ b/src/runtime/os_openbsd_syscall2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build openbsd && !amd64 && !arm64 // +build openbsd,!amd64,!arm64 package runtime diff --git a/src/runtime/panic32.go b/src/runtime/panic32.go index aea8401a37..acbdd1ff45 100644 --- a/src/runtime/panic32.go +++ b/src/runtime/panic32.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build 386 || arm || mips || mipsle // +build 386 arm mips mipsle package runtime diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go index c11a45fd69..3ef40d3de7 100644 --- a/src/runtime/pprof/mprof_test.go +++ b/src/runtime/pprof/mprof_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package pprof @@ -93,31 +94,31 @@ func TestMemoryProfiler(t *testing.T) { }{{ stk: []string{"runtime/pprof.allocatePersistent1K", "runtime/pprof.TestMemoryProfiler"}, legacy: fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ -# 0x[0-9,a-f]+ runtime/pprof\.allocatePersistent1K\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:47 -# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:82 +# 0x[0-9,a-f]+ runtime/pprof\.allocatePersistent1K\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:48 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:83 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun), }, { stk: []string{"runtime/pprof.allocateTransient1M", "runtime/pprof.TestMemoryProfiler"}, legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ -# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient1M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:24 -# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:79 +# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient1M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:25 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:80 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun), }, { stk: []string{"runtime/pprof.allocateTransient2M", "runtime/pprof.TestMemoryProfiler"}, legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ -# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient2M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:30 -# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:80 +# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient2M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:31 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:81 `, memoryProfilerRun, (2<<20)*memoryProfilerRun), }, { stk: []string{"runtime/pprof.allocateTransient2MInline", "runtime/pprof.TestMemoryProfiler"}, legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ -# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient2MInline\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:34 -# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:81 +# 0x[0-9,a-f]+ runtime/pprof\.allocateTransient2MInline\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:35 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:82 `, memoryProfilerRun, (2<<20)*memoryProfilerRun), }, { stk: []string{"runtime/pprof.allocateReflectTransient"}, legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @( 0x[0-9,a-f]+)+ -# 0x[0-9,a-f]+ runtime/pprof\.allocateReflectTransient\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:55 +# 0x[0-9,a-f]+ runtime/pprof\.allocateReflectTransient\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:56 `, memoryProfilerRun, (2<<20)*memoryProfilerRun), }} diff --git a/src/runtime/pprof/pprof_norusage.go b/src/runtime/pprof/pprof_norusage.go index 6fdcc6cc38..e175dd380c 100644 --- a/src/runtime/pprof/pprof_norusage.go +++ b/src/runtime/pprof/pprof_norusage.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !darwin && !linux // +build !darwin,!linux package pprof diff --git a/src/runtime/pprof/pprof_rusage.go b/src/runtime/pprof/pprof_rusage.go index 7954673811..269f21bc2f 100644 --- a/src/runtime/pprof/pprof_rusage.go +++ b/src/runtime/pprof/pprof_rusage.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || linux // +build darwin linux package pprof diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 14321b0934..1b86dbff5b 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js package pprof diff --git a/src/runtime/preempt_nonwindows.go b/src/runtime/preempt_nonwindows.go index 3066a1521e..365e86a611 100644 --- a/src/runtime/preempt_nonwindows.go +++ b/src/runtime/preempt_nonwindows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package runtime diff --git a/src/runtime/race.go b/src/runtime/race.go index 79fd21765d..cc8c5db1bd 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package runtime diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go index 17dc32013f..4a959d9aba 100644 --- a/src/runtime/race/output_test.go +++ b/src/runtime/race/output_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package race_test diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go index d6a14b79e7..fe50900ec8 100644 --- a/src/runtime/race/race.go +++ b/src/runtime/race/race.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) // +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 package race diff --git a/src/runtime/race/race_linux_test.go b/src/runtime/race/race_linux_test.go index c00ce4d3df..9c0d48d6bd 100644 --- a/src/runtime/race/race_linux_test.go +++ b/src/runtime/race/race_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && race // +build linux,race package race_test diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go index d433af6bd0..8c880b8570 100644 --- a/src/runtime/race/race_test.go +++ b/src/runtime/race/race_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race // This program is used to verify the race detector diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go index 84f0acece6..acd6e47f98 100644 --- a/src/runtime/race/race_unix_test.go +++ b/src/runtime/race/race_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race && (darwin || freebsd || linux) // +build race // +build darwin freebsd linux diff --git a/src/runtime/race/race_windows_test.go b/src/runtime/race/race_windows_test.go index 307a1ea6c0..e490d766dd 100644 --- a/src/runtime/race/race_windows_test.go +++ b/src/runtime/race/race_windows_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows && race // +build windows,race package race_test diff --git a/src/runtime/race/sched_test.go b/src/runtime/race/sched_test.go index d6bb323cde..e904ebd20d 100644 --- a/src/runtime/race/sched_test.go +++ b/src/runtime/race/sched_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package race_test diff --git a/src/runtime/race/syso_test.go b/src/runtime/race/syso_test.go index db846c5d2a..cbce5a8f18 100644 --- a/src/runtime/race/syso_test.go +++ b/src/runtime/race/syso_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !android && !js && !ppc64le // +build !android,!js,!ppc64le // Note: we don't run on Android or ppc64 because if there is any non-race test diff --git a/src/runtime/race/timer_test.go b/src/runtime/race/timer_test.go index a6c34a8352..f11f8456a0 100644 --- a/src/runtime/race/timer_test.go +++ b/src/runtime/race/timer_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build race // +build race package race_test diff --git a/src/runtime/race0.go b/src/runtime/race0.go index 180f707b1a..0e431b8103 100644 --- a/src/runtime/race0.go +++ b/src/runtime/race0.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !race // +build !race // Dummy race detection API, used when not built with -race. diff --git a/src/runtime/relax_stub.go b/src/runtime/relax_stub.go index 81ed1291b8..5b92879c20 100644 --- a/src/runtime/relax_stub.go +++ b/src/runtime/relax_stub.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !windows // +build !windows package runtime diff --git a/src/runtime/runtime_mmap_test.go b/src/runtime/runtime_mmap_test.go index bb0b747606..f71f8afa57 100644 --- a/src/runtime/runtime_mmap_test.go +++ b/src/runtime/runtime_mmap_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package runtime_test diff --git a/src/runtime/runtime_unix_test.go b/src/runtime/runtime_unix_test.go index b0cbbbe3e6..0251c676e6 100644 --- a/src/runtime/runtime_unix_test.go +++ b/src/runtime/runtime_unix_test.go @@ -6,6 +6,7 @@ // We need a fast system call to provoke the race, // and Close(-1) is nearly universally fast. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || plan9 // +build aix darwin dragonfly freebsd linux netbsd openbsd plan9 package runtime_test diff --git a/src/runtime/semasleep_test.go b/src/runtime/semasleep_test.go index 9b371b0732..905e932b7d 100644 --- a/src/runtime/semasleep_test.go +++ b/src/runtime/semasleep_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !plan9 && !windows && !js // +build !plan9,!windows,!js package runtime_test diff --git a/src/runtime/sigaction.go b/src/runtime/sigaction.go index 3c888579d0..76f37b1b53 100644 --- a/src/runtime/sigaction.go +++ b/src/runtime/sigaction.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux && !amd64 && !arm64) || (freebsd && !amd64) // +build linux,!amd64,!arm64 freebsd,!amd64 package runtime diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index 065aff48d3..5824eaddb5 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package runtime diff --git a/src/runtime/signal_aix_ppc64.go b/src/runtime/signal_aix_ppc64.go index c17563e2a5..a0becd431e 100644 --- a/src/runtime/signal_aix_ppc64.go +++ b/src/runtime/signal_aix_ppc64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix // +build aix package runtime diff --git a/src/runtime/signal_amd64.go b/src/runtime/signal_amd64.go index 3eeb5e044f..e45fbb4a87 100644 --- a/src/runtime/signal_amd64.go +++ b/src/runtime/signal_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 && (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) // +build amd64 // +build darwin dragonfly freebsd linux netbsd openbsd solaris diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go index 156d9d384c..4d9c6224a2 100644 --- a/src/runtime/signal_arm.go +++ b/src/runtime/signal_arm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package runtime diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go index b559b93938..f04750084f 100644 --- a/src/runtime/signal_arm64.go +++ b/src/runtime/signal_arm64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || freebsd || linux || netbsd || openbsd // +build darwin freebsd linux netbsd openbsd package runtime diff --git a/src/runtime/signal_linux_mips64x.go b/src/runtime/signal_linux_mips64x.go index b608197d60..f0a75ac3ea 100644 --- a/src/runtime/signal_linux_mips64x.go +++ b/src/runtime/signal_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/runtime/signal_linux_mipsx.go b/src/runtime/signal_linux_mipsx.go index c88ac4d521..f3969c5aac 100644 --- a/src/runtime/signal_linux_mipsx.go +++ b/src/runtime/signal_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/runtime/signal_linux_ppc64x.go b/src/runtime/signal_linux_ppc64x.go index 97cb26d587..d9d3e55ec2 100644 --- a/src/runtime/signal_linux_ppc64x.go +++ b/src/runtime/signal_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index 2a347ff4cb..1616b57027 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux || openbsd) && (mips64 || mips64le) // +build linux openbsd // +build mips64 mips64le diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go index 8c29f59bd1..dcc7f1e9dd 100644 --- a/src/runtime/signal_mipsx.go +++ b/src/runtime/signal_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go index 5de93a330a..f2225da9a1 100644 --- a/src/runtime/signal_ppc64x.go +++ b/src/runtime/signal_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (aix || linux) && (ppc64 || ppc64le) // +build aix linux // +build ppc64 ppc64le diff --git a/src/runtime/signal_riscv64.go b/src/runtime/signal_riscv64.go index 93363a4746..e6b1b14130 100644 --- a/src/runtime/signal_riscv64.go +++ b/src/runtime/signal_riscv64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && riscv64 // +build linux,riscv64 package runtime diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 3f70707ab4..f2e526973d 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/signal_windows_test.go b/src/runtime/signal_windows_test.go index 33a9b92ee7..05bc6f8e71 100644 --- a/src/runtime/signal_windows_test.go +++ b/src/runtime/signal_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package runtime_test diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go index 28b9e26d0f..a282c7aca7 100644 --- a/src/runtime/sigqueue.go +++ b/src/runtime/sigqueue.go @@ -28,6 +28,7 @@ // unnecessary rechecks of sig.mask, but it cannot lead to missed signals // nor deadlocks. +//go:build !plan9 // +build !plan9 package runtime diff --git a/src/runtime/sigqueue_note.go b/src/runtime/sigqueue_note.go index 16aeeb2ef0..e23446bea4 100644 --- a/src/runtime/sigqueue_note.go +++ b/src/runtime/sigqueue_note.go @@ -7,8 +7,8 @@ // signal_recv thread. This file holds the non-Darwin implementations of // those functions. These functions will never be called. -// +build !darwin -// +build !plan9 +//go:build !darwin && !plan9 +// +build !darwin,!plan9 package runtime diff --git a/src/runtime/sigtab_linux_generic.go b/src/runtime/sigtab_linux_generic.go index 38d686544f..dc1debddab 100644 --- a/src/runtime/sigtab_linux_generic.go +++ b/src/runtime/sigtab_linux_generic.go @@ -2,11 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !mips -// +build !mipsle -// +build !mips64 -// +build !mips64le -// +build linux +//go:build !mips && !mipsle && !mips64 && !mips64le && linux +// +build !mips,!mipsle,!mips64,!mips64le,linux package runtime diff --git a/src/runtime/sigtab_linux_mipsx.go b/src/runtime/sigtab_linux_mipsx.go index 51ef470ce7..af9c7e56eb 100644 --- a/src/runtime/sigtab_linux_mipsx.go +++ b/src/runtime/sigtab_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (mips || mipsle || mips64 || mips64le) && linux // +build mips mipsle mips64 mips64le // +build linux diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 96096d236b..525b324c81 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -2,13 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !aix -// +build !darwin -// +build !js -// +build !openbsd -// +build !plan9 -// +build !solaris -// +build !windows +//go:build !aix && !darwin && !js && !openbsd && !plan9 && !solaris && !windows +// +build !aix,!darwin,!js,!openbsd,!plan9,!solaris,!windows package runtime diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go index 1885d32051..b895be4c70 100644 --- a/src/runtime/stubs3.go +++ b/src/runtime/stubs3.go @@ -2,12 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !aix -// +build !darwin -// +build !freebsd -// +build !openbsd -// +build !plan9 -// +build !solaris +//go:build !aix && !darwin && !freebsd && !openbsd && !plan9 && !solaris +// +build !aix,!darwin,!freebsd,!openbsd,!plan9,!solaris package runtime diff --git a/src/runtime/stubs_linux.go b/src/runtime/stubs_linux.go index e75fcf6c95..ba267009ca 100644 --- a/src/runtime/stubs_linux.go +++ b/src/runtime/stubs_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package runtime diff --git a/src/runtime/stubs_mips64x.go b/src/runtime/stubs_mips64x.go index 652e7a9e34..05a4d0d38d 100644 --- a/src/runtime/stubs_mips64x.go +++ b/src/runtime/stubs_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package runtime diff --git a/src/runtime/stubs_mipsx.go b/src/runtime/stubs_mipsx.go index 707b295f7a..9bffb35b67 100644 --- a/src/runtime/stubs_mipsx.go +++ b/src/runtime/stubs_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle package runtime diff --git a/src/runtime/stubs_nonlinux.go b/src/runtime/stubs_nonlinux.go index e1ea05cf0b..f9b98595fc 100644 --- a/src/runtime/stubs_nonlinux.go +++ b/src/runtime/stubs_nonlinux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !linux // +build !linux package runtime diff --git a/src/runtime/stubs_ppc64x.go b/src/runtime/stubs_ppc64x.go index 26f5bb20ca..0841b413fd 100644 --- a/src/runtime/stubs_ppc64x.go +++ b/src/runtime/stubs_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package runtime diff --git a/src/runtime/sys_libc.go b/src/runtime/sys_libc.go index 996c032105..99d073517b 100644 --- a/src/runtime/sys_libc.go +++ b/src/runtime/sys_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || (openbsd && amd64) || (openbsd && arm64) // +build darwin openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/sys_mips64x.go b/src/runtime/sys_mips64x.go index cb429c3147..842a4a7084 100644 --- a/src/runtime/sys_mips64x.go +++ b/src/runtime/sys_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips64 || mips64le // +build mips64 mips64le package runtime diff --git a/src/runtime/sys_mipsx.go b/src/runtime/sys_mipsx.go index 2819218d5f..2038eb7d79 100644 --- a/src/runtime/sys_mipsx.go +++ b/src/runtime/sys_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build mips || mipsle // +build mips mipsle package runtime diff --git a/src/runtime/sys_nonppc64x.go b/src/runtime/sys_nonppc64x.go index 440937498f..66821b1f76 100644 --- a/src/runtime/sys_nonppc64x.go +++ b/src/runtime/sys_nonppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !ppc64 && !ppc64le // +build !ppc64,!ppc64le package runtime diff --git a/src/runtime/sys_openbsd.go b/src/runtime/sys_openbsd.go index fcddf4d6a5..362fa777ef 100644 --- a/src/runtime/sys_openbsd.go +++ b/src/runtime/sys_openbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd1.go b/src/runtime/sys_openbsd1.go index 44c7871ceb..43e0058985 100644 --- a/src/runtime/sys_openbsd1.go +++ b/src/runtime/sys_openbsd1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd2.go b/src/runtime/sys_openbsd2.go index 33032596c3..73157043be 100644 --- a/src/runtime/sys_openbsd2.go +++ b/src/runtime/sys_openbsd2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/sys_openbsd3.go b/src/runtime/sys_openbsd3.go index 4d4c88e3ac..751c00c2b3 100644 --- a/src/runtime/sys_openbsd3.go +++ b/src/runtime/sys_openbsd3.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package runtime diff --git a/src/runtime/sys_ppc64x.go b/src/runtime/sys_ppc64x.go index 796f27c4e3..69bd99fa09 100644 --- a/src/runtime/sys_ppc64x.go +++ b/src/runtime/sys_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ppc64 || ppc64le // +build ppc64 ppc64le package runtime diff --git a/src/runtime/sys_x86.go b/src/runtime/sys_x86.go index 8f21585d28..0866e3140e 100644 --- a/src/runtime/sys_x86.go +++ b/src/runtime/sys_x86.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 || 386 // +build amd64 386 package runtime diff --git a/src/runtime/time_fake.go b/src/runtime/time_fake.go index c64d2994a9..1238744ebf 100644 --- a/src/runtime/time_fake.go +++ b/src/runtime/time_fake.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build faketime -// +build !windows +//go:build faketime && !windows +// +build faketime,!windows // Faketime isn't currently supported on Windows. This would require: // diff --git a/src/runtime/time_nofake.go b/src/runtime/time_nofake.go index 1912a94e87..13bf1c2d4f 100644 --- a/src/runtime/time_nofake.go +++ b/src/runtime/time_nofake.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !faketime // +build !faketime package runtime diff --git a/src/runtime/timeasm.go b/src/runtime/timeasm.go index 82cf63edff..fe38a086fc 100644 --- a/src/runtime/timeasm.go +++ b/src/runtime/timeasm.go @@ -4,6 +4,7 @@ // Declarations for operating systems implementing time.now directly in assembly. +//go:build windows // +build windows package runtime diff --git a/src/runtime/timestub.go b/src/runtime/timestub.go index 459bf8e543..2ef8d4665f 100644 --- a/src/runtime/timestub.go +++ b/src/runtime/timestub.go @@ -5,6 +5,7 @@ // Declarations for operating systems implementing time.now // indirectly, in terms of walltime and nanotime assembly. +//go:build !windows // +build !windows package runtime diff --git a/src/runtime/timestub2.go b/src/runtime/timestub2.go index 68777ee4a9..53b10885af 100644 --- a/src/runtime/timestub2.go +++ b/src/runtime/timestub2.go @@ -2,12 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !aix -// +build !darwin -// +build !freebsd -// +build !openbsd -// +build !solaris -// +build !windows +//go:build !aix && !darwin && !freebsd && !openbsd && !solaris && !windows +// +build !aix,!darwin,!freebsd,!openbsd,!solaris,!windows package runtime diff --git a/src/runtime/vdso_elf32.go b/src/runtime/vdso_elf32.go index 2720f33eed..456173b0f5 100644 --- a/src/runtime/vdso_elf32.go +++ b/src/runtime/vdso_elf32.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (386 || arm) // +build linux // +build 386 arm diff --git a/src/runtime/vdso_elf64.go b/src/runtime/vdso_elf64.go index 6ded9d621a..9923bd4697 100644 --- a/src/runtime/vdso_elf64.go +++ b/src/runtime/vdso_elf64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le) // +build linux // +build amd64 arm64 mips64 mips64le ppc64 ppc64le diff --git a/src/runtime/vdso_freebsd.go b/src/runtime/vdso_freebsd.go index 122cc8b128..74b2f1435a 100644 --- a/src/runtime/vdso_freebsd.go +++ b/src/runtime/vdso_freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd // +build freebsd package runtime diff --git a/src/runtime/vdso_freebsd_x86.go b/src/runtime/vdso_freebsd_x86.go index 1fa5d80dcc..23a5a8c322 100644 --- a/src/runtime/vdso_freebsd_x86.go +++ b/src/runtime/vdso_freebsd_x86.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd && (386 || amd64) // +build freebsd // +build 386 amd64 diff --git a/src/runtime/vdso_in_none.go b/src/runtime/vdso_in_none.go index 7f4019c0d6..c66fbf8216 100644 --- a/src/runtime/vdso_in_none.go +++ b/src/runtime/vdso_in_none.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le) || !linux // +build linux,!386,!amd64,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le !linux package runtime diff --git a/src/runtime/vdso_linux.go b/src/runtime/vdso_linux.go index 6e2942498d..ae211f96b1 100644 --- a/src/runtime/vdso_linux.go +++ b/src/runtime/vdso_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (386 || amd64 || arm || arm64 || mips64 || mips64le || ppc64 || ppc64le) // +build linux // +build 386 amd64 arm arm64 mips64 mips64le ppc64 ppc64le diff --git a/src/runtime/vdso_linux_mips64x.go b/src/runtime/vdso_linux_mips64x.go index 3a0f947612..395ddbba69 100644 --- a/src/runtime/vdso_linux_mips64x.go +++ b/src/runtime/vdso_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/runtime/vdso_linux_ppc64x.go b/src/runtime/vdso_linux_ppc64x.go index f30946e4c5..b741dbfcdc 100644 --- a/src/runtime/vdso_linux_ppc64x.go +++ b/src/runtime/vdso_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go index 996c0611fd..cf631bdcca 100644 --- a/src/runtime/vlrt.go +++ b/src/runtime/vlrt.go @@ -23,6 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +//go:build arm || 386 || mips || mipsle // +build arm 386 mips mipsle package runtime diff --git a/src/runtime/wincallback.go b/src/runtime/wincallback.go index cf3327c6fe..56f0674f4e 100644 --- a/src/runtime/wincallback.go +++ b/src/runtime/wincallback.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // Generate Windows callback assembly file. diff --git a/src/runtime/write_err.go b/src/runtime/write_err.go index 6b1467b1c4..a4656fd728 100644 --- a/src/runtime/write_err.go +++ b/src/runtime/write_err.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !android // +build !android package runtime diff --git a/src/sort/genzfunc.go b/src/sort/genzfunc.go index e7eb573737..ed04e33568 100644 --- a/src/sort/genzfunc.go +++ b/src/sort/genzfunc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program is run via "go generate" (via a directive in sort.go) diff --git a/src/sort/slice_go113.go b/src/sort/slice_go113.go index bf24db714a..53542dbd1a 100644 --- a/src/sort/slice_go113.go +++ b/src/sort/slice_go113.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.13 // +build go1.13 package sort diff --git a/src/sort/slice_go14.go b/src/sort/slice_go14.go index 3bf5cbc00b..5d5949f3ca 100644 --- a/src/sort/slice_go14.go +++ b/src/sort/slice_go14.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.8 // +build !go1.8 package sort diff --git a/src/sort/slice_go18.go b/src/sort/slice_go18.go index e1766040a7..1538477bc5 100644 --- a/src/sort/slice_go18.go +++ b/src/sort/slice_go18.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.8 && !go1.13 // +build go1.8,!go1.13 package sort diff --git a/src/strconv/bytealg.go b/src/strconv/bytealg.go index 7f66f2a8bb..9780c28ef3 100644 --- a/src/strconv/bytealg.go +++ b/src/strconv/bytealg.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !compiler_bootstrap // +build !compiler_bootstrap package strconv diff --git a/src/strconv/bytealg_bootstrap.go b/src/strconv/bytealg_bootstrap.go index a3a547d1b6..875a0eb147 100644 --- a/src/strconv/bytealg_bootstrap.go +++ b/src/strconv/bytealg_bootstrap.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build compiler_bootstrap // +build compiler_bootstrap package strconv diff --git a/src/strconv/makeisprint.go b/src/strconv/makeisprint.go index 0e6e90a6c6..79678341d4 100644 --- a/src/strconv/makeisprint.go +++ b/src/strconv/makeisprint.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go index ad98350b2b..65666daab4 100644 --- a/src/sync/pool_test.go +++ b/src/sync/pool_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Pool is no-op under race detector, so all these tests do not work. +//go:build !race // +build !race package sync_test diff --git a/src/sync/runtime2.go b/src/sync/runtime2.go index f10c4e8e0e..c4b44893f0 100644 --- a/src/sync/runtime2.go +++ b/src/sync/runtime2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !goexperiment.staticlockranking // +build !goexperiment.staticlockranking package sync diff --git a/src/sync/runtime2_lockrank.go b/src/sync/runtime2_lockrank.go index aaa1c27626..e91fdb6c1f 100644 --- a/src/sync/runtime2_lockrank.go +++ b/src/sync/runtime2_lockrank.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build goexperiment.staticlockranking // +build goexperiment.staticlockranking package sync diff --git a/src/syscall/bpf_bsd.go b/src/syscall/bpf_bsd.go index f67ee6064b..452d4cf14b 100644 --- a/src/syscall/bpf_bsd.go +++ b/src/syscall/bpf_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || netbsd || openbsd // +build dragonfly freebsd netbsd openbsd // Berkeley packet filter for BSD variants diff --git a/src/syscall/creds_test.go b/src/syscall/creds_test.go index 524689ae2d..463033d558 100644 --- a/src/syscall/creds_test.go +++ b/src/syscall/creds_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package syscall_test diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go index fab123d4a7..9e1222e81c 100644 --- a/src/syscall/dirent.go +++ b/src/syscall/dirent.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package syscall diff --git a/src/syscall/dirent_test.go b/src/syscall/dirent_test.go index 7dac98ff4b..8ed3caa9d4 100644 --- a/src/syscall/dirent_test.go +++ b/src/syscall/dirent_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test diff --git a/src/syscall/endian_big.go b/src/syscall/endian_big.go index 3c26005ab5..dc0947fa6e 100644 --- a/src/syscall/endian_big.go +++ b/src/syscall/endian_big.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +//go:build ppc64 || s390x || mips || mips64 // +build ppc64 s390x mips mips64 package syscall diff --git a/src/syscall/endian_little.go b/src/syscall/endian_little.go index 43b081d640..a894445f73 100644 --- a/src/syscall/endian_little.go +++ b/src/syscall/endian_little.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +//go:build 386 || amd64 || arm || arm64 || ppc64le || mips64le || mipsle || riscv64 || wasm // +build 386 amd64 arm arm64 ppc64le mips64le mipsle riscv64 wasm package syscall diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go index a4bb28cc45..022ef6ed73 100644 --- a/src/syscall/env_unix.go +++ b/src/syscall/env_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || plan9 // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9 // Unix environment variables. diff --git a/src/syscall/exec_aix_test.go b/src/syscall/exec_aix_test.go index 22b752cf27..17c7ac0664 100644 --- a/src/syscall/exec_aix_test.go +++ b/src/syscall/exec_aix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix // +build aix package syscall diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 940a81b58e..9c1fbbaeab 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || netbsd || (openbsd && !amd64 && !arm64) // +build dragonfly freebsd netbsd openbsd,!amd64,!arm64 package syscall diff --git a/src/syscall/exec_libc.go b/src/syscall/exec_libc.go index 3722858325..3c8e87d32f 100644 --- a/src/syscall/exec_libc.go +++ b/src/syscall/exec_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || solaris // +build aix solaris // This file handles forkAndExecInChild function for OS using libc syscall like AIX or Solaris. diff --git a/src/syscall/exec_libc2.go b/src/syscall/exec_libc2.go index 45d3f85baf..507eff8ab3 100644 --- a/src/syscall/exec_libc2.go +++ b/src/syscall/exec_libc2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || (openbsd && amd64) || (openbsd && arm64) // +build darwin openbsd,amd64 openbsd,arm64 package syscall diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index b6acad96ea..b0099cb4b0 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package syscall diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index ac3a5754ae..7d89eaae63 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package syscall_test diff --git a/src/syscall/exec_solaris_test.go b/src/syscall/exec_solaris_test.go index 6b8f1ad383..f54fc8385d 100644 --- a/src/syscall/exec_solaris_test.go +++ b/src/syscall/exec_solaris_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build solaris // +build solaris package syscall diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go index 1f49c78ef9..1f38de22b2 100644 --- a/src/syscall/exec_unix.go +++ b/src/syscall/exec_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Fork, exec, wait, etc. diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go index d6b6f51fa6..10bad5ac46 100644 --- a/src/syscall/exec_unix_test.go +++ b/src/syscall/exec_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test diff --git a/src/syscall/export_unix_test.go b/src/syscall/export_unix_test.go index 4c3d0f6d2a..2d2c67673d 100644 --- a/src/syscall/export_unix_test.go +++ b/src/syscall/export_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build dragonfly || freebsd || linux || netbsd || openbsd // +build dragonfly freebsd linux netbsd openbsd package syscall diff --git a/src/syscall/flock.go b/src/syscall/flock.go index 568efca7d4..3b43b6aede 100644 --- a/src/syscall/flock.go +++ b/src/syscall/flock.go @@ -1,3 +1,4 @@ +//go:build linux || freebsd || openbsd || netbsd || dragonfly // +build linux freebsd openbsd netbsd dragonfly // Copyright 2014 The Go Authors. All rights reserved. diff --git a/src/syscall/flock_linux_32bit.go b/src/syscall/flock_linux_32bit.go index e11aed6ed1..2f3277497c 100644 --- a/src/syscall/flock_linux_32bit.go +++ b/src/syscall/flock_linux_32bit.go @@ -5,6 +5,7 @@ // If you change the build tags here, see // internal/syscall/unix/fcntl_linux_32bit.go. +//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) // +build linux,386 linux,arm linux,mips linux,mipsle package syscall diff --git a/src/syscall/forkpipe.go b/src/syscall/forkpipe.go index d9999cb8b8..c7ddcf26ab 100644 --- a/src/syscall/forkpipe.go +++ b/src/syscall/forkpipe.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || solaris // +build aix darwin dragonfly solaris package syscall diff --git a/src/syscall/forkpipe2.go b/src/syscall/forkpipe2.go index c9a0c4996e..cd98779ac9 100644 --- a/src/syscall/forkpipe2.go +++ b/src/syscall/forkpipe2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd || netbsd || openbsd // +build freebsd netbsd openbsd package syscall diff --git a/src/syscall/fs_js.go b/src/syscall/fs_js.go index 673feea77f..0170516201 100644 --- a/src/syscall/fs_js.go +++ b/src/syscall/fs_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package syscall diff --git a/src/syscall/getdirentries_test.go b/src/syscall/getdirentries_test.go index 66bb8acba2..936c8a163a 100644 --- a/src/syscall/getdirentries_test.go +++ b/src/syscall/getdirentries_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || freebsd || netbsd || openbsd // +build darwin freebsd netbsd openbsd package syscall_test diff --git a/src/syscall/mkasm.go b/src/syscall/mkasm.go index e53d14bed1..39461145e9 100644 --- a/src/syscall/mkasm.go +++ b/src/syscall/mkasm.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // mkasm.go generates assembly trampolines to call library routines from Go. diff --git a/src/syscall/mkpost.go b/src/syscall/mkpost.go index ef89128310..94e8d92eff 100644 --- a/src/syscall/mkpost.go +++ b/src/syscall/mkpost.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // mkpost processes the output of cgo -godefs to diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index 240254b2c7..d8e8a713c5 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // mksyscall_windows wraps golang.org/x/sys/windows/mkwinsyscall. diff --git a/src/syscall/mmap_unix_test.go b/src/syscall/mmap_unix_test.go index d0b3644b59..e3909f1afb 100644 --- a/src/syscall/mmap_unix_test.go +++ b/src/syscall/mmap_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build aix darwin dragonfly freebsd linux netbsd openbsd package syscall_test diff --git a/src/syscall/msan.go b/src/syscall/msan.go index baaad6df98..89fb75f03c 100644 --- a/src/syscall/msan.go +++ b/src/syscall/msan.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build msan // +build msan package syscall diff --git a/src/syscall/msan0.go b/src/syscall/msan0.go index ff10be9d25..85097025a0 100644 --- a/src/syscall/msan0.go +++ b/src/syscall/msan0.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !msan // +build !msan package syscall diff --git a/src/syscall/net_js.go b/src/syscall/net_js.go index 25f171bda8..ed462025bb 100644 --- a/src/syscall/net_js.go +++ b/src/syscall/net_js.go @@ -5,6 +5,7 @@ // js/wasm uses fake networking directly implemented in the net package. // This file only exists to make the compiler happy. +//go:build js && wasm // +build js,wasm package syscall diff --git a/src/syscall/ptrace_darwin.go b/src/syscall/ptrace_darwin.go index a873d826b8..b968c7c7f3 100644 --- a/src/syscall/ptrace_darwin.go +++ b/src/syscall/ptrace_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !ios // +build !ios package syscall diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go index b364eeaba5..e9321a4e64 100644 --- a/src/syscall/route_bsd.go +++ b/src/syscall/route_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package syscall diff --git a/src/syscall/route_freebsd_32bit.go b/src/syscall/route_freebsd_32bit.go index aed8682237..412833a37c 100644 --- a/src/syscall/route_freebsd_32bit.go +++ b/src/syscall/route_freebsd_32bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (freebsd && 386) || (freebsd && arm) // +build freebsd,386 freebsd,arm package syscall diff --git a/src/syscall/route_freebsd_64bit.go b/src/syscall/route_freebsd_64bit.go index e70ba3df89..5300bed471 100644 --- a/src/syscall/route_freebsd_64bit.go +++ b/src/syscall/route_freebsd_64bit.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (freebsd && amd64) || (freebsd && arm64) // +build freebsd,amd64 freebsd,arm64 package syscall diff --git a/src/syscall/setuidgid_32_linux.go b/src/syscall/setuidgid_32_linux.go index b0b7f61d22..64897fe43c 100644 --- a/src/syscall/setuidgid_32_linux.go +++ b/src/syscall/setuidgid_32_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (386 || arm) // +build linux // +build 386 arm diff --git a/src/syscall/setuidgid_linux.go b/src/syscall/setuidgid_linux.go index 38c83c92f9..3b36f66fa2 100644 --- a/src/syscall/setuidgid_linux.go +++ b/src/syscall/setuidgid_linux.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux -// +build !386,!arm +//go:build linux && !386 && !arm +// +build linux,!386,!arm package syscall diff --git a/src/syscall/sockcmsg_unix.go b/src/syscall/sockcmsg_unix.go index 1ff97a5ae1..99913b9a88 100644 --- a/src/syscall/sockcmsg_unix.go +++ b/src/syscall/sockcmsg_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // Socket control messages diff --git a/src/syscall/sockcmsg_unix_other.go b/src/syscall/sockcmsg_unix_other.go index 40f03142a6..bd8dcfa34c 100644 --- a/src/syscall/sockcmsg_unix_other.go +++ b/src/syscall/sockcmsg_unix_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin freebsd linux netbsd openbsd solaris package syscall diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go index 1c7ec588bc..595e705856 100644 --- a/src/syscall/syscall_bsd.go +++ b/src/syscall/syscall_bsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd // BSD system call wrappers shared by *BSD based systems diff --git a/src/syscall/syscall_bsd_test.go b/src/syscall/syscall_bsd_test.go index f2bc3f5147..2d8a8cbfe6 100644 --- a/src/syscall/syscall_bsd_test.go +++ b/src/syscall/syscall_bsd_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || openbsd // +build darwin dragonfly freebsd openbsd package syscall_test diff --git a/src/syscall/syscall_dup2_linux.go b/src/syscall/syscall_dup2_linux.go index f03a923112..351a96edc1 100644 --- a/src/syscall/syscall_dup2_linux.go +++ b/src/syscall/syscall_dup2_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !android && (386 || amd64 || arm || mips || mipsle || mips64 || mips64le || ppc64 || ppc64le || s390x) // +build !android // +build 386 amd64 arm mips mipsle mips64 mips64le ppc64 ppc64le s390x diff --git a/src/syscall/syscall_dup3_linux.go b/src/syscall/syscall_dup3_linux.go index 1ebdcb20a2..66ec67b0ab 100644 --- a/src/syscall/syscall_dup3_linux.go +++ b/src/syscall/syscall_dup3_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build android || arm64 || riscv64 // +build android arm64 riscv64 package syscall diff --git a/src/syscall/syscall_freebsd_test.go b/src/syscall/syscall_freebsd_test.go index 3ccfe5d463..89c7959d0c 100644 --- a/src/syscall/syscall_freebsd_test.go +++ b/src/syscall/syscall_freebsd_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build freebsd // +build freebsd package syscall_test diff --git a/src/syscall/syscall_illumos.go b/src/syscall/syscall_illumos.go index d70a436d13..ef95fe58f7 100644 --- a/src/syscall/syscall_illumos.go +++ b/src/syscall/syscall_illumos.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos // Illumos system calls not present on Solaris. diff --git a/src/syscall/syscall_js.go b/src/syscall/syscall_js.go index 0ab8c3fba4..c17c6fcdcf 100644 --- a/src/syscall/syscall_js.go +++ b/src/syscall/syscall_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package syscall diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go index ab25b7be6f..dd51f3d00a 100644 --- a/src/syscall/syscall_linux_mips64x.go +++ b/src/syscall/syscall_linux_mips64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) // +build linux // +build mips64 mips64le diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go index 377946fc92..7894bdd465 100644 --- a/src/syscall/syscall_linux_mipsx.go +++ b/src/syscall/syscall_linux_mipsx.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) // +build linux // +build mips mipsle diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go index 45bf667407..495ae29757 100644 --- a/src/syscall/syscall_linux_ppc64x.go +++ b/src/syscall/syscall_linux_ppc64x.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/src/syscall/syscall_openbsd1.go b/src/syscall/syscall_openbsd1.go index 2c7d0f8c90..0d6761d49e 100644 --- a/src/syscall/syscall_openbsd1.go +++ b/src/syscall/syscall_openbsd1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build openbsd && !amd64 && !arm64 // +build openbsd,!amd64,!arm64 package syscall diff --git a/src/syscall/syscall_openbsd_libc.go b/src/syscall/syscall_openbsd_libc.go index 042615bf2a..610c66fd34 100644 --- a/src/syscall/syscall_openbsd_libc.go +++ b/src/syscall/syscall_openbsd_libc.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (openbsd && amd64) || (openbsd && arm64) // +build openbsd,amd64 openbsd,arm64 package syscall diff --git a/src/syscall/syscall_ptrace_test.go b/src/syscall/syscall_ptrace_test.go index 6b7f54dcfd..45729d9e8e 100644 --- a/src/syscall/syscall_ptrace_test.go +++ b/src/syscall/syscall_ptrace_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd package syscall_test diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index 786ad34170..40fc8b8a30 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go index 7e6a8c9043..a05fff5136 100644 --- a/src/syscall/syscall_unix_test.go +++ b/src/syscall/syscall_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test diff --git a/src/syscall/tables_js.go b/src/syscall/tables_js.go index a7c4f8c890..64d958415d 100644 --- a/src/syscall/tables_js.go +++ b/src/syscall/tables_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package syscall diff --git a/src/syscall/time_fake.go b/src/syscall/time_fake.go index 5dec57a25a..cf88aeb921 100644 --- a/src/syscall/time_fake.go +++ b/src/syscall/time_fake.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build faketime // +build faketime package syscall diff --git a/src/syscall/time_nofake.go b/src/syscall/time_nofake.go index c94cef8686..5eaa2daabd 100644 --- a/src/syscall/time_nofake.go +++ b/src/syscall/time_nofake.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !faketime // +build !faketime package syscall diff --git a/src/syscall/timestruct.go b/src/syscall/timestruct.go index bca51df08d..e4f3d50f56 100644 --- a/src/syscall/timestruct.go +++ b/src/syscall/timestruct.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package syscall diff --git a/src/syscall/types_aix.go b/src/syscall/types_aix.go index cbc47cc6c1..6588d690ea 100644 --- a/src/syscall/types_aix.go +++ b/src/syscall/types_aix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_darwin.go b/src/syscall/types_darwin.go index 7b3a9d2335..c2a32c0782 100644 --- a/src/syscall/types_darwin.go +++ b/src/syscall/types_darwin.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_dragonfly.go b/src/syscall/types_dragonfly.go index 53bc12403b..9f8d5bc3dd 100644 --- a/src/syscall/types_dragonfly.go +++ b/src/syscall/types_dragonfly.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_freebsd.go b/src/syscall/types_freebsd.go index f686021121..d741411703 100644 --- a/src/syscall/types_freebsd.go +++ b/src/syscall/types_freebsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_illumos_amd64.go b/src/syscall/types_illumos_amd64.go index abb282f3e4..254e3e7cfe 100644 --- a/src/syscall/types_illumos_amd64.go +++ b/src/syscall/types_illumos_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build illumos // +build illumos // Illumos consts not present on Solaris. These are added manually rather than diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go index 9de32d9c01..bf76be978b 100644 --- a/src/syscall/types_linux.go +++ b/src/syscall/types_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_netbsd.go b/src/syscall/types_netbsd.go index 30ab2dc845..0bd25ea3c9 100644 --- a/src/syscall/types_netbsd.go +++ b/src/syscall/types_netbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_openbsd.go b/src/syscall/types_openbsd.go index 922864815b..8b41cdca23 100644 --- a/src/syscall/types_openbsd.go +++ b/src/syscall/types_openbsd.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/types_solaris.go b/src/syscall/types_solaris.go index 76a74508d2..179f791481 100644 --- a/src/syscall/types_solaris.go +++ b/src/syscall/types_solaris.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore /* diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go index 58799fbde7..0b9897284c 100644 --- a/src/syscall/zerrors_darwin_amd64.go +++ b/src/syscall/zerrors_darwin_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && darwin // +build amd64,darwin package syscall diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go index 8b433616ee..5f210fd1c4 100644 --- a/src/syscall/zerrors_darwin_arm64.go +++ b/src/syscall/zerrors_darwin_arm64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build arm64 && darwin // +build arm64,darwin package syscall diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go index 3434a85d34..b572f44a6b 100644 --- a/src/syscall/zerrors_dragonfly_amd64.go +++ b/src/syscall/zerrors_dragonfly_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && dragonfly // +build amd64,dragonfly package syscall diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go index 85786a5b4e..aec26ad778 100644 --- a/src/syscall/zerrors_freebsd_386.go +++ b/src/syscall/zerrors_freebsd_386.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +//go:build 386 && freebsd // +build 386,freebsd package syscall diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go index b3ebf3d474..d6d13e4155 100644 --- a/src/syscall/zerrors_freebsd_amd64.go +++ b/src/syscall/zerrors_freebsd_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && freebsd // +build amd64,freebsd package syscall diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go index 29eabb1d2d..15c714fad8 100644 --- a/src/syscall/zerrors_freebsd_arm.go +++ b/src/syscall/zerrors_freebsd_arm.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +//go:build arm && freebsd // +build arm,freebsd package syscall diff --git a/src/syscall/zerrors_freebsd_arm64.go b/src/syscall/zerrors_freebsd_arm64.go index 82ee158478..b20ce7d823 100644 --- a/src/syscall/zerrors_freebsd_arm64.go +++ b/src/syscall/zerrors_freebsd_arm64.go @@ -1,6 +1,7 @@ // mkerrors.sh -m64 // Code generated by the command above; DO NOT EDIT. +//go:build freebsd && arm64 // +build freebsd,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go index 53a442d108..fb64932ad6 100644 --- a/src/syscall/zerrors_linux_386.go +++ b/src/syscall/zerrors_linux_386.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +//go:build 386 && linux // +build 386,linux package syscall diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go index 0b4c60dd4c..3a92bcdbb4 100644 --- a/src/syscall/zerrors_linux_amd64.go +++ b/src/syscall/zerrors_linux_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && linux // +build amd64,linux package syscall diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go index 9a8d9e8579..e013d8e7fd 100644 --- a/src/syscall/zerrors_linux_arm.go +++ b/src/syscall/zerrors_linux_arm.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +//go:build arm && linux // +build arm,linux package syscall diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go index f0caf552b2..1a4d33e3fd 100644 --- a/src/syscall/zerrors_linux_arm64.go +++ b/src/syscall/zerrors_linux_arm64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +//go:build arm64 && linux // +build arm64,linux package syscall diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go index f064731ae5..1dda43be70 100644 --- a/src/syscall/zerrors_linux_ppc64.go +++ b/src/syscall/zerrors_linux_ppc64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build ppc64 && linux // +build ppc64,linux package syscall diff --git a/src/syscall/zerrors_linux_ppc64le.go b/src/syscall/zerrors_linux_ppc64le.go index 41e21a510e..6d56f1c998 100644 --- a/src/syscall/zerrors_linux_ppc64le.go +++ b/src/syscall/zerrors_linux_ppc64le.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build ppc64le && linux // +build ppc64le,linux package syscall diff --git a/src/syscall/zerrors_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go index bf1e4a74c3..6a58946a4a 100644 --- a/src/syscall/zerrors_netbsd_386.go +++ b/src/syscall/zerrors_netbsd_386.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +//go:build 386 && netbsd // +build 386,netbsd package syscall diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go index 247e78e6c6..f5c5c2f49c 100644 --- a/src/syscall/zerrors_netbsd_amd64.go +++ b/src/syscall/zerrors_netbsd_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && netbsd // +build amd64,netbsd package syscall diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go index f23cd8693f..c9d4579b41 100644 --- a/src/syscall/zerrors_netbsd_arm.go +++ b/src/syscall/zerrors_netbsd_arm.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -marm _const.go +//go:build arm && netbsd // +build arm,netbsd package syscall diff --git a/src/syscall/zerrors_netbsd_arm64.go b/src/syscall/zerrors_netbsd_arm64.go index 6f6453f6ee..e35bff7f3e 100644 --- a/src/syscall/zerrors_netbsd_arm64.go +++ b/src/syscall/zerrors_netbsd_arm64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build arm64 && netbsd // +build arm64,netbsd package syscall diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go index 7985abe3f0..04d1b3f177 100644 --- a/src/syscall/zerrors_openbsd_386.go +++ b/src/syscall/zerrors_openbsd_386.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +//go:build 386 && openbsd // +build 386,openbsd package syscall diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go index 9c4ff2955f..923a3a47c5 100644 --- a/src/syscall/zerrors_openbsd_amd64.go +++ b/src/syscall/zerrors_openbsd_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && openbsd // +build amd64,openbsd package syscall diff --git a/src/syscall/zerrors_openbsd_arm.go b/src/syscall/zerrors_openbsd_arm.go index 493a8389f2..89a4e6d89a 100644 --- a/src/syscall/zerrors_openbsd_arm.go +++ b/src/syscall/zerrors_openbsd_arm.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +//go:build arm && openbsd // +build arm,openbsd package syscall diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go index eba401544a..b7dee69602 100644 --- a/src/syscall/zerrors_solaris_amd64.go +++ b/src/syscall/zerrors_solaris_amd64.go @@ -4,6 +4,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +//go:build amd64 && solaris // +build amd64,solaris package syscall diff --git a/src/syscall/zsyscall_aix_ppc64.go b/src/syscall/zsyscall_aix_ppc64.go index 20625c1a3e..134ae41165 100644 --- a/src/syscall/zsyscall_aix_ppc64.go +++ b/src/syscall/zsyscall_aix_ppc64.go @@ -1,6 +1,7 @@ // mksyscall_libc.pl -aix -tags aix,ppc64 syscall_aix.go syscall_aix_ppc64.go // Code generated by the command above; DO NOT EDIT. +//go:build aix && ppc64 // +build aix,ppc64 package syscall diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 4f2cdf861e..13dfacdba2 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -darwin -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build darwin && amd64 // +build darwin,amd64 package syscall diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go index 0d8598d816..79576eedf7 100644 --- a/src/syscall/zsyscall_darwin_arm64.go +++ b/src/syscall/zsyscall_darwin_arm64.go @@ -1,6 +1,7 @@ // mksyscall.pl -darwin -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go // Code generated by the command above; DO NOT EDIT. +//go:build darwin && arm64 // +build darwin,arm64 package syscall diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 578b5a3e9e..4799d1dcb0 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -dragonfly -tags dragonfly,amd64 syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build dragonfly && amd64 // +build dragonfly,amd64 package syscall diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go index ddc265f190..7137d66f0b 100644 --- a/src/syscall/zsyscall_freebsd_386.go +++ b/src/syscall/zsyscall_freebsd_386.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go // Code generated by the command above; DO NOT EDIT. +//go:build freebsd && 386 // +build freebsd,386 package syscall diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go index a0f79522b9..d721dafde2 100644 --- a/src/syscall/zsyscall_freebsd_amd64.go +++ b/src/syscall/zsyscall_freebsd_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build freebsd && amd64 // +build freebsd,amd64 package syscall diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go index 2cd23d3db6..d9dbea921a 100644 --- a/src/syscall/zsyscall_freebsd_arm.go +++ b/src/syscall/zsyscall_freebsd_arm.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go // Code generated by the command above; DO NOT EDIT. +//go:build freebsd && arm // +build freebsd,arm package syscall diff --git a/src/syscall/zsyscall_freebsd_arm64.go b/src/syscall/zsyscall_freebsd_arm64.go index 1b177383c2..a24f0115e2 100644 --- a/src/syscall/zsyscall_freebsd_arm64.go +++ b/src/syscall/zsyscall_freebsd_arm64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags freebsd,arm64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm64.go // Code generated by the command above; DO NOT EDIT. +//go:build freebsd && arm64 // +build freebsd,arm64 package syscall diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 5a749ff3f3..ac822d6f7a 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && 386 // +build linux,386 package syscall diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 34b624c1d4..ed37fa8dec 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && amd64 // +build linux,amd64 package syscall diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index 4d133766f7..213aaf3bac 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && arm // +build linux,arm package syscall diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index e7f7b7e3f8..e2f9c0fd9b 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,arm64 syscall_linux.go syscall_linux_arm64.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && arm64 // +build linux,arm64 package syscall diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index a8522dc571..617c2f5466 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -1,6 +1,7 @@ // mksyscall.pl -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && mips // +build linux,mips package syscall diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 1219fcc6cb..793d4b9884 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && mips64 // +build linux,mips64 package syscall diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index c3737bf3cf..54e1760bda 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,mips64le syscall_linux.go syscall_linux_mips64x.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && mips64le // +build linux,mips64le package syscall diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index 5006f4a409..ba7e2118c0 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && mipsle // +build linux,mipsle package syscall diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index 323be988be..c3437722e0 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && ppc64 // +build linux,ppc64 package syscall diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index 99aea6b559..acc34a76d2 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && ppc64le // +build linux,ppc64le package syscall diff --git a/src/syscall/zsyscall_linux_riscv64.go b/src/syscall/zsyscall_linux_riscv64.go index afa8945944..d662d780db 100644 --- a/src/syscall/zsyscall_linux_riscv64.go +++ b/src/syscall/zsyscall_linux_riscv64.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,riscv64 syscall_linux.go syscall_linux_riscv64.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && riscv64 // +build linux,riscv64 package syscall diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go index 5717206f28..20f8c61366 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -1,6 +1,7 @@ // mksyscall.pl -tags linux,s390x syscall_linux.go syscall_linux_s390x.go // Code generated by the command above; DO NOT EDIT. +//go:build linux && s390x // +build linux,s390x package syscall diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go index 7e0210081e..07ff5fba5f 100644 --- a/src/syscall/zsyscall_netbsd_386.go +++ b/src/syscall/zsyscall_netbsd_386.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -netbsd -tags netbsd,386 syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go // Code generated by the command above; DO NOT EDIT. +//go:build netbsd && 386 // +build netbsd,386 package syscall diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go index e9ee790501..ffb4e059a4 100644 --- a/src/syscall/zsyscall_netbsd_amd64.go +++ b/src/syscall/zsyscall_netbsd_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -netbsd -tags netbsd,amd64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build netbsd && amd64 // +build netbsd,amd64 package syscall diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go index 37438b020b..37df77e5e8 100644 --- a/src/syscall/zsyscall_netbsd_arm.go +++ b/src/syscall/zsyscall_netbsd_arm.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -netbsd -arm -tags netbsd,arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go // Code generated by the command above; DO NOT EDIT. +//go:build netbsd && arm // +build netbsd,arm package syscall diff --git a/src/syscall/zsyscall_netbsd_arm64.go b/src/syscall/zsyscall_netbsd_arm64.go index 758f398228..c5eb57a226 100644 --- a/src/syscall/zsyscall_netbsd_arm64.go +++ b/src/syscall/zsyscall_netbsd_arm64.go @@ -1,6 +1,7 @@ // mksyscall.pl -netbsd -tags netbsd,arm64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm64.go // Code generated by the command above; DO NOT EDIT. +//go:build netbsd && arm64 // +build netbsd,arm64 package syscall diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index decd169f0d..7d4c4d342a 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -openbsd -tags openbsd,386 syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go // Code generated by the command above; DO NOT EDIT. +//go:build openbsd && 386 // +build openbsd,386 package syscall diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 733050ad1d..b4698b79e2 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -openbsd -libc -tags openbsd,amd64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_libc.go syscall_openbsd_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build openbsd && amd64 // +build openbsd,amd64 package syscall diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go index dce0a540e6..31425b3558 100644 --- a/src/syscall/zsyscall_openbsd_arm.go +++ b/src/syscall/zsyscall_openbsd_arm.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go // Code generated by the command above; DO NOT EDIT. +//go:build openbsd && arm // +build openbsd,arm package syscall diff --git a/src/syscall/zsyscall_openbsd_arm64.go b/src/syscall/zsyscall_openbsd_arm64.go index 2093eb74e5..de6db1e3fa 100644 --- a/src/syscall/zsyscall_openbsd_arm64.go +++ b/src/syscall/zsyscall_openbsd_arm64.go @@ -1,6 +1,7 @@ // mksyscall.pl -openbsd -libc -tags openbsd,arm64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_libc.go syscall_openbsd_arm64.go // Code generated by the command above; DO NOT EDIT. +//go:build openbsd && arm64 // +build openbsd,arm64 package syscall diff --git a/src/syscall/zsyscall_openbsd_mips64.go b/src/syscall/zsyscall_openbsd_mips64.go index ded05686c4..70fd1474fd 100644 --- a/src/syscall/zsyscall_openbsd_mips64.go +++ b/src/syscall/zsyscall_openbsd_mips64.go @@ -1,6 +1,7 @@ // mksyscall.pl -openbsd -tags openbsd,mips64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_mips64x.go // Code generated by the command above; DO NOT EDIT. +//go:build openbsd && mips64 // +build openbsd,mips64 package syscall diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go index 998c6c555e..8b7727b343 100644 --- a/src/syscall/zsyscall_plan9_386.go +++ b/src/syscall/zsyscall_plan9_386.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -plan9 -tags plan9,386 syscall_plan9.go // Code generated by the command above; DO NOT EDIT. +//go:build plan9 && 386 // +build plan9,386 package syscall diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go index 02a28294ea..bed9108ea6 100644 --- a/src/syscall/zsyscall_plan9_amd64.go +++ b/src/syscall/zsyscall_plan9_amd64.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -plan9 -tags plan9,amd64 syscall_plan9.go // Code generated by the command above; DO NOT EDIT. +//go:build plan9 && amd64 // +build plan9,amd64 package syscall diff --git a/src/syscall/zsyscall_plan9_arm.go b/src/syscall/zsyscall_plan9_arm.go index 449823976d..7bbcf9b4b7 100644 --- a/src/syscall/zsyscall_plan9_arm.go +++ b/src/syscall/zsyscall_plan9_arm.go @@ -1,6 +1,7 @@ // mksyscall.pl -l32 -plan9 -tags plan9,arm syscall_plan9.go // Code generated by the command above; DO NOT EDIT. +//go:build plan9 && arm // +build plan9,arm package syscall diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go index 446ebfc503..9b37dc0950 100644 --- a/src/syscall/zsyscall_solaris_amd64.go +++ b/src/syscall/zsyscall_solaris_amd64.go @@ -1,6 +1,7 @@ // mksyscall_libc.pl -solaris -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go // Code generated by the command above; DO NOT EDIT. +//go:build solaris && amd64 // +build solaris,amd64 package syscall diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go index a2331bee8a..f66f7d2715 100644 --- a/src/syscall/zsysnum_darwin_amd64.go +++ b/src/syscall/zsysnum_darwin_amd64.go @@ -1,6 +1,7 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && darwin // +build amd64,darwin package syscall diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go index 9548717945..6fa146368a 100644 --- a/src/syscall/zsysnum_darwin_arm64.go +++ b/src/syscall/zsysnum_darwin_arm64.go @@ -1,6 +1,7 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // Code generated by the command above; DO NOT EDIT. +//go:build arm64 && darwin // +build arm64,darwin package syscall diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go index 9ce11f5899..855188f045 100644 --- a/src/syscall/zsysnum_dragonfly_amd64.go +++ b/src/syscall/zsysnum_dragonfly_amd64.go @@ -1,6 +1,7 @@ // mksysnum_dragonfly.pl // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && dragonfly // +build amd64,dragonfly package syscall diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go index bb6e9d7ac3..1ed7e3ee8d 100644 --- a/src/syscall/zsysnum_freebsd_386.go +++ b/src/syscall/zsysnum_freebsd_386.go @@ -1,6 +1,7 @@ // mksysnum_freebsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build 386 && freebsd // +build 386,freebsd package syscall diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go index f5d81abc51..d72dbc944a 100644 --- a/src/syscall/zsysnum_freebsd_amd64.go +++ b/src/syscall/zsysnum_freebsd_amd64.go @@ -1,6 +1,7 @@ // mksysnum_freebsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && freebsd // +build amd64,freebsd package syscall diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go index 006b49c245..4f4dc4db79 100644 --- a/src/syscall/zsysnum_freebsd_arm.go +++ b/src/syscall/zsysnum_freebsd_arm.go @@ -1,6 +1,7 @@ // mksysnum_freebsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm && freebsd // +build arm,freebsd package syscall diff --git a/src/syscall/zsysnum_freebsd_arm64.go b/src/syscall/zsysnum_freebsd_arm64.go index 0ce3d05cf2..ab1a05258e 100644 --- a/src/syscall/zsysnum_freebsd_arm64.go +++ b/src/syscall/zsysnum_freebsd_arm64.go @@ -1,6 +1,7 @@ // mksysnum_freebsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm64 && freebsd // +build arm64,freebsd package syscall diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go index 6bcd22185e..792f43550e 100644 --- a/src/syscall/zsysnum_linux_386.go +++ b/src/syscall/zsysnum_linux_386.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl /usr/include/asm/unistd_32.h // Code generated by the command above; DO NOT EDIT. +//go:build 386 && linux // +build 386,linux package syscall diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go index 70ca68639f..9ea18d6111 100644 --- a/src/syscall/zsysnum_linux_amd64.go +++ b/src/syscall/zsysnum_linux_amd64.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl /usr/include/asm/unistd_64.h // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && linux // +build amd64,linux package syscall diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go index 39ddc6536b..ccae9c15e3 100644 --- a/src/syscall/zsysnum_linux_arm.go +++ b/src/syscall/zsysnum_linux_arm.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm && linux // +build arm,linux package syscall diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go index 22a88b4dfe..17c54a2c83 100644 --- a/src/syscall/zsysnum_linux_arm64.go +++ b/src/syscall/zsysnum_linux_arm64.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl /usr/include/asm-generic/unistd.h // Code generated by the command above; DO NOT EDIT. +//go:build arm64 && linux // +build arm64,linux package syscall diff --git a/src/syscall/zsysnum_linux_ppc64.go b/src/syscall/zsysnum_linux_ppc64.go index 5882a7c058..a0d37ff1f2 100644 --- a/src/syscall/zsysnum_linux_ppc64.go +++ b/src/syscall/zsysnum_linux_ppc64.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl /usr/include/asm/unistd.h // Code generated by the command above; DO NOT EDIT. +//go:build ppc64 && linux // +build ppc64,linux package syscall diff --git a/src/syscall/zsysnum_linux_ppc64le.go b/src/syscall/zsysnum_linux_ppc64le.go index 4fb3f6cd29..f8f82d2043 100644 --- a/src/syscall/zsysnum_linux_ppc64le.go +++ b/src/syscall/zsysnum_linux_ppc64le.go @@ -1,6 +1,7 @@ // mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h // Code generated by the command above; DO NOT EDIT. +//go:build ppc64le && linux // +build ppc64le,linux package syscall diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go index 514d1f8cfd..4ff8d80341 100644 --- a/src/syscall/zsysnum_netbsd_386.go +++ b/src/syscall/zsysnum_netbsd_386.go @@ -1,6 +1,7 @@ // mksysnum_netbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build 386 && netbsd // +build 386,netbsd package syscall diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go index db05c03ecd..929da07604 100644 --- a/src/syscall/zsysnum_netbsd_amd64.go +++ b/src/syscall/zsysnum_netbsd_amd64.go @@ -1,6 +1,7 @@ // mksysnum_netbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && netbsd // +build amd64,netbsd package syscall diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go index 9a10a4383a..998238518b 100644 --- a/src/syscall/zsysnum_netbsd_arm.go +++ b/src/syscall/zsysnum_netbsd_arm.go @@ -1,6 +1,7 @@ // mksysnum_netbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm && netbsd // +build arm,netbsd package syscall diff --git a/src/syscall/zsysnum_netbsd_arm64.go b/src/syscall/zsysnum_netbsd_arm64.go index 31e13bf3b6..b3f5034390 100644 --- a/src/syscall/zsysnum_netbsd_arm64.go +++ b/src/syscall/zsysnum_netbsd_arm64.go @@ -1,6 +1,7 @@ // mksysnum_netbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm64 && netbsd // +build arm64,netbsd package syscall diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go index 39b9c78288..b289886d6c 100644 --- a/src/syscall/zsysnum_openbsd_386.go +++ b/src/syscall/zsysnum_openbsd_386.go @@ -1,6 +1,7 @@ // mksysnum_openbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build 386 && openbsd // +build 386,openbsd package syscall diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go index e176c4e23e..8cf2b68dcd 100644 --- a/src/syscall/zsysnum_openbsd_amd64.go +++ b/src/syscall/zsysnum_openbsd_amd64.go @@ -1,6 +1,7 @@ // mksysnum_openbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build amd64 && openbsd // +build amd64,openbsd package syscall diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go index 96bbdb09f5..cc33773a05 100644 --- a/src/syscall/zsysnum_openbsd_arm.go +++ b/src/syscall/zsysnum_openbsd_arm.go @@ -1,6 +1,7 @@ // mksysnum_openbsd.pl // Code generated by the command above; DO NOT EDIT. +//go:build arm && openbsd // +build arm,openbsd package syscall diff --git a/src/syscall/zsysnum_solaris_amd64.go b/src/syscall/zsysnum_solaris_amd64.go index be198f899b..23c9c715b5 100644 --- a/src/syscall/zsysnum_solaris_amd64.go +++ b/src/syscall/zsysnum_solaris_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 && solaris // +build amd64,solaris package syscall diff --git a/src/syscall/ztypes_darwin_amd64.go b/src/syscall/ztypes_darwin_amd64.go index da56f0da22..8feacc47ab 100644 --- a/src/syscall/ztypes_darwin_amd64.go +++ b/src/syscall/ztypes_darwin_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +//go:build amd64 && darwin // +build amd64,darwin package syscall diff --git a/src/syscall/ztypes_darwin_arm64.go b/src/syscall/ztypes_darwin_arm64.go index 82685ff659..8079d22429 100644 --- a/src/syscall/ztypes_darwin_arm64.go +++ b/src/syscall/ztypes_darwin_arm64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +//go:build arm64 && darwin // +build arm64,darwin package syscall diff --git a/src/syscall/ztypes_dragonfly_amd64.go b/src/syscall/ztypes_dragonfly_amd64.go index e9e811f776..a51e0038bb 100644 --- a/src/syscall/ztypes_dragonfly_amd64.go +++ b/src/syscall/ztypes_dragonfly_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_dragonfly.go +//go:build amd64 && dragonfly // +build amd64,dragonfly package syscall diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go index 27d82dea10..1739726883 100644 --- a/src/syscall/ztypes_freebsd_386.go +++ b/src/syscall/ztypes_freebsd_386.go @@ -1,6 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go | go run mkpost.go +//go:build 386 && freebsd // +build 386,freebsd package syscall diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go index 8abfbb45d6..0457d8e995 100644 --- a/src/syscall/ztypes_freebsd_amd64.go +++ b/src/syscall/ztypes_freebsd_amd64.go @@ -1,6 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go | go run mkpost.go +//go:build amd64 && freebsd // +build amd64,freebsd package syscall diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go index ff552a6a63..29c8380d89 100644 --- a/src/syscall/ztypes_freebsd_arm.go +++ b/src/syscall/ztypes_freebsd_arm.go @@ -1,6 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -fsigned-char types_freebsd.go +//go:build arm && freebsd // +build arm,freebsd package syscall diff --git a/src/syscall/ztypes_freebsd_arm64.go b/src/syscall/ztypes_freebsd_arm64.go index 6d56fc85cf..6472db0080 100644 --- a/src/syscall/ztypes_freebsd_arm64.go +++ b/src/syscall/ztypes_freebsd_arm64.go @@ -1,6 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go | go run mkpost.go +//go:build arm64 && freebsd // +build arm64,freebsd package syscall diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go index 0252620f48..251a0c0b4a 100644 --- a/src/syscall/ztypes_linux_386.go +++ b/src/syscall/ztypes_linux_386.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +//go:build 386 && linux // +build 386,linux package syscall diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go index 1fb0ee566f..34c953fc8b 100644 --- a/src/syscall/ztypes_linux_amd64.go +++ b/src/syscall/ztypes_linux_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +//go:build amd64 && linux // +build amd64,linux package syscall diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go index a88b577bed..4de656b491 100644 --- a/src/syscall/ztypes_linux_arm.go +++ b/src/syscall/ztypes_linux_arm.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +//go:build arm && linux // +build arm,linux package syscall diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go index f63391cdad..bed9cb0851 100644 --- a/src/syscall/ztypes_linux_arm64.go +++ b/src/syscall/ztypes_linux_arm64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -fsigned-char types_linux.go +//go:build arm64 && linux // +build arm64,linux package syscall diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go index 8b6be21e2e..355533fb27 100644 --- a/src/syscall/ztypes_linux_ppc64.go +++ b/src/syscall/ztypes_linux_ppc64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +//go:build ppc64 && linux // +build ppc64,linux package syscall diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go index a9c3ee2626..94e12c742c 100644 --- a/src/syscall/ztypes_linux_ppc64le.go +++ b/src/syscall/ztypes_linux_ppc64le.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +//go:build ppc64le && linux // +build ppc64le,linux package syscall diff --git a/src/syscall/ztypes_netbsd_386.go b/src/syscall/ztypes_netbsd_386.go index 737abb87c7..321460f45a 100644 --- a/src/syscall/ztypes_netbsd_386.go +++ b/src/syscall/ztypes_netbsd_386.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +//go:build 386 && netbsd // +build 386,netbsd package syscall diff --git a/src/syscall/ztypes_netbsd_amd64.go b/src/syscall/ztypes_netbsd_amd64.go index cf059f79ff..370d717263 100644 --- a/src/syscall/ztypes_netbsd_amd64.go +++ b/src/syscall/ztypes_netbsd_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +//go:build amd64 && netbsd // +build amd64,netbsd package syscall diff --git a/src/syscall/ztypes_netbsd_arm.go b/src/syscall/ztypes_netbsd_arm.go index c532b3a7af..557c634533 100644 --- a/src/syscall/ztypes_netbsd_arm.go +++ b/src/syscall/ztypes_netbsd_arm.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +//go:build arm && netbsd // +build arm,netbsd package syscall diff --git a/src/syscall/ztypes_netbsd_arm64.go b/src/syscall/ztypes_netbsd_arm64.go index 6d7f9edf34..19f3690341 100644 --- a/src/syscall/ztypes_netbsd_arm64.go +++ b/src/syscall/ztypes_netbsd_arm64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +//go:build arm64 && netbsd // +build arm64,netbsd package syscall diff --git a/src/syscall/ztypes_openbsd_386.go b/src/syscall/ztypes_openbsd_386.go index c2a03ebdd8..222c6c7e46 100644 --- a/src/syscall/ztypes_openbsd_386.go +++ b/src/syscall/ztypes_openbsd_386.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go +//go:build 386 && openbsd // +build 386,openbsd package syscall diff --git a/src/syscall/ztypes_openbsd_amd64.go b/src/syscall/ztypes_openbsd_amd64.go index 1a659ba2fe..644ee9b3df 100644 --- a/src/syscall/ztypes_openbsd_amd64.go +++ b/src/syscall/ztypes_openbsd_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go +//go:build amd64 && openbsd // +build amd64,openbsd package syscall diff --git a/src/syscall/ztypes_solaris_amd64.go b/src/syscall/ztypes_solaris_amd64.go index f846666fff..64e16b4943 100644 --- a/src/syscall/ztypes_solaris_amd64.go +++ b/src/syscall/ztypes_solaris_amd64.go @@ -1,6 +1,7 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_solaris.go +//go:build amd64 && solaris // +build amd64,solaris package syscall diff --git a/src/testing/run_example.go b/src/testing/run_example.go index 4dc83f7d32..d9e342d495 100644 --- a/src/testing/run_example.go +++ b/src/testing/run_example.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !js // +build !js // TODO(@musiol, @odeke-em): re-unify this entire file back into diff --git a/src/testing/run_example_js.go b/src/testing/run_example_js.go index 1d4164b61f..d914633ba9 100644 --- a/src/testing/run_example_js.go +++ b/src/testing/run_example_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js // +build js package testing diff --git a/src/time/embed.go b/src/time/embed.go index cb4fdac4ef..34490c859d 100644 --- a/src/time/embed.go +++ b/src/time/embed.go @@ -5,6 +5,7 @@ // This file is used with build tag timetzdata to embed tzdata into // the binary. +//go:build timetzdata // +build timetzdata package time diff --git a/src/time/genzabbrs.go b/src/time/genzabbrs.go index 9825e705d2..9fd2f2b762 100644 --- a/src/time/genzabbrs.go +++ b/src/time/genzabbrs.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // diff --git a/src/time/sys_plan9.go b/src/time/sys_plan9.go index b7fba0802c..4dc55e44aa 100644 --- a/src/time/sys_plan9.go +++ b/src/time/sys_plan9.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build plan9 // +build plan9 package time diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go index 97b1140bbc..60fc090dc9 100644 --- a/src/time/sys_unix.go +++ b/src/time/sys_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris package time diff --git a/src/time/tzdata/generate_zipdata.go b/src/time/tzdata/generate_zipdata.go index 21357fbf1c..64b5b1b22c 100644 --- a/src/time/tzdata/generate_zipdata.go +++ b/src/time/tzdata/generate_zipdata.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // This program generates zipdata.go from $GOROOT/lib/time/zoneinfo.zip. diff --git a/src/time/zoneinfo_ios.go b/src/time/zoneinfo_ios.go index 0f1e9334b5..044691e130 100644 --- a/src/time/zoneinfo_ios.go +++ b/src/time/zoneinfo_ios.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ios // +build ios package time diff --git a/src/time/zoneinfo_js.go b/src/time/zoneinfo_js.go index 2d76a571f2..8245614d2e 100644 --- a/src/time/zoneinfo_js.go +++ b/src/time/zoneinfo_js.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build js && wasm // +build js,wasm package time diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go index d2465eef65..4ea029dbde 100644 --- a/src/time/zoneinfo_unix.go +++ b/src/time/zoneinfo_unix.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || (darwin && !ios) || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || solaris // +build aix darwin,!ios dragonfly freebsd linux,!android netbsd openbsd solaris // Parse "zoneinfo" time zone file. diff --git a/src/time/zoneinfo_unix_test.go b/src/time/zoneinfo_unix_test.go index f290ae754f..b75b374c3d 100644 --- a/src/time/zoneinfo_unix_test.go +++ b/src/time/zoneinfo_unix_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build aix || (darwin && !ios) || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || solaris // +build aix darwin,!ios dragonfly freebsd linux,!android netbsd openbsd solaris package time_test -- GitLab From 40656f3a758728276e164ecb48822527a80e5f7b Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sat, 20 Feb 2021 17:53:43 +0100 Subject: [PATCH 0008/1298] doc/1.16: fix link to fs.FileInfo Updates #40700 Change-Id: Ifff622ccadaa31c0c0684c3c695aadcaa2305623 Reviewed-on: https://go-review.googlesource.com/c/go/+/294669 Trust: Alberto Donizetti Reviewed-by: Ian Lance Taylor --- doc/go1.16.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.16.html b/doc/go1.16.html index 0beb62d160..f2370e8363 100644 --- a/doc/go1.16.html +++ b/doc/go1.16.html @@ -548,7 +548,7 @@ func TestFoo(t *testing.T) { (note: returns a slice of os.DirEntry rather than a slice of - fs.FileInfo) + fs.FileInfo)

  • ReadFile => os.ReadFile
  • -- GitLab From 03d36d8198428a6970ba01f5de41c264acbff8fc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 20 Feb 2021 11:25:15 -0800 Subject: [PATCH 0009/1298] syscall: add explicit ios build tag This permits analysis of the syscall package by tools built with older versions of Go that do not recognize ios as a GOOS. Fixes #44459 Change-Id: I79cec2ffe0dbcbc2dc45a385e556dc9e62033125 Reviewed-on: https://go-review.googlesource.com/c/go/+/294634 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Brad Fitzpatrick TryBot-Result: Go Bot --- src/syscall/ptrace_ios.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/syscall/ptrace_ios.go b/src/syscall/ptrace_ios.go index 2f61a88a08..5209d1e0dd 100644 --- a/src/syscall/ptrace_ios.go +++ b/src/syscall/ptrace_ios.go @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ios +// +build ios + package syscall // Nosplit because it is called from forkAndExecInChild. -- GitLab From e78e04ce39b9df316edda08f43f253f5e9ac509e Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 19 Feb 2021 10:09:15 -0500 Subject: [PATCH 0010/1298] cmd/compile: fix panic in DWARF-gen handling obfuscated code DWARF generation uses variable source positions (file/line/col) as a way to uniquely identify locals and parameters, as part of the process of matching up post-optimization variables with the corresponding pre-optimization versions (since the DWARF needs to be in terms of the original source constructs). This strategy can run into problems when compiling obfuscated or machine-generated code, where you can in some circumstances wind up with two local variables that appear to have the same name, file, line, and column. This patch changes DWARF generation to skip over such duplicates as opposed to issuing a fatal error (if an obfuscation tool is in use, it is unlikely that a human being will be able to make much sense of DWARF info in any case). Fixes #44378. Change-Id: I198022d184701aa9ec3dce42c005d29b72d2e321 Reviewed-on: https://go-review.googlesource.com/c/go/+/294289 TryBot-Result: Go Bot Reviewed-by: David Chase Reviewed-by: Jeremy Faller Reviewed-by: Cherry Zhang Trust: Than McIntosh Run-TryBot: Than McIntosh --- src/cmd/compile/internal/dwarfgen/dwinl.go | 3 +- test/fixedbugs/issue44378.go | 40 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue44378.go diff --git a/src/cmd/compile/internal/dwarfgen/dwinl.go b/src/cmd/compile/internal/dwarfgen/dwinl.go index d5687cb1d7..8adb36fc88 100644 --- a/src/cmd/compile/internal/dwarfgen/dwinl.go +++ b/src/cmd/compile/internal/dwarfgen/dwinl.go @@ -247,7 +247,8 @@ func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int { DeclCol: pos.Col(), } if _, found := m[vp]; found { - base.Fatalf("child dcl collision on symbol %s within %v\n", n.Sym().Name, fnsym.Name) + // We can see collisions (variables with the same name/file/line/col) in obfuscated or machine-generated code -- see issue 44378 for an example. Skip duplicates in such cases, since it is unlikely that a human will be debugging such code. + continue } m[vp] = i } diff --git a/test/fixedbugs/issue44378.go b/test/fixedbugs/issue44378.go new file mode 100644 index 0000000000..58c88d573f --- /dev/null +++ b/test/fixedbugs/issue44378.go @@ -0,0 +1,40 @@ +// compile + +// Copyright 2021 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 test case caused a panic in the compiler's DWARF gen code. + +// Note to future maintainers of this code: +// +// ** Do NOT run gofmt when editing this file ** +// +// In order for the buggy behavior to be triggered in the compiler, +// we need to have a the function of interest all on one gigantic line. + +package a + +type O interface{} +type IO int +type OS int + +type A struct { + x int +} + +// original versions of the two function +func (p *A) UO(o O) { + p.r(o, o) +} +func (p *A) r(o1, o2 O) { + switch x := o1.(type) { + case *IO: + p.x = int(*x) + case *OS: + p.x = int(*x + 2) + } +} + +// see note above about the importance of all this code winding up on one line. +var myverylongname0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 int ; func (p *A) UO2(o O) { p.r2(o, o); }; func (p *A) r2(o1, o2 O) { switch x := o1.(type) { case *IO: p.x = int(*x); case *OS: p.x = int(*x + 2); } } -- GitLab From 0f66fb7b856b02497cf801ce72d80f375f53358b Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 19 Feb 2021 10:34:55 -0500 Subject: [PATCH 0011/1298] go/internal/gccgoimporter: fix up gccgo installation test Change the TestInstallationImporter testpoint to query type information for sort.Search instead of sort.Ints. The latter function changed recently (1.16 timeframe), parameter "a" is now "x". A better candidate for this sort of query is sort.Search, which has been stable for a while. Fixes #44425. Change-Id: I314476eac0b0802f86f5cbce32195cab2926db83 Reviewed-on: https://go-review.googlesource.com/c/go/+/294290 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/go/internal/gccgoimporter/gccgoinstallation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/internal/gccgoimporter/gccgoinstallation_test.go b/src/go/internal/gccgoimporter/gccgoinstallation_test.go index b332babc7b..df0188ace7 100644 --- a/src/go/internal/gccgoimporter/gccgoinstallation_test.go +++ b/src/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -184,7 +184,7 @@ func TestInstallationImporter(t *testing.T) { {pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"}, {pkgpath: "math", name: "Pi", want: "const Pi untyped float"}, {pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"}, - {pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"}, + {pkgpath: "sort", name: "Search", want: "func Search(n int, f func(int) bool) int"}, {pkgpath: "unsafe", name: "Pointer", want: "type Pointer"}, } { runImporterTest(t, imp, nil, &test) -- GitLab From b2bdadfe88c205baed2f3dde6aa4709940ce4a7b Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Mon, 2 Nov 2020 15:05:40 -0600 Subject: [PATCH 0012/1298] cmd/internal: cleanup ppc64 optab structure This is no-functionality change to begin the process of supporting more than 6 operands. This rewrites the table to use named arguments, and removes default initialized argument values. The following sed regexes rewrote the table: s/{\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)}/{as:\1,a1:\2,a2:\3,a3:\4,a4:\5,type_:\6,size:\7,param:\8} s/a[1-4]: C_NONE, //g s/, param: 0// Change-Id: I5f4de9da75f2fb3964d625d6b4e2f1ce1e29cc47 Reviewed-on: https://go-review.googlesource.com/c/go/+/294189 Trust: Lynn Boger Run-TryBot: Lynn Boger TryBot-Result: Go Bot Reviewed-by: Carlos Eduardo Seo --- src/cmd/internal/obj/ppc64/asm9.go | 912 +++++++++++++++-------------- 1 file changed, 459 insertions(+), 453 deletions(-) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 41e263b2c0..97b4cb2317 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -73,558 +73,564 @@ type Optab struct { param int16 } -// This optab contains a list of opcodes with the operand -// combinations that are implemented. Not all opcodes are in this -// table, but are added later in buildop by calling opset for those -// opcodes which allow the same operand combinations as an opcode -// already in the table. +// optab contains an array to be sliced of accepted operand combinations for an +// instruction. Unused arguments and fields are not explicitly enumerated, and +// should not be listed for clarity. Unused arguments and values should always +// assume the default value for the given type. // -// The type field in the Optabl identifies the case in asmout where -// the instruction word is assembled. +// optab does not list every valid ppc64 opcode, it enumerates representative +// operand combinations for a class of instruction. The variable oprange indexes +// all valid ppc64 opcodes. +// +// oprange is initialized to point a slice within optab which contains the valid +// operand combinations for a given instruction. This is initialized from buildop. +// +// Likewise, each slice of optab is dynamically sorted using the ocmp Sort interface +// to arrange entries to minimize text size of each opcode. var optab = []Optab{ - {obj.ATEXT, C_LEXT, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0}, - {obj.ATEXT, C_LEXT, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0}, - {obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0}, - {obj.ATEXT, C_ADDR, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0}, + {as: obj.ATEXT, a1: C_LEXT, a4: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_LEXT, a3: C_LCON, a4: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_ADDR, a4: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_ADDR, a3: C_LCON, a4: C_TEXTSIZE, type_: 0, size: 0}, /* move register */ - {AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0}, - {AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0}, - {AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0}, - {AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, - {AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0}, - {AADD, C_SCON, C_REG, C_NONE, C_REG, 4, 4, 0}, - {AADD, C_SCON, C_NONE, C_NONE, C_REG, 4, 4, 0}, - {AADD, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0}, - {AADD, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0}, - {AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0}, - {AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0}, - {AADD, C_ANDCON, C_REG, C_NONE, C_REG, 22, 8, 0}, - {AADD, C_ANDCON, C_NONE, C_NONE, C_REG, 22, 8, 0}, - {AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0}, - {AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0}, - {AADDIS, C_ADDCON, C_REG, C_NONE, C_REG, 20, 4, 0}, - {AADDIS, C_ADDCON, C_NONE, C_NONE, C_REG, 20, 4, 0}, - {AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, - {AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0}, - {AADDC, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0}, - {AADDC, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0}, - {AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0}, - {AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0}, - {AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, no literal */ - {AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, - {AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {AANDCC, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0}, - {AANDCC, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0}, - {AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0}, - {AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0}, - {AANDCC, C_ADDCON, C_NONE, C_NONE, C_REG, 23, 8, 0}, - {AANDCC, C_ADDCON, C_REG, C_NONE, C_REG, 23, 8, 0}, - {AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0}, - {AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0}, - {AANDISCC, C_ANDCON, C_NONE, C_NONE, C_REG, 59, 4, 0}, - {AANDISCC, C_ANDCON, C_REG, C_NONE, C_REG, 59, 4, 0}, - {AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, - {AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0}, - {AMULLW, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0}, - {AMULLW, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0}, - {AMULLW, C_ANDCON, C_REG, C_NONE, C_REG, 4, 4, 0}, - {AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0}, - {AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0}, - {AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0}, - {ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0}, - {ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0}, - {ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0}, - {ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0}, - {AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, literal not cc (or/xor) */ - {AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0}, - {AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0}, - {AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0}, - {AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0}, - {AOR, C_ADDCON, C_NONE, C_NONE, C_REG, 23, 8, 0}, - {AOR, C_ADDCON, C_REG, C_NONE, C_REG, 23, 8, 0}, - {AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0}, - {AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0}, - {AORIS, C_ANDCON, C_NONE, C_NONE, C_REG, 59, 4, 0}, - {AORIS, C_ANDCON, C_REG, C_NONE, C_REG, 59, 4, 0}, - {ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, /* op r1[,r2],r3 */ - {ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0}, - {ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0}, /* op r2[,r1],r3 */ - {ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0}, - {ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, - {ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, - {ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0}, - {ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0}, - {AEXTSWSLI, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0}, - {AEXTSWSLI, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0}, - {ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0}, - {ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0}, - {ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, - {ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0}, - {ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0}, - {ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0}, - {ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, - {ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0}, - {ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0}, - {ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0}, - {ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0}, - {ACLRLSLWI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0}, - {ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0}, - {ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0}, - {ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0}, - {ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0}, - {ARLDICL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0}, - {ARLDICL, C_SCON, C_REG, C_LCON, C_REG, 14, 4, 0}, - {ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0}, - {AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0}, - {AFADD, C_FREG, C_FREG, C_NONE, C_FREG, 2, 4, 0}, - {AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0}, - {AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0}, - {AFMADD, C_FREG, C_FREG, C_FREG, C_FREG, 34, 4, 0}, - {AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0}, - {AFMUL, C_FREG, C_FREG, C_NONE, C_FREG, 32, 4, 0}, + {as: AMOVD, a1: C_REG, a4: C_REG, type_: 1, size: 4}, + {as: AMOVB, a1: C_REG, a4: C_REG, type_: 12, size: 4}, + {as: AMOVBZ, a1: C_REG, a4: C_REG, type_: 13, size: 4}, + {as: AMOVW, a1: C_REG, a4: C_REG, type_: 12, size: 4}, + {as: AMOVWZ, a1: C_REG, a4: C_REG, type_: 13, size: 4}, + {as: AADD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AADD, a1: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AADD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_SCON, a4: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 20, size: 4}, + {as: AADD, a1: C_UCON, a4: C_REG, type_: 20, size: 4}, + {as: AADD, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 22, size: 8}, + {as: AADD, a1: C_ANDCON, a4: C_REG, type_: 22, size: 8}, + {as: AADD, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, + {as: AADD, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, + {as: AADDIS, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 20, size: 4}, + {as: AADDIS, a1: C_ADDCON, a4: C_REG, type_: 20, size: 4}, + {as: AADDC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AADDC, a1: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AADDC, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, + {as: AADDC, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, + {as: AADDC, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, + {as: AADDC, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, + {as: AAND, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, /* logical, no literal */ + {as: AAND, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_ANDCON, a4: C_REG, type_: 58, size: 4}, + {as: AANDCC, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 58, size: 4}, + {as: AANDCC, a1: C_UCON, a4: C_REG, type_: 59, size: 4}, + {as: AANDCC, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, + {as: AANDCC, a1: C_ADDCON, a4: C_REG, type_: 23, size: 8}, + {as: AANDCC, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 23, size: 8}, + {as: AANDCC, a1: C_LCON, a4: C_REG, type_: 23, size: 12}, + {as: AANDCC, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 23, size: 12}, + {as: AANDISCC, a1: C_ANDCON, a4: C_REG, type_: 59, size: 4}, + {as: AANDISCC, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, + {as: AMULLW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AMULLW, a1: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: AMULLW, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ANDCON, a4: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, + {as: AMULLW, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, + {as: ASUBC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 10, size: 4}, + {as: ASUBC, a1: C_REG, a4: C_REG, type_: 10, size: 4}, + {as: ASUBC, a1: C_REG, a3: C_ADDCON, a4: C_REG, type_: 27, size: 4}, + {as: ASUBC, a1: C_REG, a3: C_LCON, a4: C_REG, type_: 28, size: 12}, + {as: AOR, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, /* logical, literal not cc (or/xor) */ + {as: AOR, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: AOR, a1: C_ANDCON, a4: C_REG, type_: 58, size: 4}, + {as: AOR, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 58, size: 4}, + {as: AOR, a1: C_UCON, a4: C_REG, type_: 59, size: 4}, + {as: AOR, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, + {as: AOR, a1: C_ADDCON, a4: C_REG, type_: 23, size: 8}, + {as: AOR, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 23, size: 8}, + {as: AOR, a1: C_LCON, a4: C_REG, type_: 23, size: 12}, + {as: AOR, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 23, size: 12}, + {as: AORIS, a1: C_ANDCON, a4: C_REG, type_: 59, size: 4}, + {as: AORIS, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, + {as: ADIVW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, /* op r1[,r2],r3 */ + {as: ADIVW, a1: C_REG, a4: C_REG, type_: 2, size: 4}, + {as: ASUB, a1: C_REG, a2: C_REG, a4: C_REG, type_: 10, size: 4}, /* op r2[,r1],r3 */ + {as: ASUB, a1: C_REG, a4: C_REG, type_: 10, size: 4}, + {as: ASLW, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASLW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 25, size: 4}, + {as: ASLD, a1: C_SCON, a4: C_REG, type_: 25, size: 4}, + {as: AEXTSWSLI, a1: C_SCON, a4: C_REG, type_: 25, size: 4}, + {as: AEXTSWSLI, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 25, size: 4}, + {as: ASLW, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 57, size: 4}, + {as: ASLW, a1: C_SCON, a4: C_REG, type_: 57, size: 4}, + {as: ASRAW, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASRAW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASRAW, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 56, size: 4}, + {as: ASRAW, a1: C_SCON, a4: C_REG, type_: 56, size: 4}, + {as: ASRAD, a1: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASRAD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, + {as: ASRAD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 56, size: 4}, + {as: ASRAD, a1: C_SCON, a4: C_REG, type_: 56, size: 4}, + {as: ARLWMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 62, size: 4}, + {as: ARLWMI, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 63, size: 4}, + {as: ACLRLSLWI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 62, size: 4}, + {as: ARLDMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 30, size: 4}, + {as: ARLDC, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 29, size: 4}, + {as: ARLDCL, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 29, size: 4}, + {as: ARLDCL, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, + {as: ARLDICL, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, + {as: ARLDICL, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, + {as: ARLDCL, a1: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, + {as: AFADD, a1: C_FREG, a4: C_FREG, type_: 2, size: 4}, + {as: AFADD, a1: C_FREG, a2: C_FREG, a4: C_FREG, type_: 2, size: 4}, + {as: AFABS, a1: C_FREG, a4: C_FREG, type_: 33, size: 4}, + {as: AFABS, a4: C_FREG, type_: 33, size: 4}, + {as: AFMOVD, a1: C_FREG, a4: C_FREG, type_: 33, size: 4}, + {as: AFMADD, a1: C_FREG, a2: C_FREG, a3: C_FREG, a4: C_FREG, type_: 34, size: 4}, + {as: AFMUL, a1: C_FREG, a4: C_FREG, type_: 32, size: 4}, + {as: AFMUL, a1: C_FREG, a2: C_FREG, a4: C_FREG, type_: 32, size: 4}, /* store, short offset */ - {AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO}, - {AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB}, - {AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB}, - {AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB}, - {AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP}, - {AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP}, - {AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP}, - {AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, + {as: AMOVD, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBU, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVW, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVWZ, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVBZ, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVB, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVD, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVW, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVBZ, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVB, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVD, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBU, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, /* load, short offset */ - {AMOVD, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVW, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVWZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVBZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVBZU, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVB, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO}, - {AMOVBU, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO}, - {AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB}, - {AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB}, - {AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB}, - {AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB}, - {AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB}, - {AMOVD, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP}, - {AMOVW, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP}, - {AMOVWZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP}, - {AMOVBZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP}, - {AMOVB, C_SAUTO, C_NONE, C_NONE, C_REG, 9, 8, REGSP}, - {AMOVD, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVW, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVWZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVBZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVBZU, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO}, - {AMOVB, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO}, - {AMOVBU, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO}, + {as: AMOVD, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVW, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVWZ, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVBZ, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVB, a1: C_SEXT, a4: C_REG, type_: 9, size: 8, param: REGSB}, + {as: AMOVD, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVW, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVBZ, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVB, a1: C_SAUTO, a4: C_REG, type_: 9, size: 8, param: REGSP}, + {as: AMOVD, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_SOREG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVBU, a1: C_SOREG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, /* store, long offset */ - {AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, - {AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, - {AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, - {AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, + {as: AMOVD, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVW, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVBZ, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVB, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVD, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVW, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVBZ, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVB, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVD, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVW, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVB, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, + {as: AMOVW, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, + {as: AMOVWZ, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, + {as: AMOVBZ, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, + {as: AMOVB, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, /* load, long offset */ - {AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB}, - {AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB}, - {AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB}, - {AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB}, - {AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB}, - {AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP}, - {AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP}, - {AMOVWZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP}, - {AMOVBZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP}, - {AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 37, 12, REGSP}, - {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO}, - {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO}, - {AMOVWZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO}, - {AMOVBZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO}, - {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 37, 12, REGZERO}, - {AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0}, - {AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0}, - {AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0}, - {AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0}, - {AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0}, - - {AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 79, 4, 0}, - {AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 80, 8, 0}, - - {AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 81, 8, 0}, - {AMOVD, C_TOCADDR, C_NONE, C_NONE, C_REG, 95, 8, 0}, + {as: AMOVD, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVW, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVBZ, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVB, a1: C_LEXT, a4: C_REG, type_: 37, size: 12, param: REGSB}, + {as: AMOVD, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVW, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVBZ, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVB, a1: C_LAUTO, a4: C_REG, type_: 37, size: 12, param: REGSP}, + {as: AMOVD, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVW, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVWZ, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVBZ, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVB, a1: C_LOREG, a4: C_REG, type_: 37, size: 12, param: REGZERO}, + {as: AMOVD, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, + {as: AMOVW, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, + {as: AMOVWZ, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, + {as: AMOVBZ, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, + {as: AMOVB, a1: C_ADDR, a4: C_REG, type_: 76, size: 12}, + + {as: AMOVD, a1: C_TLS_LE, a4: C_REG, type_: 79, size: 4}, + {as: AMOVD, a1: C_TLS_IE, a4: C_REG, type_: 80, size: 8}, + + {as: AMOVD, a1: C_GOTADDR, a4: C_REG, type_: 81, size: 8}, + {as: AMOVD, a1: C_TOCADDR, a4: C_REG, type_: 95, size: 8}, /* load constant */ - {AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, - {AMOVD, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP}, - {AMOVD, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB}, - {AMOVD, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP}, - {AMOVD, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVD, C_ANDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVW, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */ - {AMOVW, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP}, - {AMOVW, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB}, - {AMOVW, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP}, - {AMOVW, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVW, C_ANDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVWZ, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */ - {AMOVWZ, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP}, - {AMOVWZ, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB}, - {AMOVWZ, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP}, - {AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVWZ, C_ANDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, + {as: AMOVD, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, + {as: AMOVD, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVD, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVD, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVD, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ + {as: AMOVW, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVW, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVW, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVW, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ + {as: AMOVWZ, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, /* load unsigned/long constants (TO DO: check) */ - {AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0}, - {AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0}, - {AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO}, - {AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0}, - {AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0}, - {AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0}, - {AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0}, - {AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0}, - {ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0}, - {ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0}, - {ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0}, - {ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0}, - {ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0}, - {ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, - {ABR, C_NONE, C_NONE, C_NONE, C_LBRAPIC, 11, 8, 0}, - {ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0}, - {ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0}, - {ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0}, - {ABR, C_NONE, C_NONE, C_SCON, C_LR, 18, 4, 0}, - {ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0}, - {ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0}, - {ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0}, - {ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0}, - {ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0}, - {ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0}, - {ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0}, - {ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0}, - {AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB}, - {AFMOVD, C_SAUTO, C_NONE, C_NONE, C_FREG, 8, 4, REGSP}, - {AFMOVD, C_SOREG, C_NONE, C_NONE, C_FREG, 8, 4, REGZERO}, - {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}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO}, - {AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0}, - {AFMOVSX, C_ZOREG, C_REG, C_NONE, C_FREG, 45, 4, 0}, - {AFMOVSX, C_ZOREG, C_NONE, C_NONE, C_FREG, 45, 4, 0}, - {AFMOVSX, C_FREG, C_REG, C_NONE, C_ZOREG, 44, 4, 0}, - {AFMOVSX, C_FREG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0}, - {AFMOVSZ, C_ZOREG, C_REG, C_NONE, C_FREG, 45, 4, 0}, - {AFMOVSZ, C_ZOREG, C_NONE, C_NONE, C_FREG, 45, 4, 0}, - {ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0}, - {AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0}, - {ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0}, - {ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0}, - {AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0}, - {AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0}, - {AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0}, - {AISEL, C_LCON, C_REG, C_REG, C_REG, 84, 4, 0}, - {AISEL, C_ZCON, C_REG, C_REG, C_REG, 84, 4, 0}, - {ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0}, - {ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0}, - {AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0}, - {AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0}, - {AREMU, C_REG, C_NONE, C_NONE, C_REG, 50, 16, 0}, - {AREMU, C_REG, C_REG, C_NONE, C_REG, 50, 16, 0}, - {AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0}, - {AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0}, - {AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0}, - {AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0}, - {AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0}, - {AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0}, - {AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0}, - {AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0}, /* mfmsr */ - {AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0}, /* mtmsrd */ - {AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0}, /* mtmsr */ + {as: AMOVD, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, + {as: AMOVW, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, + {as: AMOVWZ, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, + {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 45, size: 4}, + {as: AMOVHBR, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, + {as: AMOVHBR, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AMOVHBR, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: ASYSCALL, type_: 5, size: 4}, + {as: ASYSCALL, a1: C_REG, type_: 77, size: 12}, + {as: ASYSCALL, a1: C_SCON, type_: 77, size: 12}, + {as: ABEQ, a4: C_SBRA, type_: 16, size: 4}, + {as: ABEQ, a1: C_CREG, a4: C_SBRA, type_: 16, size: 4}, + {as: ABR, a4: C_LBRA, type_: 11, size: 4}, + {as: ABR, a4: C_LBRAPIC, type_: 11, size: 8}, + {as: ABC, a1: C_SCON, a2: C_REG, a4: C_SBRA, type_: 16, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a4: C_LBRA, type_: 17, size: 4}, + {as: ABR, a4: C_LR, type_: 18, size: 4}, + {as: ABR, a3: C_SCON, a4: C_LR, type_: 18, size: 4}, + {as: ABR, a4: C_CTR, type_: 18, size: 4}, + {as: ABR, a1: C_REG, a4: C_CTR, type_: 18, size: 4}, + {as: ABR, a4: C_ZOREG, type_: 15, size: 8}, + {as: ABC, a2: C_REG, a4: C_LR, type_: 18, size: 4}, + {as: ABC, a2: C_REG, a4: C_CTR, type_: 18, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a4: C_LR, type_: 18, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a4: C_CTR, type_: 18, size: 4}, + {as: ABC, a4: C_ZOREG, type_: 15, size: 8}, + {as: AFMOVD, a1: C_SEXT, a4: C_FREG, type_: 8, size: 4, param: REGSB}, + {as: AFMOVD, a1: C_SAUTO, a4: C_FREG, type_: 8, size: 4, param: REGSP}, + {as: AFMOVD, a1: C_SOREG, a4: C_FREG, type_: 8, size: 4, param: REGZERO}, + {as: AFMOVD, a1: C_LEXT, a4: C_FREG, type_: 36, size: 8, param: REGSB}, + {as: AFMOVD, a1: C_LAUTO, a4: C_FREG, type_: 36, size: 8, param: REGSP}, + {as: AFMOVD, a1: C_LOREG, a4: C_FREG, type_: 36, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_ZCON, a4: C_FREG, type_: 24, size: 4}, + {as: AFMOVD, a1: C_ADDCON, a4: C_FREG, type_: 24, size: 8}, + {as: AFMOVD, a1: C_ADDR, a4: C_FREG, type_: 75, size: 8}, + {as: AFMOVD, a1: C_FREG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AFMOVD, a1: C_FREG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AFMOVD, a1: C_FREG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AFMOVD, a1: C_FREG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AFMOVD, a1: C_FREG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AFMOVD, a1: C_FREG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_FREG, a4: C_ADDR, type_: 74, size: 8}, + {as: AFMOVSX, a1: C_ZOREG, a2: C_REG, a4: C_FREG, type_: 45, size: 4}, + {as: AFMOVSX, a1: C_ZOREG, a4: C_FREG, type_: 45, size: 4}, + {as: AFMOVSX, a1: C_FREG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AFMOVSX, a1: C_FREG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AFMOVSZ, a1: C_ZOREG, a2: C_REG, a4: C_FREG, type_: 45, size: 4}, + {as: AFMOVSZ, a1: C_ZOREG, a4: C_FREG, type_: 45, size: 4}, + {as: ASYNC, type_: 46, size: 4}, + {as: AWORD, a1: C_LCON, type_: 40, size: 4}, + {as: ADWORD, a1: C_LCON, type_: 31, size: 8}, + {as: ADWORD, a1: C_DCON, type_: 31, size: 8}, + {as: AADDME, a1: C_REG, a4: C_REG, type_: 47, size: 4}, + {as: AEXTSB, a1: C_REG, a4: C_REG, type_: 48, size: 4}, + {as: AEXTSB, a4: C_REG, type_: 48, size: 4}, + {as: AISEL, a1: C_LCON, a2: C_REG, a3: C_REG, a4: C_REG, type_: 84, size: 4}, + {as: AISEL, a1: C_ZCON, a2: C_REG, a3: C_REG, a4: C_REG, type_: 84, size: 4}, + {as: ANEG, a1: C_REG, a4: C_REG, type_: 47, size: 4}, + {as: ANEG, a4: C_REG, type_: 47, size: 4}, + {as: AREM, a1: C_REG, a4: C_REG, type_: 50, size: 12}, + {as: AREM, a1: C_REG, a2: C_REG, a4: C_REG, type_: 50, size: 12}, + {as: AREMU, a1: C_REG, a4: C_REG, type_: 50, size: 16}, + {as: AREMU, a1: C_REG, a2: C_REG, a4: C_REG, type_: 50, size: 16}, + {as: AREMD, a1: C_REG, a4: C_REG, type_: 51, size: 12}, + {as: AREMD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 51, size: 12}, + {as: AMTFSB0, a1: C_SCON, type_: 52, size: 4}, + {as: AMOVFL, a1: C_FPSCR, a4: C_FREG, type_: 53, size: 4}, + {as: AMOVFL, a1: C_FREG, a4: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_FREG, a3: C_LCON, a4: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_LCON, a4: C_FPSCR, type_: 65, size: 4}, + {as: AMOVD, a1: C_MSR, a4: C_REG, type_: 54, size: 4}, /* mfmsr */ + {as: AMOVD, a1: C_REG, a4: C_MSR, type_: 54, size: 4}, /* mtmsrd */ + {as: AMOVWZ, a1: C_REG, a4: C_MSR, type_: 54, size: 4}, /* mtmsr */ /* Other ISA 2.05+ instructions */ - {APOPCNTD, C_REG, C_NONE, C_NONE, C_REG, 93, 4, 0}, /* population count, x-form */ - {ACMPB, C_REG, C_REG, C_NONE, C_REG, 92, 4, 0}, /* compare byte, x-form */ - {ACMPEQB, C_REG, C_REG, C_NONE, C_CREG, 92, 4, 0}, /* compare equal byte, x-form, ISA 3.0 */ - {ACMPEQB, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0}, - {AFTDIV, C_FREG, C_FREG, C_NONE, C_SCON, 92, 4, 0}, /* floating test for sw divide, x-form */ - {AFTSQRT, C_FREG, C_NONE, C_NONE, C_SCON, 93, 4, 0}, /* floating test for sw square root, x-form */ - {ACOPY, C_REG, C_NONE, C_NONE, C_REG, 92, 4, 0}, /* copy/paste facility, x-form */ - {ADARN, C_SCON, C_NONE, C_NONE, C_REG, 92, 4, 0}, /* deliver random number, x-form */ - {ALDMX, C_SOREG, C_NONE, C_NONE, C_REG, 45, 4, 0}, /* load doubleword monitored, x-form */ - {AMADDHD, C_REG, C_REG, C_REG, C_REG, 83, 4, 0}, /* multiply-add high/low doubleword, va-form */ - {AADDEX, C_REG, C_REG, C_SCON, C_REG, 94, 4, 0}, /* add extended using alternate carry, z23-form */ - {ACRAND, C_CREG, C_NONE, C_NONE, C_CREG, 2, 4, 0}, /* logical ops for condition registers xl-form */ + {as: APOPCNTD, a1: C_REG, a4: C_REG, type_: 93, size: 4}, /* population count, x-form */ + {as: ACMPB, a1: C_REG, a2: C_REG, a4: C_REG, type_: 92, size: 4}, /* compare byte, x-form */ + {as: ACMPEQB, a1: C_REG, a2: C_REG, a4: C_CREG, type_: 92, size: 4}, /* compare equal byte, x-form, ISA 3.0 */ + {as: ACMPEQB, a1: C_REG, a4: C_REG, type_: 70, size: 4}, + {as: AFTDIV, a1: C_FREG, a2: C_FREG, a4: C_SCON, type_: 92, size: 4}, /* floating test for sw divide, x-form */ + {as: AFTSQRT, a1: C_FREG, a4: C_SCON, type_: 93, size: 4}, /* floating test for sw square root, x-form */ + {as: ACOPY, a1: C_REG, a4: C_REG, type_: 92, size: 4}, /* copy/paste facility, x-form */ + {as: ADARN, a1: C_SCON, a4: C_REG, type_: 92, size: 4}, /* deliver random number, x-form */ + {as: ALDMX, a1: C_SOREG, a4: C_REG, type_: 45, size: 4}, /* load doubleword monitored, x-form */ + {as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a4: C_REG, type_: 83, size: 4}, /* multiply-add high/low doubleword, va-form */ + {as: AADDEX, a1: C_REG, a2: C_REG, a3: C_SCON, a4: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */ + {as: ACRAND, a1: C_CREG, a4: C_CREG, type_: 2, size: 4}, /* logical ops for condition registers xl-form */ /* Vector instructions */ /* Vector load */ - {ALV, C_SOREG, C_NONE, C_NONE, C_VREG, 45, 4, 0}, /* vector load, x-form */ + {as: ALV, a1: C_SOREG, a4: C_VREG, type_: 45, size: 4}, /* vector load, x-form */ /* Vector store */ - {ASTV, C_VREG, C_NONE, C_NONE, C_SOREG, 44, 4, 0}, /* vector store, x-form */ + {as: ASTV, a1: C_VREG, a4: C_SOREG, type_: 44, size: 4}, /* vector store, x-form */ /* Vector logical */ - {AVAND, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector and, vx-form */ - {AVOR, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector or, vx-form */ + {as: AVAND, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector and, vx-form */ + {as: AVOR, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector or, vx-form */ /* Vector add */ - {AVADDUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add unsigned modulo, vx-form */ - {AVADDCU, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add & write carry unsigned, vx-form */ - {AVADDUS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add unsigned saturate, vx-form */ - {AVADDSS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add signed saturate, vx-form */ - {AVADDE, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector add extended, va-form */ + {as: AVADDUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add unsigned modulo, vx-form */ + {as: AVADDCU, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add & write carry unsigned, vx-form */ + {as: AVADDUS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add unsigned saturate, vx-form */ + {as: AVADDSS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add signed saturate, vx-form */ + {as: AVADDE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector add extended, va-form */ /* Vector subtract */ - {AVSUBUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract unsigned modulo, vx-form */ - {AVSUBCU, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract & write carry unsigned, vx-form */ - {AVSUBUS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract unsigned saturate, vx-form */ - {AVSUBSS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract signed saturate, vx-form */ - {AVSUBE, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector subtract extended, va-form */ + {as: AVSUBUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned modulo, vx-form */ + {as: AVSUBCU, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract & write carry unsigned, vx-form */ + {as: AVSUBUS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned saturate, vx-form */ + {as: AVSUBSS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract signed saturate, vx-form */ + {as: AVSUBE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector subtract extended, va-form */ /* Vector multiply */ - {AVMULESB, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 9}, /* vector multiply, vx-form */ - {AVPMSUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector polynomial multiply & sum, vx-form */ - {AVMSUMUDM, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector multiply-sum, va-form */ + {as: AVMULESB, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4, param: 9}, /* vector multiply, vx-form */ + {as: AVPMSUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector polynomial multiply & sum, vx-form */ + {as: AVMSUMUDM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector multiply-sum, va-form */ /* Vector rotate */ - {AVR, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector rotate, vx-form */ + {as: AVR, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector rotate, vx-form */ /* Vector shift */ - {AVS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector shift, vx-form */ - {AVSA, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector shift algebraic, vx-form */ - {AVSOI, C_ANDCON, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector shift by octet immediate, va-form */ + {as: AVS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector shift, vx-form */ + {as: AVSA, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector shift algebraic, vx-form */ + {as: AVSOI, a1: C_ANDCON, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector shift by octet immediate, va-form */ /* Vector count */ - {AVCLZ, C_VREG, C_NONE, C_NONE, C_VREG, 85, 4, 0}, /* vector count leading zeros, vx-form */ - {AVPOPCNT, C_VREG, C_NONE, C_NONE, C_VREG, 85, 4, 0}, /* vector population count, vx-form */ + {as: AVCLZ, a1: C_VREG, a4: C_VREG, type_: 85, size: 4}, /* vector count leading zeros, vx-form */ + {as: AVPOPCNT, a1: C_VREG, a4: C_VREG, type_: 85, size: 4}, /* vector population count, vx-form */ /* Vector compare */ - {AVCMPEQ, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector compare equal, vc-form */ - {AVCMPGT, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector compare greater than, vc-form */ - {AVCMPNEZB, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector compare not equal, vx-form */ + {as: AVCMPEQ, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare equal, vc-form */ + {as: AVCMPGT, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare greater than, vc-form */ + {as: AVCMPNEZB, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare not equal, vx-form */ /* Vector merge */ - {AVMRGOW, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector merge odd word, vx-form */ + {as: AVMRGOW, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector merge odd word, vx-form */ /* Vector permute */ - {AVPERM, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector permute, va-form */ + {as: AVPERM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector permute, va-form */ /* Vector bit permute */ - {AVBPERMQ, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector bit permute, vx-form */ + {as: AVBPERMQ, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector bit permute, vx-form */ /* Vector select */ - {AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector select, va-form */ + {as: AVSEL, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector select, va-form */ /* Vector splat */ - {AVSPLTB, C_SCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector splat, vx-form */ - {AVSPLTB, C_ADDCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, - {AVSPLTISB, C_SCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector splat immediate, vx-form */ - {AVSPLTISB, C_ADDCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, + {as: AVSPLTB, a1: C_SCON, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector splat, vx-form */ + {as: AVSPLTB, a1: C_ADDCON, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, + {as: AVSPLTISB, a1: C_SCON, a4: C_VREG, type_: 82, size: 4}, /* vector splat immediate, vx-form */ + {as: AVSPLTISB, a1: C_ADDCON, a4: C_VREG, type_: 82, size: 4}, /* Vector AES */ - {AVCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES cipher, vx-form */ - {AVNCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES inverse cipher, vx-form */ - {AVSBOX, C_VREG, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector AES subbytes, vx-form */ + {as: AVCIPH, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES cipher, vx-form */ + {as: AVNCIPH, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES inverse cipher, vx-form */ + {as: AVSBOX, a1: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES subbytes, vx-form */ /* Vector SHA */ - {AVSHASIGMA, C_ANDCON, C_VREG, C_ANDCON, C_VREG, 82, 4, 0}, /* vector SHA sigma, vx-form */ + {as: AVSHASIGMA, a1: C_ANDCON, a2: C_VREG, a3: C_ANDCON, a4: C_VREG, type_: 82, size: 4}, /* vector SHA sigma, vx-form */ /* VSX vector load */ - {ALXVD2X, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx vector load, xx1-form */ - {ALXV, C_SOREG, C_NONE, C_NONE, C_VSREG, 96, 4, 0}, /* vsx vector load, dq-form */ - {ALXVL, C_REG, C_REG, C_NONE, C_VSREG, 98, 4, 0}, /* vsx vector load length */ + {as: ALXVD2X, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx vector load, xx1-form */ + {as: ALXV, a1: C_SOREG, a4: C_VSREG, type_: 96, size: 4}, /* vsx vector load, dq-form */ + {as: ALXVL, a1: C_REG, a2: C_REG, a4: C_VSREG, type_: 98, size: 4}, /* vsx vector load length */ /* VSX vector store */ - {ASTXVD2X, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx vector store, xx1-form */ - {ASTXV, C_VSREG, C_NONE, C_NONE, C_SOREG, 97, 4, 0}, /* vsx vector store, dq-form */ - {ASTXVL, C_VSREG, C_REG, C_NONE, C_REG, 99, 4, 0}, /* vsx vector store with length x-form */ + {as: ASTXVD2X, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx vector store, xx1-form */ + {as: ASTXV, a1: C_VSREG, a4: C_SOREG, type_: 97, size: 4}, /* vsx vector store, dq-form */ + {as: ASTXVL, a1: C_VSREG, a2: C_REG, a4: C_REG, type_: 99, size: 4}, /* vsx vector store with length x-form */ /* VSX scalar load */ - {ALXSDX, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar load, xx1-form */ + {as: ALXSDX, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx scalar load, xx1-form */ /* VSX scalar store */ - {ASTXSDX, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar store, xx1-form */ + {as: ASTXSDX, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx scalar store, xx1-form */ /* VSX scalar as integer load */ - {ALXSIWAX, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar as integer load, xx1-form */ + {as: ALXSIWAX, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx scalar as integer load, xx1-form */ /* VSX scalar store as integer */ - {ASTXSIWX, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar as integer store, xx1-form */ + {as: ASTXSIWX, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx scalar as integer store, xx1-form */ /* VSX move from VSR */ - {AMFVSRD, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */ - {AMFVSRD, C_FREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, - {AMFVSRD, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, + {as: AMFVSRD, a1: C_VSREG, a4: C_REG, type_: 88, size: 4}, /* vsx move from vsr, xx1-form */ + {as: AMFVSRD, a1: C_FREG, a4: C_REG, type_: 88, size: 4}, + {as: AMFVSRD, a1: C_VREG, a4: C_REG, type_: 88, size: 4}, /* VSX move to VSR */ - {AMTVSRD, C_REG, C_NONE, C_NONE, C_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */ - {AMTVSRD, C_REG, C_REG, C_NONE, C_VSREG, 88, 4, 0}, - {AMTVSRD, C_REG, C_NONE, C_NONE, C_FREG, 88, 4, 0}, - {AMTVSRD, C_REG, C_NONE, C_NONE, C_VREG, 88, 4, 0}, + {as: AMTVSRD, a1: C_REG, a4: C_VSREG, type_: 88, size: 4}, /* vsx move to vsr, xx1-form */ + {as: AMTVSRD, a1: C_REG, a2: C_REG, a4: C_VSREG, type_: 88, size: 4}, + {as: AMTVSRD, a1: C_REG, a4: C_FREG, type_: 88, size: 4}, + {as: AMTVSRD, a1: C_REG, a4: C_VREG, type_: 88, size: 4}, /* VSX logical */ - {AXXLAND, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx and, xx3-form */ - {AXXLOR, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx or, xx3-form */ + {as: AXXLAND, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx and, xx3-form */ + {as: AXXLOR, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx or, xx3-form */ /* VSX select */ - {AXXSEL, C_VSREG, C_VSREG, C_VSREG, C_VSREG, 91, 4, 0}, /* vsx select, xx4-form */ + {as: AXXSEL, a1: C_VSREG, a2: C_VSREG, a3: C_VSREG, a4: C_VSREG, type_: 91, size: 4}, /* vsx select, xx4-form */ /* VSX merge */ - {AXXMRGHW, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx merge, xx3-form */ + {as: AXXMRGHW, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx merge, xx3-form */ /* VSX splat */ - {AXXSPLTW, C_VSREG, C_NONE, C_SCON, C_VSREG, 89, 4, 0}, /* vsx splat, xx2-form */ - {AXXSPLTIB, C_SCON, C_NONE, C_NONE, C_VSREG, 100, 4, 0}, /* vsx splat, xx2-form */ + {as: AXXSPLTW, a1: C_VSREG, a3: C_SCON, a4: C_VSREG, type_: 89, size: 4}, /* vsx splat, xx2-form */ + {as: AXXSPLTIB, a1: C_SCON, a4: C_VSREG, type_: 100, size: 4}, /* vsx splat, xx2-form */ /* VSX permute */ - {AXXPERM, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx permute, xx3-form */ + {as: AXXPERM, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx permute, xx3-form */ /* VSX shift */ - {AXXSLDWI, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx shift immediate, xx3-form */ + {as: AXXSLDWI, a1: C_VSREG, a2: C_VSREG, a3: C_SCON, a4: C_VSREG, type_: 90, size: 4}, /* vsx shift immediate, xx3-form */ /* VSX reverse bytes */ - {AXXBRQ, C_VSREG, C_NONE, C_NONE, C_VSREG, 101, 4, 0}, /* vsx reverse bytes */ + {as: AXXBRQ, a1: C_VSREG, a4: C_VSREG, type_: 101, size: 4}, /* vsx reverse bytes */ /* VSX scalar FP-FP conversion */ - {AXSCVDPSP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-fp conversion, xx2-form */ + {as: AXSCVDPSP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-fp conversion, xx2-form */ /* VSX vector FP-FP conversion */ - {AXVCVDPSP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-fp conversion, xx2-form */ + {as: AXVCVDPSP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-fp conversion, xx2-form */ /* VSX scalar FP-integer conversion */ - {AXSCVDPSXDS, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-integer conversion, xx2-form */ + {as: AXSCVDPSXDS, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-integer conversion, xx2-form */ /* VSX scalar integer-FP conversion */ - {AXSCVSXDDP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar integer-fp conversion, xx2-form */ + {as: AXSCVSXDDP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar integer-fp conversion, xx2-form */ /* VSX vector FP-integer conversion */ - {AXVCVDPSXDS, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-integer conversion, xx2-form */ + {as: AXVCVDPSXDS, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-integer conversion, xx2-form */ /* VSX vector integer-FP conversion */ - {AXVCVSXDDP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector integer-fp conversion, xx2-form */ + {as: AXVCVSXDDP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */ /* 64-bit special registers */ - {AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0}, - {AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0}, - {AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0}, - {AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0}, - {AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0}, + {as: AMOVD, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a4: C_LR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a4: C_XER, type_: 66, size: 4}, + {as: AMOVD, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_LR, a4: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_CTR, a4: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_XER, a4: C_REG, type_: 66, size: 4}, /* 32-bit special registers (gloss over sign-extension or not?) */ - {AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0}, - {AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0}, - {AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0}, - {AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0}, - {AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0}, - {AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0}, - {AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0}, - {AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0}, - {AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0}, - {AMOVFL, C_REG, C_NONE, C_NONE, C_LCON, 69, 4, 0}, - {AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0}, - {AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0}, - {AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0}, - {ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0}, - {ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0}, - {ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0}, - {ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0}, - {ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0}, - {ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0}, - {ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0}, - {ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0}, - {AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0}, - {AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0}, - {ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0}, - {ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0}, - {ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0}, - {ADCBF, C_SOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0}, - {ADCBF, C_ZOREG, C_REG, C_NONE, C_SCON, 43, 4, 0}, - {ADCBF, C_SOREG, C_NONE, C_NONE, C_SCON, 43, 4, 0}, - {AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0}, - {AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0}, - {AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0}, - {AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0}, - {ALDAR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0}, - {ALDAR, C_ZOREG, C_NONE, C_ANDCON, C_REG, 45, 4, 0}, - {AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0}, - {ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0}, - {ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0}, - {ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0}, - {ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0}, - {ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0}, - {ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0}, - {ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0}, - {ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0}, - {obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0}, - {obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0}, - {obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0}, - {obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0}, - {obj.ANOP, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0}, // NOP operand variations added for #40689 - {obj.ANOP, C_REG, C_NONE, C_NONE, C_NONE, 0, 0, 0}, // to preserve previous behavior - {obj.ANOP, C_FREG, C_NONE, C_NONE, C_NONE, 0, 0, 0}, - {obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL - {obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL - {obj.APCALIGN, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0}, // align code - - {obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0}, + {as: AMOVW, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a4: C_XER, type_: 66, size: 4}, + {as: AMOVW, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, + {as: AMOVW, a1: C_XER, a4: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a4: C_XER, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_XER, a4: C_REG, type_: 66, size: 4}, + {as: AMOVFL, a1: C_FPSCR, a4: C_CREG, type_: 73, size: 4}, + {as: AMOVFL, a1: C_CREG, a4: C_CREG, type_: 67, size: 4}, + {as: AMOVW, a1: C_CREG, a4: C_REG, type_: 68, size: 4}, + {as: AMOVWZ, a1: C_CREG, a4: C_REG, type_: 68, size: 4}, + {as: AMOVFL, a1: C_REG, a4: C_LCON, type_: 69, size: 4}, + {as: AMOVFL, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, + {as: AMOVW, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, + {as: AMOVWZ, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, + {as: ACMP, a1: C_REG, a4: C_REG, type_: 70, size: 4}, + {as: ACMP, a1: C_REG, a2: C_REG, a4: C_REG, type_: 70, size: 4}, + {as: ACMP, a1: C_REG, a4: C_ADDCON, type_: 71, size: 4}, + {as: ACMP, a1: C_REG, a2: C_REG, a4: C_ADDCON, type_: 71, size: 4}, + {as: ACMPU, a1: C_REG, a4: C_REG, type_: 70, size: 4}, + {as: ACMPU, a1: C_REG, a2: C_REG, a4: C_REG, type_: 70, size: 4}, + {as: ACMPU, a1: C_REG, a4: C_ANDCON, type_: 71, size: 4}, + {as: ACMPU, a1: C_REG, a2: C_REG, a4: C_ANDCON, type_: 71, size: 4}, + {as: AFCMPO, a1: C_FREG, a4: C_FREG, type_: 70, size: 4}, + {as: AFCMPO, a1: C_FREG, a2: C_REG, a4: C_FREG, type_: 70, size: 4}, + {as: ATW, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 60, size: 4}, + {as: ATW, a1: C_LCON, a2: C_REG, a4: C_ADDCON, type_: 61, size: 4}, + {as: ADCBF, a1: C_ZOREG, type_: 43, size: 4}, + {as: ADCBF, a1: C_SOREG, type_: 43, size: 4}, + {as: ADCBF, a1: C_ZOREG, a2: C_REG, a4: C_SCON, type_: 43, size: 4}, + {as: ADCBF, a1: C_SOREG, a4: C_SCON, type_: 43, size: 4}, + {as: AECOWX, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AECIWX, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 45, size: 4}, + {as: AECOWX, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AECIWX, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, + {as: ALDAR, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, + {as: ALDAR, a1: C_ZOREG, a3: C_ANDCON, a4: C_REG, type_: 45, size: 4}, + {as: AEIEIO, type_: 46, size: 4}, + {as: ATLBIE, a1: C_REG, type_: 49, size: 4}, + {as: ATLBIE, a1: C_SCON, a4: C_REG, type_: 49, size: 4}, + {as: ASLBMFEE, a1: C_REG, a4: C_REG, type_: 55, size: 4}, + {as: ASLBMTE, a1: C_REG, a4: C_REG, type_: 55, size: 4}, + {as: ASTSW, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: ASTSW, a1: C_REG, a3: C_LCON, a4: C_ZOREG, type_: 41, size: 4}, + {as: ALSW, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, + {as: ALSW, a1: C_ZOREG, a3: C_LCON, a4: C_REG, type_: 42, size: 4}, + {as: obj.AUNDEF, type_: 78, size: 4}, + {as: obj.APCDATA, a1: C_LCON, a4: C_LCON, type_: 0, size: 0}, + {as: obj.AFUNCDATA, a1: C_SCON, a4: C_ADDR, type_: 0, size: 0}, + {as: obj.ANOP, type_: 0, size: 0}, + {as: obj.ANOP, a1: C_LCON, type_: 0, size: 0}, // NOP operand variations added for #40689 + {as: obj.ANOP, a1: C_REG, type_: 0, size: 0}, // to preserve previous behavior + {as: obj.ANOP, a1: C_FREG, type_: 0, size: 0}, + {as: obj.ADUFFZERO, a4: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL + {as: obj.ADUFFCOPY, a4: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL + {as: obj.APCALIGN, a1: C_LCON, type_: 0, size: 0}, // align code + + {as: obj.AXXX, type_: 0, size: 4}, } var oprange [ALAST & obj.AMask][]Optab -- GitLab From 87e984ab2988afccdb75a4c235b318ec6be46e6a Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 22 Feb 2021 11:11:51 -0800 Subject: [PATCH 0013/1298] test: add test for issue 38698 It was fixed by CL 294289, for #44378. This is a different style of test that uses line directives instead of extremely long lines. Fixes #38698. Change-Id: I50a1585030978b35fffa9981d6ed96b99216dc3e Reviewed-on: https://go-review.googlesource.com/c/go/+/295129 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- test/fixedbugs/issue38698.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/fixedbugs/issue38698.go diff --git a/test/fixedbugs/issue38698.go b/test/fixedbugs/issue38698.go new file mode 100644 index 0000000000..819e223791 --- /dev/null +++ b/test/fixedbugs/issue38698.go @@ -0,0 +1,23 @@ +// compile + +// Copyright 2021 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 test case caused a panic in the compiler's DWARF gen code. + +package p + +func ff( /*line :10*/ x string) bool { + { + var _ /*line :10*/, x int + _ = x + } + return x == "" +} + + +func h(a string) bool { + return ff(a) +} + -- GitLab From 04903476fe6a1bba4ed751f5e234bccb5a651a9b Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 22 Feb 2021 11:55:14 -0800 Subject: [PATCH 0014/1298] cmd/compile: reject some rare looping CFGs in shortcircuit One CFGs that shortcircuit looks for is: p q \ / b / \ t u The test case creates a CFG like that in which p == t. That caused the compiler to generate a (short-lived) invalid phi value. Fix this with a relatively big hammer: Disallow single-length loops entirely. This is probably overkill, but it such loops are very rare. This doesn't change the generated code for anything in std. It generates worse code for the test case: It no longer compiles the entire function away. Fixes #44465 Change-Id: Ib8cdcd6cc9d7f48b4dab253652038ace24eae152 Reviewed-on: https://go-review.googlesource.com/c/go/+/295130 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/shortcircuit.go | 7 +++++++ test/fixedbugs/issue44465.go | 21 ++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/fixedbugs/issue44465.go diff --git a/src/cmd/compile/internal/ssa/shortcircuit.go b/src/cmd/compile/internal/ssa/shortcircuit.go index 7b4ee2e81c..c72c86a67e 100644 --- a/src/cmd/compile/internal/ssa/shortcircuit.go +++ b/src/cmd/compile/internal/ssa/shortcircuit.go @@ -266,6 +266,13 @@ func shortcircuitPhiPlan(b *Block, ctl *Value, cidx int, ti int64) func(*Value, // u is the "untaken" branch: the successor we never go to when coming in from p. u := b.Succs[1^ti].b + // In the following CFG matching, ensure that b's preds are entirely distinct from b's succs. + // This is probably a stronger condition than required, but this happens extremely rarely, + // and it makes it easier to avoid getting deceived by pretty ASCII charts. See #44465. + if p0, p1 := b.Preds[0].b, b.Preds[1].b; p0 == t || p1 == t || p0 == u || p1 == u { + return nil + } + // Look for some common CFG structures // in which the outbound paths from b merge, // with no other preds joining them. diff --git a/test/fixedbugs/issue44465.go b/test/fixedbugs/issue44465.go new file mode 100644 index 0000000000..8cb62adaac --- /dev/null +++ b/test/fixedbugs/issue44465.go @@ -0,0 +1,21 @@ +// compile -d=ssa/check/seed + +// Copyright 2021 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 code caused an internal consistency error due to a bad shortcircuit optimization. + +package p + +func f() { + var b bool + if b { + b = true + } +l: + for !b { + b = true + goto l + } +} -- GitLab From 1391d4142cab5e5b83ca3362be67af80ba2f95e8 Mon Sep 17 00:00:00 2001 From: zhengjianxun Date: Mon, 22 Feb 2021 13:30:03 +0000 Subject: [PATCH 0015/1298] fix typo in issue16760.go fix typo in issue16760.go, unconditinally -> unconditionally Change-Id: I3a04fbcb23395c562821b35bc2d81cfaec0bc1ed GitHub-Last-Rev: 5ce52a3deb52826bc28022776c3fe3ffa7376084 GitHub-Pull-Request: golang/go#44495 Reviewed-on: https://go-review.googlesource.com/c/go/+/294969 Trust: Alberto Donizetti Reviewed-by: zhengjianxun Reviewed-by: Robert Griesemer --- test/fixedbugs/issue16760.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixedbugs/issue16760.go b/test/fixedbugs/issue16760.go index d0e08b5ead..a7eede4d10 100644 --- a/test/fixedbugs/issue16760.go +++ b/test/fixedbugs/issue16760.go @@ -6,7 +6,7 @@ // Make sure we don't start marshaling (writing to the stack) // arguments until those arguments are evaluated and known -// not to unconditinally panic. If they unconditionally panic, +// not to unconditionally panic. If they unconditionally panic, // we write some args but never do the call. That messes up // the logic which decides how big the argout section needs to be. -- GitLab From 094048b93845c08e0f2db8639764f9564e64835b Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 18 Feb 2021 17:51:24 +0000 Subject: [PATCH 0016/1298] cmd/compile/internal: loop opt Change-Id: I5fe767237b8046934e9b0f33bd3dafabdb727dd6 GitHub-Last-Rev: 94fea3d57279e8b2d62f7f6be4301698dc8841e3 GitHub-Pull-Request: golang/go#44384 Reviewed-on: https://go-review.googlesource.com/c/go/+/293809 Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Matthew Dempsky Run-TryBot: Robert Griesemer TryBot-Result: Go Bot --- src/cmd/compile/internal/types/size.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index d1203e4a21..799cf3a1f6 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -624,9 +624,11 @@ func PtrDataSize(t *Type) int64 { case TSTRUCT: // Find the last field that has pointers. var lastPtrField *Field - for _, t1 := range t.Fields().Slice() { - if t1.Type.HasPointers() { - lastPtrField = t1 + fs := t.Fields().Slice() + for i := len(fs) - 1; i >= 0; i-- { + if fs[i].Type.HasPointers() { + lastPtrField = fs[i] + break } } return lastPtrField.Offset + PtrDataSize(lastPtrField.Type) -- GitLab From 1678829d9555761c0fa6571fd3bcaec016add3d2 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 22 Feb 2021 17:43:08 -0500 Subject: [PATCH 0017/1298] cmd/compile: correctly use X15 to zero frame In CL 288093 we reserve X15 as the zero register and use that to zero values. It only covered zeroing generated in SSA but missed zeroing the frame generated late in the compilation. The latter still uses X0, but now DUFFZERO expects X15, so it doesn't actually zero the frame. Change it to use X15. Should fix #44333. Change-Id: I239d2b78a5f6468bc86b70aecdd294045311759f Reviewed-on: https://go-review.googlesource.com/c/go/+/295210 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/amd64/ggen.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go index aefdb14a69..14c3bd1129 100644 --- a/src/cmd/compile/internal/amd64/ggen.go +++ b/src/cmd/compile/internal/amd64/ggen.go @@ -56,8 +56,8 @@ func dzDI(b int64) int64 { func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj.Prog { const ( - ax = 1 << iota - x0 + ax = 1 << iota // if AX is already zeroed. + x15 // if X15 is already zeroed. Note: in new ABI, X15 is always zero. ) if cnt == 0 { @@ -85,29 +85,29 @@ func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, state *uint32) *obj. } p = pp.Append(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, off) } else if !isPlan9 && cnt <= int64(8*types.RegSize) { - if *state&x0 == 0 { - p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0) - *state |= x0 + if objabi.Regabi_enabled == 0 && *state&x15 == 0 { + p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_REG, x86.REG_X15, 0) + *state |= x15 } for i := int64(0); i < cnt/16; i++ { - p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, off+i*16) + p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+i*16) } if cnt%16 != 0 { - p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, off+cnt-int64(16)) + p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_SP, off+cnt-int64(16)) } } else if !isPlan9 && (cnt <= int64(128*types.RegSize)) { - if *state&x0 == 0 { - p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0) - *state |= x0 + if objabi.Regabi_enabled == 0 && *state&x15 == 0 { + p = pp.Append(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_REG, x86.REG_X15, 0) + *state |= x15 } p = pp.Append(p, leaptr, obj.TYPE_MEM, x86.REG_SP, off+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0) p = pp.Append(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(cnt)) p.To.Sym = ir.Syms.Duffzero if cnt%16 != 0 { - p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8)) + p = pp.Append(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X15, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8)) } } else { if *state&ax == 0 { -- GitLab From 1126bbb82ab2f81dcb33df696a1bb601a98d3174 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 22 Feb 2021 15:39:00 -0500 Subject: [PATCH 0018/1298] go/parser: return ast.BadExpr for missing index operands The parser was returning the indexed operand when a slice or index or instance expression was missing any index arguments (as in the expression `a[]`). This can result in returning an *ast.Ident for the LHS of the (invalid) assignment `a[] = ...` -- in this case parsing the LHS as just `a`. Unfortunately, as the indexed operand `a` has already been resolved, this results in a panic for duplicate resolution. Fix this by instead returning an ast.BadExpr. This can suppress some subsequent errors from the typechecker, but those errors may or may not be correct anyway. Other interpretations, such as an *ast.IndexExpr with bad or missing X, run into potential misinterpretations downstream (both caused errors in go/types and/or gopls). Fixes #44504 Change-Id: I5ca8bed4a1861bcc7db8898770b08937110981d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/295151 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/parser/parser.go | 3 ++- src/go/parser/testdata/issue44504.src | 13 +++++++++++++ src/go/types/fixedbugs/issue39634.go2 | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/go/parser/testdata/issue44504.src diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 41c3f2943e..5c4cea8638 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1485,8 +1485,9 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr { // empty index, slice or index expressions are not permitted; // accept them for parsing tolerance, but complain p.errorExpected(p.pos, "operand") + rbrack := p.pos p.next() - return x + return &ast.BadExpr{From: x.Pos(), To: rbrack} } p.exprLev++ diff --git a/src/go/parser/testdata/issue44504.src b/src/go/parser/testdata/issue44504.src new file mode 100644 index 0000000000..7791f4a809 --- /dev/null +++ b/src/go/parser/testdata/issue44504.src @@ -0,0 +1,13 @@ +// Copyright 2021 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. + +// Test case for issue 44504: panic due to duplicate resolution of slice/index +// operands. We should not try to resolve a LHS expression with invalid syntax. + +package p + +func _() { + var items []bool + items[] /* ERROR "operand" */ = false +} diff --git a/src/go/types/fixedbugs/issue39634.go2 b/src/go/types/fixedbugs/issue39634.go2 index 249542d541..78dee00383 100644 --- a/src/go/types/fixedbugs/issue39634.go2 +++ b/src/go/types/fixedbugs/issue39634.go2 @@ -84,7 +84,7 @@ var x T25 /* ERROR without instantiation */ .m1 // crash 26 type T26 = interface{ F26[ /* ERROR methods cannot have type parameters */ Z any]() } -func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ } +func F26[Z any]() T26 { return F26[] /* ERROR operand */ } // crash 27 func e27[T any]() interface{ x27 /* ERROR not a type */ } -- GitLab From f113e9a14f08d23be78f75050185f9796a1d243f Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 18 Feb 2021 14:18:53 -0500 Subject: [PATCH 0019/1298] cmd/dist: match goexperiment.regabi tag when GOEXPERIMENT is on Change-Id: I5e4347dde6dcb49cd96608e4f67e54c7b3050bc2 Reviewed-on: https://go-review.googlesource.com/c/go/+/293851 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/cmd/dist/build.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index c02b92818c..07ede42574 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -982,6 +982,11 @@ func matchtag(tag string) bool { } return !matchtag(tag[1:]) } + if os.Getenv("GOEXPERIMENT") == "regabi" && tag == "goexperiment.regabi" { + // TODO: maybe we can handle GOEXPERIMENT more generally. + // Or remove once we commit to regabi (#40724). + return true + } return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") || (goos == "illumos" && tag == "solaris") || -- GitLab From 7af821a661be57cdd13212695cd6c1095487f2b4 Mon Sep 17 00:00:00 2001 From: yangwenmai Date: Fri, 25 Dec 2020 09:36:41 +0800 Subject: [PATCH 0020/1298] all: faster midpoint computation in binary search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On my machine (3.1 GHz Quad-Core Intel Core i7, macOS 10.15.7 10.15.7), go 1.15.6 benchstat: name old time/op new time/op delta SearchInts-8 20.3ns ± 1% 16.6ns ± 6% -18.37% (p=0.000 n=9+10) Change-Id: I346e5955fd6df6ce10254b22267dbc8d5a2b16c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/279439 Reviewed-by: Ben Shi Reviewed-by: Robert Griesemer Trust: Robert Griesemer --- src/go/token/position.go | 2 +- src/go/token/position_bench_test.go | 24 ++++++++++++++++++++++++ src/reflect/type.go | 2 +- src/strconv/makeisprint.go | 4 ++-- src/strconv/quote.go | 4 ++-- 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 src/go/token/position_bench_test.go diff --git a/src/go/token/position.go b/src/go/token/position.go index a21f5fd056..bbcd8b022b 100644 --- a/src/go/token/position.go +++ b/src/go/token/position.go @@ -540,7 +540,7 @@ func searchInts(a []int, x int) int { // TODO(gri): Remove this when compilers have caught up. i, j := 0, len(a) for i < j { - h := i + (j-i)/2 // avoid overflow when computing h + h := i + (j-i)>>1 // avoid overflow when computing h // i ≤ h < j if a[h] <= x { i = h + 1 diff --git a/src/go/token/position_bench_test.go b/src/go/token/position_bench_test.go new file mode 100644 index 0000000000..41be7285b7 --- /dev/null +++ b/src/go/token/position_bench_test.go @@ -0,0 +1,24 @@ +// Copyright 2021 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 token + +import ( + "testing" +) + +func BenchmarkSearchInts(b *testing.B) { + data := make([]int, 10000) + for i := 0; i < 10000; i++ { + data[i] = i + } + const x = 8 + if r := searchInts(data, x); r != x { + b.Errorf("got index = %d; want %d", r, x) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + searchInts(data, x) + } +} diff --git a/src/reflect/type.go b/src/reflect/type.go index d52816628f..eb2030063a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1723,7 +1723,7 @@ func typesByString(s string) []*rtype { // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). i, j := 0, len(offs) for i < j { - h := i + (j-i)/2 // avoid overflow when computing h + h := i + (j-i)>>1 // avoid overflow when computing h // i ≤ h < j if !(rtypeOff(section, offs[h]).String() >= s) { i = h + 1 // preserves f(i-1) == false diff --git a/src/strconv/makeisprint.go b/src/strconv/makeisprint.go index 79678341d4..909f9e4787 100644 --- a/src/strconv/makeisprint.go +++ b/src/strconv/makeisprint.go @@ -37,7 +37,7 @@ var ( func bsearch16(a []uint16, x uint16) int { i, j := 0, len(a) for i < j { - h := i + (j-i)/2 + h := i + (j-i)>>1 if a[h] < x { i = h + 1 } else { @@ -52,7 +52,7 @@ func bsearch16(a []uint16, x uint16) int { func bsearch32(a []uint32, x uint32) int { i, j := 0, len(a) for i < j { - h := i + (j-i)/2 + h := i + (j-i)>>1 if a[h] < x { i = h + 1 } else { diff --git a/src/strconv/quote.go b/src/strconv/quote.go index 4ffa10b72e..db0dbb288b 100644 --- a/src/strconv/quote.go +++ b/src/strconv/quote.go @@ -440,7 +440,7 @@ func Unquote(s string) (string, error) { func bsearch16(a []uint16, x uint16) int { i, j := 0, len(a) for i < j { - h := i + (j-i)/2 + h := i + (j-i)>>1 if a[h] < x { i = h + 1 } else { @@ -455,7 +455,7 @@ func bsearch16(a []uint16, x uint16) int { func bsearch32(a []uint32, x uint32) int { i, j := 0, len(a) for i < j { - h := i + (j-i)/2 + h := i + (j-i)>>1 if a[h] < x { i = h + 1 } else { -- GitLab From 5f3dabbb79fb3dc8eea9a5050557e9241793dce3 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 19 Feb 2021 09:40:35 -0800 Subject: [PATCH 0021/1298] cmd/compile: fix import of functions of multiple nested closure For import of functions with closures, the connections among closure variables are constructed on-the-fly via CaptureName(). For multiple nested closures, we need to temporarily set r.curfn to each closure we construct, so that the processing of closure variables will be correct for any nested closure inside that closure. Fixes #44335 Change-Id: I34f99e2822250542528ff6b2232bf36756140868 Reviewed-on: https://go-review.googlesource.com/c/go/+/294212 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/iimport.go | 12 ++++++++---- test/fixedbugs/issue44335.dir/a.go | 17 +++++++++++++++++ test/fixedbugs/issue44335.dir/b.go | 11 +++++++++++ test/fixedbugs/issue44335.go | 7 +++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 test/fixedbugs/issue44335.dir/a.go create mode 100644 test/fixedbugs/issue44335.dir/b.go create mode 100644 test/fixedbugs/issue44335.go diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 7b5b113b15..29090a9178 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -986,15 +986,19 @@ func (r *importReader) node() ir.Node { fn.ClosureVars = cvars r.allClosureVars = append(r.allClosureVars, cvars...) - fn.Dcl = r.readFuncDcls(fn) - body := r.stmtList() + fn.Inl = &ir.Inline{} + // Read in the Dcls and Body of the closure after temporarily + // setting r.curfn to fn. + r.funcBody(fn) + fn.Dcl = fn.Inl.Dcl + fn.Body = fn.Inl.Body + fn.Inl = nil + ir.FinishCaptureNames(pos, r.curfn, fn) clo := ir.NewClosureExpr(pos, fn) fn.OClosure = clo - fn.Body = body - return clo // case OPTRLIT: diff --git a/test/fixedbugs/issue44335.dir/a.go b/test/fixedbugs/issue44335.dir/a.go new file mode 100644 index 0000000000..2c9c217813 --- /dev/null +++ b/test/fixedbugs/issue44335.dir/a.go @@ -0,0 +1,17 @@ +// Copyright 2021 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 a + +type W struct { + M func(string) string +} + +func FM(m string) func(W) { + return func(pw W) { + pw.M = func(string) string { + return m + } + } +} diff --git a/test/fixedbugs/issue44335.dir/b.go b/test/fixedbugs/issue44335.dir/b.go new file mode 100644 index 0000000000..e72c2abc6a --- /dev/null +++ b/test/fixedbugs/issue44335.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 b + +import "./a" + +func F() { + a.FM("") +} diff --git a/test/fixedbugs/issue44335.go b/test/fixedbugs/issue44335.go new file mode 100644 index 0000000000..d406838588 --- /dev/null +++ b/test/fixedbugs/issue44335.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 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 ignored -- GitLab From 1901e2647f5724df38e9a9a3756dad01704bc783 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 17 Feb 2021 01:14:19 +0700 Subject: [PATCH 0022/1298] test: add test for findTypeLoop with symbols from other packages CL 274294 improved findTypeLoop but also fixed a new found bug on master branch. This Cl adds test cases for this. Updates #44266 Change-Id: Ie4a07a3487758a1e4ad2f2847dcde975b10d2a77 Reviewed-on: https://go-review.googlesource.com/c/go/+/292889 Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky Trust: Cuong Manh Le --- test/fixedbugs/issue44266.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/fixedbugs/issue44266.go diff --git a/test/fixedbugs/issue44266.go b/test/fixedbugs/issue44266.go new file mode 100644 index 0000000000..c683e56075 --- /dev/null +++ b/test/fixedbugs/issue44266.go @@ -0,0 +1,23 @@ +// errorcheck + +// Copyright 2021 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 p + +import "io" + +type T1 interface { + io.Reader +} + +type T2 struct { + io.SectionReader +} + +type T3 struct { // ERROR "invalid recursive type T3" + T1 + T2 + parent T3 +} -- GitLab From 378f73e2d56998fba872decd61583d96cd9b1f77 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 19 Feb 2021 16:47:04 -0800 Subject: [PATCH 0023/1298] cmd/compile/internal/types2: enable TestIssue25627 Since we have syntax.Walk, we can make this test work again. Change-Id: I55cbde7303e5bcbe1123b6679f2ce859d377fd86 Reviewed-on: https://go-review.googlesource.com/c/go/+/294472 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/issues_test.go | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index 5a32fa590a..ba7cefb892 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -300,8 +300,6 @@ func TestIssue22525(t *testing.T) { } func TestIssue25627(t *testing.T) { - t.Skip("requires syntax tree inspection") - const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T ` // The src strings (without prefix) are constructed such that the number of semicolons // plus one corresponds to the number of fields expected in the respective struct. @@ -325,20 +323,17 @@ func TestIssue25627(t *testing.T) { } } - unimplemented() - /* - ast.Inspect(f, func(n syntax.Node) bool { - if spec, _ := n.(*syntax.TypeDecl); spec != nil { - if tv, ok := info.Types[spec.Type]; ok && spec.Name.Value == "T" { - want := strings.Count(src, ";") + 1 - if got := tv.Type.(*Struct).NumFields(); got != want { - t.Errorf("%s: got %d fields; want %d", src, got, want) - } + syntax.Walk(f, func(n syntax.Node) bool { + if decl, _ := n.(*syntax.TypeDecl); decl != nil { + if tv, ok := info.Types[decl.Type]; ok && decl.Name.Value == "T" { + want := strings.Count(src, ";") + 1 + if got := tv.Type.(*Struct).NumFields(); got != want { + t.Errorf("%s: got %d fields; want %d", src, got, want) } } - return true - }) - */ + } + return false + }) } } -- GitLab From 89eb2b55b9d128f0bd2bfada5d8b2bb115e1d6d8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 19 Feb 2021 16:58:24 -0800 Subject: [PATCH 0024/1298] cmd/compile/internal/types2: review of issues_test.go The changes between (equivalent, and reviewed) go/types/issues_test.go and issues_test.go can be seen by comparing patchset 1 and 3. The actual change is just removing the "// UNREVIEWED" marker and making making some minor code adjustments to match go/types's version more closely. Change-Id: I26f3f700d12db69fc68161a6b0dc081a0e9cd0d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/294473 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/issues_test.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index ba7cefb892..a36b832f04 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2013 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. @@ -29,7 +28,6 @@ func mustParse(t *testing.T, src string) *syntax.File { func TestIssue5770(t *testing.T) { f := mustParse(t, `package p; type S struct{T}`) var conf Config - // conf := Config{Importer: importer.Default()} _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) // do not crash want := "undeclared name: T" if err == nil || !strings.Contains(err.Error(), want) { @@ -76,7 +74,7 @@ var ( } case *syntax.Name: if x.Value == "nil" { - want = NewInterfaceType(nil, nil) // interface{} + want = NewInterfaceType(nil, nil) // interface{} (for now, go/types types this as "untyped nil") } } if want != nil && !Identical(tv.Type, want) { @@ -387,9 +385,6 @@ func TestIssue28005(t *testing.T) { t.Fatal("object X not found") } iface := obj.Type().Underlying().(*Interface) // object X must be an interface - if iface == nil { - t.Fatalf("%s is not an interface", obj) - } // 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. @@ -529,22 +524,22 @@ func TestIssue34921(t *testing.T) { func TestIssue43088(t *testing.T) { // type T1 struct { - // x T2 + // _ T2 // } // // type T2 struct { - // x struct { - // x T2 + // _ struct { + // _ T2 // } // } n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil) T1 := NewNamed(n1, nil, nil) n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil) T2 := NewNamed(n2, nil, nil) - s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", T2, false)}, nil) + s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil) T1.SetUnderlying(s1) - s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", T2, false)}, nil) - s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", s2, false)}, nil) + s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil) + s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil) T2.SetUnderlying(s3) // These calls must terminate (no endless recursion). -- GitLab From 5a0e4fc4e7188fb36e64a7d7d25bab943f081811 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 19 Feb 2021 20:00:33 -0800 Subject: [PATCH 0025/1298] cmd/compile/internal/types2: review of conversions.go The changes between (equivalent, and reviewed) go/types/conversions.go and conversions.go can be seen by comparing patchset 1 and 2. The actual change is just removing the "// UNREVIEWED" marker. Change-Id: I86d20d8100ec29fe3be996b975c9b4aff01be85e Reviewed-on: https://go-review.googlesource.com/c/go/+/294509 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/conversions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/compile/internal/types2/conversions.go b/src/cmd/compile/internal/types2/conversions.go index dc0621919e..d04ccec411 100644 --- a/src/cmd/compile/internal/types2/conversions.go +++ b/src/cmd/compile/internal/types2/conversions.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2012 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. -- GitLab From a2e150c7cded1367fb092e87abb37ce2a1673d11 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 22 Feb 2021 17:02:46 -0800 Subject: [PATCH 0026/1298] go/types, cmd/compile/internal/types2: use regular type printing for unsafe.Pointer Type string printing special-cased printing of unsafe.Pointer because it's a built-in type; yet it's declared in a package like any other imported or used-defined type (unlike built-in types such as int). Use the same mechanism for printing unsafe.Pointer like any other (non-basic) type. This will make it possible to use the package Qualifier if so desired. Fixes #44515. Change-Id: I0dd1026f850737ecfc4bb99135cfb8e3c18be9e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/295271 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/issues_test.go | 22 +++++++++++++++++++ src/cmd/compile/internal/types2/typestring.go | 10 +++++++-- src/go/types/issues_test.go | 22 +++++++++++++++++++ src/go/types/typestring.go | 11 ++++++++-- 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index a36b832f04..e1f5c92fc4 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -546,3 +546,25 @@ func TestIssue43088(t *testing.T) { Comparable(T1) Comparable(T2) } + +func TestIssue44515(t *testing.T) { + typ := Unsafe.Scope().Lookup("Pointer").Type() + + got := TypeString(typ, nil) + want := "unsafe.Pointer" + if got != want { + t.Errorf("got %q; want %q", got, want) + } + + qf := func(pkg *Package) string { + if pkg == Unsafe { + return "foo" + } + return "" + } + got = TypeString(typ, qf) + want = "foo.Pointer" + if got != want { + t.Errorf("got %q; want %q", got, want) + } +} diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go index af44624d2c..40016697b7 100644 --- a/src/cmd/compile/internal/types2/typestring.go +++ b/src/cmd/compile/internal/types2/typestring.go @@ -98,9 +98,15 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("") case *Basic: - if t.kind == UnsafePointer { - buf.WriteString("unsafe.") + // exported basic types go into package unsafe + // (currently this is just unsafe.Pointer) + if isExported(t.name) { + if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil { + writeTypeName(buf, obj, qf) + break + } } + if gcCompatibilityMode { // forget the alias names switch t.kind { diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 34850eb034..9ed2934c74 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -549,3 +549,25 @@ func TestIssue43088(t *testing.T) { Comparable(T1) Comparable(T2) } + +func TestIssue44515(t *testing.T) { + typ := Unsafe.Scope().Lookup("Pointer").Type() + + got := TypeString(typ, nil) + want := "unsafe.Pointer" + if got != want { + t.Errorf("got %q; want %q", got, want) + } + + qf := func(pkg *Package) string { + if pkg == Unsafe { + return "foo" + } + return "" + } + got = TypeString(typ, qf) + want = "foo.Pointer" + if got != want { + t.Errorf("got %q; want %q", got, want) + } +} diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index 4697bd31e6..a0caded160 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -9,6 +9,7 @@ package types import ( "bytes" "fmt" + "go/token" "unicode/utf8" ) @@ -98,9 +99,15 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("") case *Basic: - if t.kind == UnsafePointer { - buf.WriteString("unsafe.") + // exported basic types go into package unsafe + // (currently this is just unsafe.Pointer) + if token.IsExported(t.name) { + if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil { + writeTypeName(buf, obj, qf) + break + } } + if gcCompatibilityMode { // forget the alias names switch t.kind { -- GitLab From 975ba6e2b2547e0c4065a09644686723704283e1 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 27 Nov 2020 11:00:29 +0700 Subject: [PATCH 0027/1298] cmd/compile: mark OpSB, OpSP as poor statement Op So that would make them last choice for a statement boundary. This is follow up of CL 273506. Change-Id: I0203aa0e0d95d538064c2113143c85c4fbb1e65e Reviewed-on: https://go-review.googlesource.com/c/go/+/273666 TryBot-Result: Go Bot Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/numberlines.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/numberlines.go b/src/cmd/compile/internal/ssa/numberlines.go index 2a9c8e4f32..54a158ff87 100644 --- a/src/cmd/compile/internal/ssa/numberlines.go +++ b/src/cmd/compile/internal/ssa/numberlines.go @@ -16,7 +16,7 @@ func isPoorStatementOp(op Op) bool { // so that a debugger-user sees the stop before the panic, and can examine the value. case OpAddr, OpLocalAddr, OpOffPtr, OpStructSelect, OpPhi, OpITab, OpIData, OpIMake, OpStringMake, OpSliceMake, OpStructMake0, OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4, - OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F: + OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F, OpSB, OpSP: return true } return false -- GitLab From 6a40dd05d833b2bd78eb68ac67d7e860edff6878 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 19 Feb 2021 20:06:24 -0800 Subject: [PATCH 0028/1298] cmd/compile/internal/types2: review of sanitize.go Remove the "// UNREVIEWED" marker and add guards (as in go/types) to prevent data races. To see the added guards, see compare patch sets 3 and 4. The equivalent changes for go/types were done in https://golang.org/cl/294411. Change-Id: Ibef07eaae400bd32bff32b102cc743580290d135 Reviewed-on: https://go-review.googlesource.com/c/go/+/294510 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/sanitize.go | 87 ++++++++++++++++----- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go index bac569416b..cd1719c8c0 100644 --- a/src/cmd/compile/internal/types2/sanitize.go +++ b/src/cmd/compile/internal/types2/sanitize.go @@ -1,10 +1,16 @@ -// UNREVIEWED // Copyright 2020 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 types2 +// sanitizeInfo walks the types contained in info to ensure that all instances +// are expanded. +// +// This includes some objects that may be shared across concurrent +// type-checking passes (such as those in the universe scope), so we are +// careful here not to write types that are already sanitized. This avoids a +// data race as any shared types should already be sanitized. func sanitizeInfo(info *Info) { var s sanitizer = make(map[Type]Type) @@ -12,27 +18,42 @@ func sanitizeInfo(info *Info) { // If modified, they must be assigned back. for e, tv := range info.Types { - tv.Type = s.typ(tv.Type) - info.Types[e] = tv + if typ := s.typ(tv.Type); typ != tv.Type { + tv.Type = typ + info.Types[e] = tv + } } for e, inf := range info.Inferred { + changed := false for i, targ := range inf.Targs { - inf.Targs[i] = s.typ(targ) + if typ := s.typ(targ); typ != targ { + inf.Targs[i] = typ + changed = true + } + } + if typ := s.typ(inf.Sig); typ != inf.Sig { + inf.Sig = typ.(*Signature) + changed = true + } + if changed { + info.Inferred[e] = inf } - inf.Sig = s.typ(inf.Sig).(*Signature) - info.Inferred[e] = inf } for _, obj := range info.Defs { if obj != nil { - obj.setType(s.typ(obj.Type())) + if typ := s.typ(obj.Type()); typ != obj.Type() { + obj.setType(typ) + } } } for _, obj := range info.Uses { if obj != nil { - obj.setType(s.typ(obj.Type())) + if typ := s.typ(obj.Type()); typ != obj.Type() { + obj.setType(typ) + } } } @@ -56,16 +77,22 @@ func (s sanitizer) typ(typ Type) Type { // nothing to do case *Array: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Slice: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Struct: s.varList(t.fields) case *Pointer: - t.base = s.typ(t.base) + if base := s.typ(t.base); base != t.base { + t.base = base + } case *Tuple: s.tuple(t) @@ -86,27 +113,39 @@ func (s sanitizer) typ(typ Type) Type { s.typ(t.allTypes) case *Map: - t.key = s.typ(t.key) - t.elem = s.typ(t.elem) + if key := s.typ(t.key); key != t.key { + t.key = key + } + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Chan: - t.elem = s.typ(t.elem) + if elem := s.typ(t.elem); elem != t.elem { + t.elem = elem + } case *Named: - t.orig = s.typ(t.orig) - t.underlying = s.typ(t.underlying) + if orig := s.typ(t.orig); orig != t.orig { + t.orig = orig + } + if under := s.typ(t.underlying); under != t.underlying { + t.underlying = under + } s.typeList(t.targs) s.funcList(t.methods) case *TypeParam: - t.bound = s.typ(t.bound) + if bound := s.typ(t.bound); bound != t.bound { + t.bound = bound + } case *instance: typ = t.expand() s[t] = typ default: - unimplemented() + panic("unimplemented") } return typ @@ -114,7 +153,9 @@ func (s sanitizer) typ(typ Type) Type { func (s sanitizer) var_(v *Var) { if v != nil { - v.typ = s.typ(v.typ) + if typ := s.typ(v.typ); typ != v.typ { + v.typ = typ + } } } @@ -132,7 +173,9 @@ func (s sanitizer) tuple(t *Tuple) { func (s sanitizer) func_(f *Func) { if f != nil { - f.typ = s.typ(f.typ) + if typ := s.typ(f.typ); typ != f.typ { + f.typ = typ + } } } @@ -144,6 +187,8 @@ func (s sanitizer) funcList(list []*Func) { func (s sanitizer) typeList(list []Type) { for i, t := range list { - list[i] = s.typ(t) + if typ := s.typ(t); typ != t { + list[i] = typ + } } } -- GitLab From 5e804ba17da12f53c0d66c1ce1e0e7845feb7f69 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 28 Nov 2020 02:46:00 +0700 Subject: [PATCH 0029/1298] cmd/compile: use transitive relations for slice len/cap in poset Currently, we keep track of slice len by mapping from slice ID to len/cap SSA value. However, slice len/cap can have multiple SSA values, so when updating fact table for slice len/cap, we only update in one place. Instead, we can take advantage of the transitive relations provided by poset. So all duplicated slice lens are set as equal to one another. When updating fact table for one, that fact will be reflected to all others. The same mechanism is applied for slice cap. Removes 15 bounds checks from std/cmd. Fixes #42603 Change-Id: I32c07968824cc33765b1e441b3ae2c4b5f5997c3 Reviewed-on: https://go-review.googlesource.com/c/go/+/273670 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/prove.go | 16 ++++++++++++++-- test/prove.go | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 8a2e7c09bc..bcfdfc13f0 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -778,7 +778,14 @@ func prove(f *Func) { if ft.lens == nil { ft.lens = map[ID]*Value{} } - ft.lens[v.Args[0].ID] = v + // Set all len Values for the same slice as equal in the poset. + // The poset handles transitive relations, so Values related to + // any OpSliceLen for this slice will be correctly related to others. + if l, ok := ft.lens[v.Args[0].ID]; ok { + ft.update(b, v, l, signed, eq) + } else { + ft.lens[v.Args[0].ID] = v + } ft.update(b, v, ft.zero, signed, gt|eq) if v.Args[0].Op == OpSliceMake { if lensVars == nil { @@ -790,7 +797,12 @@ func prove(f *Func) { if ft.caps == nil { ft.caps = map[ID]*Value{} } - ft.caps[v.Args[0].ID] = v + // Same as case OpSliceLen above, but for slice cap. + if c, ok := ft.caps[v.Args[0].ID]; ok { + ft.update(b, v, c, signed, eq) + } else { + ft.caps[v.Args[0].ID] = v + } ft.update(b, v, ft.zero, signed, gt|eq) if v.Args[0].Op == OpSliceMake { if lensVars == nil { diff --git a/test/prove.go b/test/prove.go index d37021d283..af9c06a6f7 100644 --- a/test/prove.go +++ b/test/prove.go @@ -629,6 +629,22 @@ func trans3(a, b []int, i int) { _ = b[i] // ERROR "Proved IsInBounds$" } +func trans4(b []byte, x int) { + // Issue #42603: slice len/cap transitive relations. + switch x { + case 0: + if len(b) < 20 { + return + } + _ = b[:2] // ERROR "Proved IsSliceInBounds$" + case 1: + if len(b) < 40 { + return + } + _ = b[:2] // ERROR "Proved IsSliceInBounds$" + } +} + // Derived from nat.cmp func natcmp(x, y []uint) (r int) { m := len(x) -- GitLab From 4048491234203e1ee803d489d11a02c90b14596a Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 17 Feb 2021 11:36:58 +0700 Subject: [PATCH 0030/1298] cmd/compile,runtime: make selectnbrecv return two values The only different between selectnbrecv and selectnbrecv2 is the later set the input pointer value by second return value from chanrecv. So by making selectnbrecv return two values from chanrecv, we can get rid of selectnbrecv2, the compiler can now call only selectnbrecv and generate simpler code. Change-Id: Ifaf6cf1314c4f47b06ed9606b1578319be808507 Reviewed-on: https://go-review.googlesource.com/c/go/+/292890 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/builtin.go | 2 +- .../internal/typecheck/builtin/runtime.go | 2 +- src/cmd/compile/internal/walk/select.go | 20 +++++-------- src/runtime/chan.go | 30 ++----------------- 4 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index f9a4f6aef4..17393f801c 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -316,7 +316,7 @@ func runtimeTypes() []*types.Type { typs[92] = newSig(params(typs[1], typs[3]), nil) typs[93] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) typs[94] = newSig(params(typs[87], typs[3]), params(typs[6])) - typs[95] = newSig(params(typs[3], typs[84]), params(typs[6])) + typs[95] = newSig(params(typs[3], typs[84]), params(typs[6], typs[6])) typs[96] = types.NewPtr(typs[6]) typs[97] = newSig(params(typs[3], typs[96], typs[84]), params(typs[6])) typs[98] = newSig(params(typs[63]), nil) diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index acb69c7b28..77a6fdb026 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -166,7 +166,7 @@ func typedmemclr(typ *byte, dst *any) func typedslicecopy(typ *byte, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int func selectnbsend(hchan chan<- any, elem *any) bool -func selectnbrecv(elem *any, hchan <-chan any) bool +func selectnbrecv(elem *any, hchan <-chan any) (bool, bool) func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool func selectsetpc(pc *uintptr) diff --git a/src/cmd/compile/internal/walk/select.go b/src/cmd/compile/internal/walk/select.go index 873be289dc..d2b67ddf55 100644 --- a/src/cmd/compile/internal/walk/select.go +++ b/src/cmd/compile/internal/walk/select.go @@ -106,7 +106,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node { ir.SetPos(n) r := ir.NewIfStmt(base.Pos, nil, nil, nil) *r.PtrInit() = cas.Init() - var call ir.Node + var cond ir.Node switch n.Op() { default: base.Fatalf("select %v", n.Op()) @@ -115,7 +115,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node { // if selectnbsend(c, v) { body } else { default body } n := n.(*ir.SendStmt) ch := n.Chan - call = mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Value) + cond = mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Value) case ir.OSELRECV2: n := n.(*ir.AssignListStmt) @@ -125,18 +125,14 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node { if ir.IsBlank(elem) { elem = typecheck.NodNil() } - if ir.IsBlank(n.Lhs[1]) { - // if selectnbrecv(&v, c) { body } else { default body } - call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch) - } else { - // TODO(cuonglm): make this use selectnbrecv() - // if selectnbrecv2(&v, &received, c) { body } else { default body } - receivedp := typecheck.Expr(typecheck.NodAddr(n.Lhs[1])) - call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch) - } + cond = typecheck.Temp(types.Types[types.TBOOL]) + fn := chanfn("selectnbrecv", 2, ch.Type()) + call := mkcall1(fn, fn.Type().Results(), r.PtrInit(), elem, ch) + as := ir.NewAssignListStmt(r.Pos(), ir.OAS2, []ir.Node{cond, n.Lhs[1]}, []ir.Node{call}) + r.PtrInit().Append(typecheck.Stmt(as)) } - r.Cond = typecheck.Expr(call) + r.Cond = typecheck.Expr(cond) r.Body = cas.Body r.Else = append(dflt.Init(), dflt.Body...) return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)} diff --git a/src/runtime/chan.go b/src/runtime/chan.go index ba56e2cc40..f2a75b30f4 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -687,28 +687,6 @@ func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) { return chansend(c, elem, false, getcallerpc()) } -// compiler implements -// -// select { -// case v = <-c: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if selectnbrecv(&v, c) { -// ... foo -// } else { -// ... bar -// } -// -func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) { - selected, _ = chanrecv(c, elem, false) - return -} - // compiler implements // // select { @@ -720,16 +698,14 @@ func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) { // // as // -// if c != nil && selectnbrecv2(&v, &ok, c) { +// if selected, ok = selectnbrecv(&v, c); selected { // ... foo // } else { // ... bar // } // -func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool) { - // TODO(khr): just return 2 values from this function, now that it is in Go. - selected, *received = chanrecv(c, elem, false) - return +func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected, received bool) { + return chanrecv(c, elem, false) } //go:linkname reflect_chansend reflect.chansend -- GitLab From 86deb459de6a309503aa445a7d686bd139354e5e Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 17 Feb 2021 11:38:14 +0700 Subject: [PATCH 0031/1298] cmd/compile: remove selectnbrecv2 Previous CL did remove selectnbrecv2 in runtime, the compiler now only call selectnbrecv, so remove this. Make this as separated CL because it adds much of noise to git stat. Change-Id: I06e89c823c0403e9bd66f2633409c455a46d6e79 Reviewed-on: https://go-review.googlesource.com/c/go/+/292891 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/builtin.go | 197 +++++++++--------- .../internal/typecheck/builtin/runtime.go | 1 - 2 files changed, 97 insertions(+), 101 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 17393f801c..b095a014f0 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -128,76 +128,75 @@ var runtimeDecls = [...]struct { {"typedslicecopy", funcTag, 93}, {"selectnbsend", funcTag, 94}, {"selectnbrecv", funcTag, 95}, - {"selectnbrecv2", funcTag, 97}, - {"selectsetpc", funcTag, 98}, - {"selectgo", funcTag, 99}, + {"selectsetpc", funcTag, 96}, + {"selectgo", funcTag, 97}, {"block", funcTag, 9}, - {"makeslice", funcTag, 100}, - {"makeslice64", funcTag, 101}, - {"makeslicecopy", funcTag, 102}, - {"growslice", funcTag, 104}, - {"memmove", funcTag, 105}, - {"memclrNoHeapPointers", funcTag, 106}, - {"memclrHasPointers", funcTag, 106}, - {"memequal", funcTag, 107}, - {"memequal0", funcTag, 108}, - {"memequal8", funcTag, 108}, - {"memequal16", funcTag, 108}, - {"memequal32", funcTag, 108}, - {"memequal64", funcTag, 108}, - {"memequal128", funcTag, 108}, - {"f32equal", funcTag, 109}, - {"f64equal", funcTag, 109}, - {"c64equal", funcTag, 109}, - {"c128equal", funcTag, 109}, - {"strequal", funcTag, 109}, - {"interequal", funcTag, 109}, - {"nilinterequal", funcTag, 109}, - {"memhash", funcTag, 110}, - {"memhash0", funcTag, 111}, - {"memhash8", funcTag, 111}, - {"memhash16", funcTag, 111}, - {"memhash32", funcTag, 111}, - {"memhash64", funcTag, 111}, - {"memhash128", funcTag, 111}, - {"f32hash", funcTag, 111}, - {"f64hash", funcTag, 111}, - {"c64hash", funcTag, 111}, - {"c128hash", funcTag, 111}, - {"strhash", funcTag, 111}, - {"interhash", funcTag, 111}, - {"nilinterhash", funcTag, 111}, - {"int64div", funcTag, 112}, - {"uint64div", funcTag, 113}, - {"int64mod", funcTag, 112}, - {"uint64mod", funcTag, 113}, - {"float64toint64", funcTag, 114}, - {"float64touint64", funcTag, 115}, - {"float64touint32", funcTag, 116}, - {"int64tofloat64", funcTag, 117}, - {"uint64tofloat64", funcTag, 118}, - {"uint32tofloat64", funcTag, 119}, - {"complex128div", funcTag, 120}, + {"makeslice", funcTag, 98}, + {"makeslice64", funcTag, 99}, + {"makeslicecopy", funcTag, 100}, + {"growslice", funcTag, 102}, + {"memmove", funcTag, 103}, + {"memclrNoHeapPointers", funcTag, 104}, + {"memclrHasPointers", funcTag, 104}, + {"memequal", funcTag, 105}, + {"memequal0", funcTag, 106}, + {"memequal8", funcTag, 106}, + {"memequal16", funcTag, 106}, + {"memequal32", funcTag, 106}, + {"memequal64", funcTag, 106}, + {"memequal128", funcTag, 106}, + {"f32equal", funcTag, 107}, + {"f64equal", funcTag, 107}, + {"c64equal", funcTag, 107}, + {"c128equal", funcTag, 107}, + {"strequal", funcTag, 107}, + {"interequal", funcTag, 107}, + {"nilinterequal", funcTag, 107}, + {"memhash", funcTag, 108}, + {"memhash0", funcTag, 109}, + {"memhash8", funcTag, 109}, + {"memhash16", funcTag, 109}, + {"memhash32", funcTag, 109}, + {"memhash64", funcTag, 109}, + {"memhash128", funcTag, 109}, + {"f32hash", funcTag, 109}, + {"f64hash", funcTag, 109}, + {"c64hash", funcTag, 109}, + {"c128hash", funcTag, 109}, + {"strhash", funcTag, 109}, + {"interhash", funcTag, 109}, + {"nilinterhash", funcTag, 109}, + {"int64div", funcTag, 110}, + {"uint64div", funcTag, 111}, + {"int64mod", funcTag, 110}, + {"uint64mod", funcTag, 111}, + {"float64toint64", funcTag, 112}, + {"float64touint64", funcTag, 113}, + {"float64touint32", funcTag, 114}, + {"int64tofloat64", funcTag, 115}, + {"uint64tofloat64", funcTag, 116}, + {"uint32tofloat64", funcTag, 117}, + {"complex128div", funcTag, 118}, {"racefuncenter", funcTag, 31}, {"racefuncenterfp", funcTag, 9}, {"racefuncexit", funcTag, 9}, {"raceread", funcTag, 31}, {"racewrite", funcTag, 31}, - {"racereadrange", funcTag, 121}, - {"racewriterange", funcTag, 121}, - {"msanread", funcTag, 121}, - {"msanwrite", funcTag, 121}, - {"msanmove", funcTag, 122}, - {"checkptrAlignment", funcTag, 123}, - {"checkptrArithmetic", funcTag, 125}, - {"libfuzzerTraceCmp1", funcTag, 127}, - {"libfuzzerTraceCmp2", funcTag, 129}, - {"libfuzzerTraceCmp4", funcTag, 130}, - {"libfuzzerTraceCmp8", funcTag, 131}, - {"libfuzzerTraceConstCmp1", funcTag, 127}, - {"libfuzzerTraceConstCmp2", funcTag, 129}, - {"libfuzzerTraceConstCmp4", funcTag, 130}, - {"libfuzzerTraceConstCmp8", funcTag, 131}, + {"racereadrange", funcTag, 119}, + {"racewriterange", funcTag, 119}, + {"msanread", funcTag, 119}, + {"msanwrite", funcTag, 119}, + {"msanmove", funcTag, 120}, + {"checkptrAlignment", funcTag, 121}, + {"checkptrArithmetic", funcTag, 123}, + {"libfuzzerTraceCmp1", funcTag, 125}, + {"libfuzzerTraceCmp2", funcTag, 127}, + {"libfuzzerTraceCmp4", funcTag, 128}, + {"libfuzzerTraceCmp8", funcTag, 129}, + {"libfuzzerTraceConstCmp1", funcTag, 125}, + {"libfuzzerTraceConstCmp2", funcTag, 127}, + {"libfuzzerTraceConstCmp4", funcTag, 128}, + {"libfuzzerTraceConstCmp8", funcTag, 129}, {"x86HasPOPCNT", varTag, 6}, {"x86HasSSE41", varTag, 6}, {"x86HasFMA", varTag, 6}, @@ -220,7 +219,7 @@ func params(tlist ...*types.Type) []*types.Field { } func runtimeTypes() []*types.Type { - var typs [132]*types.Type + var typs [130]*types.Type typs[0] = types.ByteType typs[1] = types.NewPtr(typs[0]) typs[2] = types.Types[types.TANY] @@ -317,41 +316,39 @@ func runtimeTypes() []*types.Type { typs[93] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) typs[94] = newSig(params(typs[87], typs[3]), params(typs[6])) typs[95] = newSig(params(typs[3], typs[84]), params(typs[6], typs[6])) - typs[96] = types.NewPtr(typs[6]) - typs[97] = newSig(params(typs[3], typs[96], typs[84]), params(typs[6])) - typs[98] = newSig(params(typs[63]), nil) - typs[99] = newSig(params(typs[1], typs[1], typs[63], typs[15], typs[15], typs[6]), params(typs[15], typs[6])) - typs[100] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7])) - typs[101] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) - typs[102] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) - typs[103] = types.NewSlice(typs[2]) - typs[104] = newSig(params(typs[1], typs[103], typs[15]), params(typs[103])) - typs[105] = newSig(params(typs[3], typs[3], typs[5]), nil) - typs[106] = newSig(params(typs[7], typs[5]), nil) - typs[107] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) - typs[108] = newSig(params(typs[3], typs[3]), params(typs[6])) - typs[109] = newSig(params(typs[7], typs[7]), params(typs[6])) - typs[110] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) - typs[111] = newSig(params(typs[7], typs[5]), params(typs[5])) - typs[112] = newSig(params(typs[22], typs[22]), params(typs[22])) - typs[113] = newSig(params(typs[24], typs[24]), params(typs[24])) - typs[114] = newSig(params(typs[20]), params(typs[22])) - typs[115] = newSig(params(typs[20]), params(typs[24])) - typs[116] = newSig(params(typs[20]), params(typs[65])) - typs[117] = newSig(params(typs[22]), params(typs[20])) - typs[118] = newSig(params(typs[24]), params(typs[20])) - typs[119] = newSig(params(typs[65]), params(typs[20])) - typs[120] = newSig(params(typs[26], typs[26]), params(typs[26])) - typs[121] = newSig(params(typs[5], typs[5]), nil) - typs[122] = newSig(params(typs[5], typs[5], typs[5]), nil) - typs[123] = newSig(params(typs[7], typs[1], typs[5]), nil) - typs[124] = types.NewSlice(typs[7]) - typs[125] = newSig(params(typs[7], typs[124]), nil) - typs[126] = types.Types[types.TUINT8] + typs[96] = newSig(params(typs[63]), nil) + typs[97] = newSig(params(typs[1], typs[1], typs[63], typs[15], typs[15], typs[6]), params(typs[15], typs[6])) + typs[98] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7])) + typs[99] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) + typs[100] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) + typs[101] = types.NewSlice(typs[2]) + typs[102] = newSig(params(typs[1], typs[101], typs[15]), params(typs[101])) + typs[103] = newSig(params(typs[3], typs[3], typs[5]), nil) + typs[104] = newSig(params(typs[7], typs[5]), nil) + typs[105] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) + typs[106] = newSig(params(typs[3], typs[3]), params(typs[6])) + typs[107] = newSig(params(typs[7], typs[7]), params(typs[6])) + typs[108] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) + typs[109] = newSig(params(typs[7], typs[5]), params(typs[5])) + typs[110] = newSig(params(typs[22], typs[22]), params(typs[22])) + typs[111] = newSig(params(typs[24], typs[24]), params(typs[24])) + typs[112] = newSig(params(typs[20]), params(typs[22])) + typs[113] = newSig(params(typs[20]), params(typs[24])) + typs[114] = newSig(params(typs[20]), params(typs[65])) + typs[115] = newSig(params(typs[22]), params(typs[20])) + typs[116] = newSig(params(typs[24]), params(typs[20])) + typs[117] = newSig(params(typs[65]), params(typs[20])) + typs[118] = newSig(params(typs[26], typs[26]), params(typs[26])) + typs[119] = newSig(params(typs[5], typs[5]), nil) + typs[120] = newSig(params(typs[5], typs[5], typs[5]), nil) + typs[121] = newSig(params(typs[7], typs[1], typs[5]), nil) + typs[122] = types.NewSlice(typs[7]) + typs[123] = newSig(params(typs[7], typs[122]), nil) + typs[124] = types.Types[types.TUINT8] + typs[125] = newSig(params(typs[124], typs[124]), nil) + typs[126] = types.Types[types.TUINT16] typs[127] = newSig(params(typs[126], typs[126]), nil) - typs[128] = types.Types[types.TUINT16] - typs[129] = newSig(params(typs[128], typs[128]), nil) - typs[130] = newSig(params(typs[65], typs[65]), nil) - typs[131] = newSig(params(typs[24], typs[24]), nil) + typs[128] = newSig(params(typs[65], typs[65]), nil) + typs[129] = newSig(params(typs[24], typs[24]), nil) return typs[:] } diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index 77a6fdb026..ad82a9b349 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -167,7 +167,6 @@ func typedslicecopy(typ *byte, dstPtr *any, dstLen int, srcPtr *any, srcLen int) func selectnbsend(hchan chan<- any, elem *any) bool func selectnbrecv(elem *any, hchan <-chan any) (bool, bool) -func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool func selectsetpc(pc *uintptr) func selectgo(cas0 *byte, order0 *byte, pc0 *uintptr, nsends int, nrecvs int, block bool) (int, bool) -- GitLab From e52149822b54811cedaaa87013de3fa4bc634e95 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 17 Feb 2021 15:14:21 +0700 Subject: [PATCH 0032/1298] cmd/compile: simplify assert{E,I}2I{,2} calling conventions This CL rebases CL 273694 on top of master with @mdempsky's permission. For assertE2I and assertI2I, there's no need to pass through the interface's data pointer: it's always going to come back unmodified. For assertE2I2 and assertI2I2, there's no need for an extra bool result parameter: it's redundant with testing the returned interface value for nil. Change-Id: Ic92d4409ad381952f875d3d74b8cf11c32702fa6 Reviewed-on: https://go-review.googlesource.com/c/go/+/292892 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/ssagen/ssa.go | 23 +++++++++------ src/cmd/compile/internal/typecheck/builtin.go | 10 +++---- .../internal/typecheck/builtin/runtime.go | 8 +++--- src/runtime/iface.go | 28 ++++++------------- src/runtime/mfinal.go | 4 +-- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 6b1ddebd32..e13ca90d33 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6075,18 +6075,23 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val if base.Debug.TypeAssert > 0 { base.WarnfAt(n.Pos(), "type assertion not inlined") } - if n.X.Type().IsEmptyInterface() { - if commaok { - call := s.rtcall(ir.Syms.AssertE2I2, true, []*types.Type{n.Type(), types.Types[types.TBOOL]}, target, iface) - return call[0], call[1] + if !commaok { + fn := ir.Syms.AssertI2I + if n.X.Type().IsEmptyInterface() { + fn = ir.Syms.AssertE2I } - return s.rtcall(ir.Syms.AssertE2I, true, []*types.Type{n.Type()}, target, iface)[0], nil + data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface) + tab := s.newValue1(ssa.OpITab, byteptr, iface) + tab = s.rtcall(fn, true, []*types.Type{byteptr}, target, tab)[0] + return s.newValue2(ssa.OpIMake, n.Type(), tab, data), nil } - if commaok { - call := s.rtcall(ir.Syms.AssertI2I2, true, []*types.Type{n.Type(), types.Types[types.TBOOL]}, target, iface) - return call[0], call[1] + fn := ir.Syms.AssertI2I2 + if n.X.Type().IsEmptyInterface() { + fn = ir.Syms.AssertE2I2 } - return s.rtcall(ir.Syms.AssertI2I, true, []*types.Type{n.Type()}, target, iface)[0], nil + res = s.rtcall(fn, true, []*types.Type{n.Type()}, target, iface)[0] + resok = s.newValue2(ssa.OpNeqInter, types.Types[types.TBOOL], res, s.constInterface(n.Type())) + return } if base.Debug.TypeAssert > 0 { diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index b095a014f0..3c7776d9ae 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -80,10 +80,10 @@ var runtimeDecls = [...]struct { {"convT2Enoptr", funcTag, 59}, {"convT2I", funcTag, 59}, {"convT2Inoptr", funcTag, 59}, - {"assertE2I", funcTag, 57}, - {"assertE2I2", funcTag, 60}, - {"assertI2I", funcTag, 57}, - {"assertI2I2", funcTag, 60}, + {"assertE2I", funcTag, 60}, + {"assertE2I2", funcTag, 57}, + {"assertI2I", funcTag, 60}, + {"assertI2I2", funcTag, 57}, {"panicdottypeE", funcTag, 61}, {"panicdottypeI", funcTag, 61}, {"panicnildottype", funcTag, 62}, @@ -280,7 +280,7 @@ func runtimeTypes() []*types.Type { typs[57] = newSig(params(typs[1], typs[2]), params(typs[2])) typs[58] = newSig(params(typs[2]), params(typs[7])) typs[59] = newSig(params(typs[1], typs[3]), params(typs[2])) - typs[60] = newSig(params(typs[1], typs[2]), params(typs[2], typs[6])) + typs[60] = newSig(params(typs[1], typs[1]), params(typs[1])) typs[61] = newSig(params(typs[1], typs[1], typs[1]), nil) typs[62] = newSig(params(typs[1]), nil) typs[63] = types.NewPtr(typs[5]) diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index ad82a9b349..d5e00afcf8 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -101,10 +101,10 @@ func convT2I(tab *byte, elem *any) (ret any) func convT2Inoptr(tab *byte, elem *any) (ret any) // interface type assertions x.(T) -func assertE2I(typ *byte, iface any) (ret any) -func assertE2I2(typ *byte, iface any) (ret any, b bool) -func assertI2I(typ *byte, iface any) (ret any) -func assertI2I2(typ *byte, iface any) (ret any, b bool) +func assertE2I(inter *byte, typ *byte) *byte +func assertE2I2(inter *byte, eface any) (ret any) +func assertI2I(inter *byte, tab *byte) *byte +func assertI2I2(inter *byte, iface any) (ret any) func panicdottypeE(have, want, iface *byte) func panicdottypeI(have, want, iface *byte) func panicnildottype(want *byte) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 0504b89363..02b18dabff 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -447,23 +447,18 @@ func convI2I(inter *interfacetype, i iface) (r iface) { return } -func assertI2I(inter *interfacetype, i iface) (r iface) { - tab := i.tab +func assertI2I(inter *interfacetype, tab *itab) *itab { if tab == nil { // explicit conversions require non-nil interface value. panic(&TypeAssertionError{nil, nil, &inter.typ, ""}) } if tab.inter == inter { - r.tab = tab - r.data = i.data - return + return tab } - r.tab = getitab(inter, tab._type, false) - r.data = i.data - return + return getitab(inter, tab._type, false) } -func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) { +func assertI2I2(inter *interfacetype, i iface) (r iface) { tab := i.tab if tab == nil { return @@ -476,22 +471,18 @@ func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) { } r.tab = tab r.data = i.data - b = true return } -func assertE2I(inter *interfacetype, e eface) (r iface) { - t := e._type +func assertE2I(inter *interfacetype, t *_type) *itab { if t == nil { // explicit conversions require non-nil interface value. panic(&TypeAssertionError{nil, nil, &inter.typ, ""}) } - r.tab = getitab(inter, t, false) - r.data = e.data - return + return getitab(inter, t, false) } -func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) { +func assertE2I2(inter *interfacetype, e eface) (r iface) { t := e._type if t == nil { return @@ -502,18 +493,17 @@ func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) { } r.tab = tab r.data = e.data - b = true return } //go:linkname reflect_ifaceE2I reflect.ifaceE2I func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { - *dst = assertE2I(inter, e) + *dst = iface{assertE2I(inter, e._type), e.data} } //go:linkname reflectlite_ifaceE2I internal/reflectlite.ifaceE2I func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) { - *dst = assertE2I(inter, e) + *dst = iface{assertE2I(inter, e._type), e.data} } func iterate_itabs(fn func(*itab)) { diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index 7d0313be12..e92ec80e3c 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -214,7 +214,7 @@ func runfinq() { if len(ityp.mhdr) != 0 { // convert to interface with methods // this conversion is guaranteed to succeed - we checked in SetFinalizer - *(*iface)(frame) = assertE2I(ityp, *(*eface)(frame)) + (*iface)(frame).tab = assertE2I(ityp, (*eface)(frame)._type) } default: throw("bad kind in runfinq") @@ -403,7 +403,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // ok - satisfies empty interface goto okarg } - if _, ok := assertE2I2(ityp, *efaceOf(&obj)); ok { + if iface := assertE2I2(ityp, *efaceOf(&obj)); iface.tab != nil { goto okarg } } -- GitLab From 2a18e37c4e78e26c9f1e613dfa97aaf275ea0b4d Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 17 Feb 2021 15:27:42 +0700 Subject: [PATCH 0033/1298] cmd/compile: remove backend's "scratch mem" support This CL rebases CL 273987 on top of master with @mdempsky's permission. The last (only?) use for this feature was 387 support, which was removed in golang.org/cl/258957. Change-Id: I4f79fee8d0c336c9b6082bcd5eb6ece52c032dc0 Reviewed-on: https://go-review.googlesource.com/c/go/+/292893 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/ssa/config.go | 1 - src/cmd/compile/internal/ssa/gen/386Ops.go | 32 ++++++------- src/cmd/compile/internal/ssa/gen/main.go | 6 --- src/cmd/compile/internal/ssa/opGen.go | 54 +++++++++------------- src/cmd/compile/internal/ssagen/pgen.go | 10 ---- src/cmd/compile/internal/ssagen/ssa.go | 27 ++--------- 6 files changed, 42 insertions(+), 88 deletions(-) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index c29bc8fae6..f3a3a88a66 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -42,7 +42,6 @@ type Config struct { useHmul bool // Use optimizations that need Hmul* operations SoftFloat bool // Race bool // race detector enabled - NeedsFpScratch bool // No direct move between GP and FP register sets BigEndian bool // UseFMA bool // Use hardware FMA operation } diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go index 737b99c371..2b7185e537 100644 --- a/src/cmd/compile/internal/ssa/gen/386Ops.go +++ b/src/cmd/compile/internal/ssa/gen/386Ops.go @@ -146,14 +146,14 @@ func init() { var _386ops = []opData{ // fp ops - {name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS", commutative: true, resultInArg0: true, usesScratch: true}, // fp32 add - {name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD", commutative: true, resultInArg0: true}, // fp64 add - {name: "SUBSS", argLength: 2, reg: fp21, asm: "SUBSS", resultInArg0: true, usesScratch: true}, // fp32 sub - {name: "SUBSD", argLength: 2, reg: fp21, asm: "SUBSD", resultInArg0: true}, // fp64 sub - {name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS", commutative: true, resultInArg0: true, usesScratch: true}, // fp32 mul - {name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD", commutative: true, resultInArg0: true}, // fp64 mul - {name: "DIVSS", argLength: 2, reg: fp21, asm: "DIVSS", resultInArg0: true, usesScratch: true}, // fp32 div - {name: "DIVSD", argLength: 2, reg: fp21, asm: "DIVSD", resultInArg0: true}, // fp64 div + {name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS", commutative: true, resultInArg0: true}, // fp32 add + {name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD", commutative: true, resultInArg0: true}, // fp64 add + {name: "SUBSS", argLength: 2, reg: fp21, asm: "SUBSS", resultInArg0: true}, // fp32 sub + {name: "SUBSD", argLength: 2, reg: fp21, asm: "SUBSD", resultInArg0: true}, // fp64 sub + {name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS", commutative: true, resultInArg0: true}, // fp32 mul + {name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD", commutative: true, resultInArg0: true}, // fp64 mul + {name: "DIVSS", argLength: 2, reg: fp21, asm: "DIVSS", resultInArg0: true}, // fp32 div + {name: "DIVSD", argLength: 2, reg: fp21, asm: "DIVSD", resultInArg0: true}, // fp64 div {name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp32 load {name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // fp64 load @@ -246,8 +246,8 @@ func init() { {name: "CMPWconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPW", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, {name: "CMPBconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPB", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, - {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f32 - {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f64 + {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32 + {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64 {name: "TESTL", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0 {name: "TESTW", argLength: 2, reg: gp2flags, commutative: true, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0 @@ -341,12 +341,12 @@ func init() { {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint - {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", usesScratch: true}, // convert float64 to int32 - {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", usesScratch: true}, // convert float32 to int32 - {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", usesScratch: true}, // convert int32 to float32 - {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", usesScratch: true}, // convert int32 to float64 - {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", usesScratch: true}, // convert float64 to float32 - {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64 + {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32 + {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL"}, // convert float32 to int32 + {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS"}, // convert int32 to float32 + {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD"}, // convert int32 to float64 + {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS"}, // convert float64 to float32 + {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64 {name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true}, // exclusive or, applied to X regs for float negation. diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go index dfa146a28a..e7a4ef0629 100644 --- a/src/cmd/compile/internal/ssa/gen/main.go +++ b/src/cmd/compile/internal/ssa/gen/main.go @@ -63,7 +63,6 @@ type opData struct { nilCheck bool // this op is a nil check on arg0 faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset) faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset) - usesScratch bool // this op requires scratch memory space hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182. zeroWidth bool // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width. unsafePoint bool // this op is an unsafe point, i.e. not safe for async preemption @@ -320,9 +319,6 @@ func genOp() { log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux) } } - if v.usesScratch { - fmt.Fprintln(w, "usesScratch: true,") - } if v.hasSideEffects { fmt.Fprintln(w, "hasSideEffects: true,") } @@ -404,8 +400,6 @@ func genOp() { // generate op string method fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") - fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }") - fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }") fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }") fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }") diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index ccfed93475..e4087bd021 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -2912,7 +2912,6 @@ var opcodeTable = [...]opInfo{ argLen: 2, commutative: true, resultInArg0: true, - usesScratch: true, asm: x86.AADDSS, reg: regInfo{ inputs: []inputInfo{ @@ -2944,7 +2943,6 @@ var opcodeTable = [...]opInfo{ name: "SUBSS", argLen: 2, resultInArg0: true, - usesScratch: true, asm: x86.ASUBSS, reg: regInfo{ inputs: []inputInfo{ @@ -2976,7 +2974,6 @@ var opcodeTable = [...]opInfo{ argLen: 2, commutative: true, resultInArg0: true, - usesScratch: true, asm: x86.AMULSS, reg: regInfo{ inputs: []inputInfo{ @@ -3008,7 +3005,6 @@ var opcodeTable = [...]opInfo{ name: "DIVSS", argLen: 2, resultInArg0: true, - usesScratch: true, asm: x86.ADIVSS, reg: regInfo{ inputs: []inputInfo{ @@ -4072,10 +4068,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UCOMISS", - argLen: 2, - usesScratch: true, - asm: x86.AUCOMISS, + name: "UCOMISS", + argLen: 2, + asm: x86.AUCOMISS, reg: regInfo{ inputs: []inputInfo{ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 @@ -4084,10 +4079,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UCOMISD", - argLen: 2, - usesScratch: true, - asm: x86.AUCOMISD, + name: "UCOMISD", + argLen: 2, + asm: x86.AUCOMISD, reg: regInfo{ inputs: []inputInfo{ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 @@ -5027,10 +5021,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSD2SL", - argLen: 1, - usesScratch: true, - asm: x86.ACVTTSD2SL, + name: "CVTTSD2SL", + argLen: 1, + asm: x86.ACVTTSD2SL, reg: regInfo{ inputs: []inputInfo{ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 @@ -5041,10 +5034,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSS2SL", - argLen: 1, - usesScratch: true, - asm: x86.ACVTTSS2SL, + name: "CVTTSS2SL", + argLen: 1, + asm: x86.ACVTTSS2SL, reg: regInfo{ inputs: []inputInfo{ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 @@ -5055,10 +5047,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTSL2SS", - argLen: 1, - usesScratch: true, - asm: x86.ACVTSL2SS, + name: "CVTSL2SS", + argLen: 1, + asm: x86.ACVTSL2SS, reg: regInfo{ inputs: []inputInfo{ {0, 239}, // AX CX DX BX BP SI DI @@ -5069,10 +5060,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTSL2SD", - argLen: 1, - usesScratch: true, - asm: x86.ACVTSL2SD, + name: "CVTSL2SD", + argLen: 1, + asm: x86.ACVTSL2SD, reg: regInfo{ inputs: []inputInfo{ {0, 239}, // AX CX DX BX BP SI DI @@ -5083,10 +5073,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTSD2SS", - argLen: 1, - usesScratch: true, - asm: x86.ACVTSD2SS, + name: "CVTSD2SS", + argLen: 1, + asm: x86.ACVTSD2SS, reg: regInfo{ inputs: []inputInfo{ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 @@ -36128,7 +36117,6 @@ var opcodeTable = [...]opInfo{ func (o Op) Asm() obj.As { return opcodeTable[o].asm } func (o Op) Scale() int16 { return int16(opcodeTable[o].scale) } func (o Op) String() string { return opcodeTable[o].name } -func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch } func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect } func (o Op) IsCall() bool { return opcodeTable[o].call } func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects } diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 40f07a8d45..25b09e1f5d 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -15,7 +15,6 @@ import ( "cmd/compile/internal/ir" "cmd/compile/internal/objw" "cmd/compile/internal/ssa" - "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/obj" "cmd/internal/objabi" @@ -90,7 +89,6 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } } - scratchUsed := false for _, b := range f.Blocks { for _, v := range b.Values { if n, ok := v.Aux.(*ir.Name); ok { @@ -104,17 +102,9 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { n.SetUsed(true) } } - if !scratchUsed { - scratchUsed = v.Op.UsesScratch() - } - } } - if f.Config.NeedsFpScratch && scratchUsed { - s.scratchFpMem = typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64]) - } - sort.Sort(byStackVar(fn.Dcl)) // Reassign stack offsets of the locals that are used. diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index e13ca90d33..cfc54ae0ab 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6282,9 +6282,6 @@ type State struct { // bstart remembers where each block starts (indexed by block ID) bstart []*obj.Prog - // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8. - ScratchFpMem *ir.Name - maxarg int64 // largest frame size for arguments to calls made by the function // Map from GC safe points to liveness index, generated by @@ -6398,8 +6395,6 @@ func genssa(f *ssa.Func, pp *objw.Progs) { progToBlock[s.pp.Next] = f.Blocks[0] } - s.ScratchFpMem = e.scratchFpMem - if base.Ctxt.Flag_locationlists { if cap(f.Cache.ValueToProgAfter) < f.NumValues() { f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues()) @@ -6948,17 +6943,6 @@ func AddrAuto(a *obj.Addr, v *ssa.Value) { } } -func (s *State) AddrScratch(a *obj.Addr) { - if s.ScratchFpMem == nil { - panic("no scratch memory available; forgot to declare usesScratch for Op?") - } - a.Type = obj.TYPE_MEM - a.Name = obj.NAME_AUTO - a.Sym = s.ScratchFpMem.Linksym() - a.Reg = int16(Arch.REGSP) - a.Offset = s.ScratchFpMem.Offset_ -} - // Call returns a new CALL instruction for the SSA value v. // It uses PrepareCall to prepare the call. func (s *State) Call(v *ssa.Value) *obj.Prog { @@ -7061,12 +7045,11 @@ func fieldIdx(n *ir.SelectorExpr) int { // ssafn holds frontend information about a function that the backend is processing. // It also exports a bunch of compiler services for the ssa backend. type ssafn struct { - curfn *ir.Func - strings map[string]*obj.LSym // map from constant string to data symbols - scratchFpMem *ir.Name // temp for floating point register / memory moves on some architectures - stksize int64 // stack size for current frame - stkptrsize int64 // prefix of stack containing pointers - log bool // print ssa debug to the stdout + curfn *ir.Func + strings map[string]*obj.LSym // map from constant string to data symbols + stksize int64 // stack size for current frame + stkptrsize int64 // prefix of stack containing pointers + log bool // print ssa debug to the stdout } // StringData returns a symbol which -- GitLab From c4b771348c3e5c5372bd00254f2e796b627c13dc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 22 Feb 2021 12:56:33 -0500 Subject: [PATCH 0034/1298] runtime: fix windows/arm signal handling assembly Bug introduced in CL 288799: R12 is used but not set. Fixes windows/arm builder. Change-Id: I015a5a83cfa3bdd23da1ffb73713623764f2f817 Reviewed-on: https://go-review.googlesource.com/c/go/+/295109 Trust: Russ Cox Reviewed-by: Cherry Zhang --- src/runtime/sys_windows_arm.s | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s index cd230ccffd..4be5ce7da0 100644 --- a/src/runtime/sys_windows_arm.s +++ b/src/runtime/sys_windows_arm.s @@ -160,6 +160,11 @@ g0: BL (R7) // Call the go routine MOVW 16(R13), R4 // Fetch return value from stack + // Save system stack pointer for sigresume setup below. + // The exact value does not matter - nothing is read or written + // from this address. It just needs to be on the system stack. + MOVW R13, R12 + // switch back to original stack and g MOVW 24(R13), R13 MOVW 20(R13), g -- GitLab From 6525abddcee2886ca0095decdfe1e97de19d06f2 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 16 Jan 2021 03:09:15 +1100 Subject: [PATCH 0035/1298] cmd/internal/obj/riscv: clean up branch tests Address review comments from earlier changes, which would have previously caused unwanted conflicts. Change-Id: If2c61ffe977d721cccf276f931825b003521fda1 Reviewed-on: https://go-review.googlesource.com/c/go/+/284116 Trust: Joel Sing Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang --- .../riscv/testdata/testbranch/branch_test.go | 117 ++++++++---------- .../riscv/testdata/testbranch/branch_test.s | 28 ++--- 2 files changed, 67 insertions(+), 78 deletions(-) diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go index 279aeb2c32..3fa95222ff 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go @@ -25,84 +25,73 @@ func testBLTU(a, b int64) (r bool) func testBLTZ(a int64) (r bool) func testBNEZ(a int64) (r bool) +func testGoBGE(a, b int64) bool { return a >= b } +func testGoBGEU(a, b int64) bool { return uint64(a) >= uint64(b) } +func testGoBGT(a, b int64) bool { return a > b } +func testGoBGTU(a, b int64) bool { return uint64(a) > uint64(b) } +func testGoBLE(a, b int64) bool { return a <= b } +func testGoBLEU(a, b int64) bool { return uint64(a) <= uint64(b) } +func testGoBLT(a, b int64) bool { return a < b } +func testGoBLTZ(a, b int64) bool { return uint64(a) < uint64(b) } + func TestBranchCondition(t *testing.T) { tests := []struct { ins string a int64 b int64 fn func(a, b int64) bool + goFn func(a, b int64) bool want bool }{ - {"BGE", 0, 1, testBGE, false}, - {"BGE", 0, 0, testBGE, true}, - {"BGE", 0, -1, testBGE, true}, - {"BGE", -1, 0, testBGE, false}, - {"BGE", 1, 0, testBGE, true}, - {"BGEU", 0, 1, testBGEU, false}, - {"BGEU", 0, 0, testBGEU, true}, - {"BGEU", 0, -1, testBGEU, false}, - {"BGEU", -1, 0, testBGEU, true}, - {"BGEU", 1, 0, testBGEU, true}, - {"BGT", 0, 1, testBGT, false}, - {"BGT", 0, 0, testBGT, false}, - {"BGT", 0, -1, testBGT, true}, - {"BGT", -1, 0, testBGT, false}, - {"BGT", 1, 0, testBGT, true}, - {"BGTU", 0, 1, testBGTU, false}, - {"BGTU", 0, 0, testBGTU, false}, - {"BGTU", 0, -1, testBGTU, false}, - {"BGTU", -1, 0, testBGTU, true}, - {"BGTU", 1, 0, testBGTU, true}, - {"BLE", 0, 1, testBLE, true}, - {"BLE", 0, 0, testBLE, true}, - {"BLE", 0, -1, testBLE, false}, - {"BLE", -1, 0, testBLE, true}, - {"BLE", 1, 0, testBLE, false}, - {"BLEU", 0, 1, testBLEU, true}, - {"BLEU", 0, 0, testBLEU, true}, - {"BLEU", 0, -1, testBLEU, true}, - {"BLEU", -1, 0, testBLEU, false}, - {"BLEU", 1, 0, testBLEU, false}, - {"BLT", 0, 1, testBLT, true}, - {"BLT", 0, 0, testBLT, false}, - {"BLT", 0, -1, testBLT, false}, - {"BLT", -1, 0, testBLT, true}, - {"BLT", 1, 0, testBLT, false}, - {"BLTU", 0, 1, testBLTU, true}, - {"BLTU", 0, 0, testBLTU, false}, - {"BLTU", 0, -1, testBLTU, true}, - {"BLTU", -1, 0, testBLTU, false}, - {"BLTU", 1, 0, testBLTU, false}, + {"BGE", 0, 1, testBGE, testGoBGE, false}, + {"BGE", 0, 0, testBGE, testGoBGE, true}, + {"BGE", 0, -1, testBGE, testGoBGE, true}, + {"BGE", -1, 0, testBGE, testGoBGE, false}, + {"BGE", 1, 0, testBGE, testGoBGE, true}, + {"BGEU", 0, 1, testBGEU, testGoBGEU, false}, + {"BGEU", 0, 0, testBGEU, testGoBGEU, true}, + {"BGEU", 0, -1, testBGEU, testGoBGEU, false}, + {"BGEU", -1, 0, testBGEU, testGoBGEU, true}, + {"BGEU", 1, 0, testBGEU, testGoBGEU, true}, + {"BGT", 0, 1, testBGT, testGoBGT, false}, + {"BGT", 0, 0, testBGT, testGoBGT, false}, + {"BGT", 0, -1, testBGT, testGoBGT, true}, + {"BGT", -1, 0, testBGT, testGoBGT, false}, + {"BGT", 1, 0, testBGT, testGoBGT, true}, + {"BGTU", 0, 1, testBGTU, testGoBGTU, false}, + {"BGTU", 0, 0, testBGTU, testGoBGTU, false}, + {"BGTU", 0, -1, testBGTU, testGoBGTU, false}, + {"BGTU", -1, 0, testBGTU, testGoBGTU, true}, + {"BGTU", 1, 0, testBGTU, testGoBGTU, true}, + {"BLE", 0, 1, testBLE, testGoBLE, true}, + {"BLE", 0, 0, testBLE, testGoBLE, true}, + {"BLE", 0, -1, testBLE, testGoBLE, false}, + {"BLE", -1, 0, testBLE, testGoBLE, true}, + {"BLE", 1, 0, testBLE, testGoBLE, false}, + {"BLEU", 0, 1, testBLEU, testGoBLEU, true}, + {"BLEU", 0, 0, testBLEU, testGoBLEU, true}, + {"BLEU", 0, -1, testBLEU, testGoBLEU, true}, + {"BLEU", -1, 0, testBLEU, testGoBLEU, false}, + {"BLEU", 1, 0, testBLEU, testGoBLEU, false}, + {"BLT", 0, 1, testBLT, testGoBLT, true}, + {"BLT", 0, 0, testBLT, testGoBLT, false}, + {"BLT", 0, -1, testBLT, testGoBLT, false}, + {"BLT", -1, 0, testBLT, testGoBLT, true}, + {"BLT", 1, 0, testBLT, testGoBLT, false}, + {"BLTU", 0, 1, testBLTU, testGoBLTU, true}, + {"BLTU", 0, 0, testBLTU, testGoBLTU, false}, + {"BLTU", 0, -1, testBLTU, testGoBLTU, true}, + {"BLTU", -1, 0, testBLTU, testGoBLTU, false}, + {"BLTU", 1, 0, testBLTU, testGoBLTU, false}, } for _, test := range tests { t.Run(test.ins, func(t *testing.T) { - var fn func(a, b int64) bool - switch test.ins { - case "BGE": - fn = func(a, b int64) bool { return a >= b } - case "BGEU": - fn = func(a, b int64) bool { return uint64(a) >= uint64(b) } - case "BGT": - fn = func(a, b int64) bool { return a > b } - case "BGTU": - fn = func(a, b int64) bool { return uint64(a) > uint64(b) } - case "BLE": - fn = func(a, b int64) bool { return a <= b } - case "BLEU": - fn = func(a, b int64) bool { return uint64(a) <= uint64(b) } - case "BLT": - fn = func(a, b int64) bool { return a < b } - case "BLTU": - fn = func(a, b int64) bool { return uint64(a) < uint64(b) } - default: - t.Fatalf("Unknown instruction %q", test.ins) - } - if got := fn(test.a, test.b); got != test.want { - t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) - } if got := test.fn(test.a, test.b); got != test.want { t.Errorf("Assembly %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) } + if got := test.goFn(test.a, test.b); got != test.want { + t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) + } }) } } diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s index 8dd6f563af..cce296feb5 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s @@ -7,7 +7,7 @@ #include "textflag.h" // func testBEQZ(a int64) (r bool) -TEXT ·testBEQZ(SB),NOSPLIT,$0-0 +TEXT ·testBEQZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BEQZ X5, b @@ -17,7 +17,7 @@ b: RET // func testBGE(a, b int64) (r bool) -TEXT ·testBGE(SB),NOSPLIT,$0-0 +TEXT ·testBGE(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -28,7 +28,7 @@ b: RET // func testBGEU(a, b int64) (r bool) -TEXT ·testBGEU(SB),NOSPLIT,$0-0 +TEXT ·testBGEU(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -39,7 +39,7 @@ b: RET // func testBGEZ(a int64) (r bool) -TEXT ·testBGEZ(SB),NOSPLIT,$0-0 +TEXT ·testBGEZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BGEZ X5, b @@ -49,7 +49,7 @@ b: RET // func testBGT(a, b int64) (r bool) -TEXT ·testBGT(SB),NOSPLIT,$0-0 +TEXT ·testBGT(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -60,7 +60,7 @@ b: RET // func testBGTU(a, b int64) (r bool) -TEXT ·testBGTU(SB),NOSPLIT,$0-0 +TEXT ·testBGTU(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -71,7 +71,7 @@ b: RET // func testBGTZ(a int64) (r bool) -TEXT ·testBGTZ(SB),NOSPLIT,$0-0 +TEXT ·testBGTZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BGTZ X5, b @@ -81,7 +81,7 @@ b: RET // func testBLE(a, b int64) (r bool) -TEXT ·testBLE(SB),NOSPLIT,$0-0 +TEXT ·testBLE(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -92,7 +92,7 @@ b: RET // func testBLEU(a, b int64) (r bool) -TEXT ·testBLEU(SB),NOSPLIT,$0-0 +TEXT ·testBLEU(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -103,7 +103,7 @@ b: RET // func testBLEZ(a int64) (r bool) -TEXT ·testBLEZ(SB),NOSPLIT,$0-0 +TEXT ·testBLEZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BLEZ X5, b @@ -113,7 +113,7 @@ b: RET // func testBLT(a, b int64) (r bool) -TEXT ·testBLT(SB),NOSPLIT,$0-0 +TEXT ·testBLT(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -124,7 +124,7 @@ b: RET // func testBLTU(a, b int64) (r bool) -TEXT ·testBLTU(SB),NOSPLIT,$0-0 +TEXT ·testBLTU(SB),NOSPLIT,$0-17 MOV a+0(FP), X5 MOV b+8(FP), X6 MOV $1, X7 @@ -135,7 +135,7 @@ b: RET // func testBLTZ(a int64) (r bool) -TEXT ·testBLTZ(SB),NOSPLIT,$0-0 +TEXT ·testBLTZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BLTZ X5, b @@ -145,7 +145,7 @@ b: RET // func testBNEZ(a int64) (r bool) -TEXT ·testBNEZ(SB),NOSPLIT,$0-0 +TEXT ·testBNEZ(SB),NOSPLIT,$0-9 MOV a+0(FP), X5 MOV $1, X6 BNEZ X5, b -- GitLab From 0398a771d2fb4c4702e31bbb485924198b1b2603 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Wed, 17 Feb 2021 21:03:59 +1100 Subject: [PATCH 0036/1298] cmd/internal/obj/riscv: prevent constant loads that do not target registers Check that the target of a constant load is a register and add test coverage for this error condition. While here, rename the RISC-V testdata and tests to be consistent with other platforms. Change-Id: I7fd0bfcee8cf9df0597d72e65cd74a2d0bfd349a Reviewed-on: https://go-review.googlesource.com/c/go/+/292895 Trust: Joel Sing Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/asm/internal/asm/endtoend_test.go | 8 ++++++-- .../asm/testdata/{riscvenc.s => riscv64.s} | 0 src/cmd/asm/internal/asm/testdata/riscv64error.s | 14 ++++++++++++++ src/cmd/internal/obj/riscv/obj.go | 5 ++++- 4 files changed, 24 insertions(+), 3 deletions(-) rename src/cmd/asm/internal/asm/testdata/{riscvenc.s => riscv64.s} (100%) create mode 100644 src/cmd/asm/internal/asm/testdata/riscv64error.s diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go index a4153f3af1..92cf64575b 100644 --- a/src/cmd/asm/internal/asm/endtoend_test.go +++ b/src/cmd/asm/internal/asm/endtoend_test.go @@ -439,8 +439,12 @@ func TestPPC64EndToEnd(t *testing.T) { testEndToEnd(t, "ppc64", "ppc64") } -func TestRISCVEncoder(t *testing.T) { - testEndToEnd(t, "riscv64", "riscvenc") +func TestRISCVEndToEnd(t *testing.T) { + testEndToEnd(t, "riscv64", "riscv64") +} + +func TestRISCVErrors(t *testing.T) { + testErrors(t, "riscv64", "riscv64error") } func TestS390XEndToEnd(t *testing.T) { diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscv64.s similarity index 100% rename from src/cmd/asm/internal/asm/testdata/riscvenc.s rename to src/cmd/asm/internal/asm/testdata/riscv64.s diff --git a/src/cmd/asm/internal/asm/testdata/riscv64error.s b/src/cmd/asm/internal/asm/testdata/riscv64error.s new file mode 100644 index 0000000000..fb43e68fc1 --- /dev/null +++ b/src/cmd/asm/internal/asm/testdata/riscv64error.s @@ -0,0 +1,14 @@ +// Copyright 2021 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. + +TEXT errors(SB),$0 + MOV $0, 0(SP) // ERROR "constant load must target register" + MOV $0, 8(SP) // ERROR "constant load must target register" + MOV $1234, 0(SP) // ERROR "constant load must target register" + MOV $1234, 8(SP) // ERROR "constant load must target register" + MOVB $1, X5 // ERROR "unsupported constant load" + MOVH $1, X5 // ERROR "unsupported constant load" + MOVW $1, X5 // ERROR "unsupported constant load" + MOVF $1, X5 // ERROR "unsupported constant load" + RET diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index d104f1cfa5..391c2486ca 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -302,7 +302,10 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) { // LUI top20bits(c), R // ADD bottom12bits(c), R, R if p.As != AMOV { - ctxt.Diag("unsupported constant load at %v", p) + ctxt.Diag("%v: unsupported constant load", p) + } + if p.To.Type != obj.TYPE_REG { + ctxt.Diag("%v: constant load must target register", p) } off := p.From.Offset to := p.To -- GitLab From 08543f071520074854f280ad789cf79c5a00af7d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 16 Feb 2021 10:36:10 +0100 Subject: [PATCH 0037/1298] ios/fs: mention f.dir in (*subFS).fixErr godoc There is no dir parameter to (f *subFS).fixErr. Change-Id: I49e42bac5e102cfab0d289658d9871429cfec515 Reviewed-on: https://go-review.googlesource.com/c/go/+/292389 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/io/fs/sub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/fs/sub.go b/src/io/fs/sub.go index 64cdffe6de..d689b9e2bc 100644 --- a/src/io/fs/sub.go +++ b/src/io/fs/sub.go @@ -68,7 +68,7 @@ func (f *subFS) shorten(name string) (rel string, ok bool) { return "", false } -// fixErr shortens any reported names in PathErrors by stripping dir. +// fixErr shortens any reported names in PathErrors by stripping f.dir. func (f *subFS) fixErr(err error) error { if e, ok := err.(*PathError); ok { if short, ok := f.shorten(e.Path); ok { -- GitLab From a78b0e67211034743a1f03645312aed35e5c5ba2 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 19 Nov 2020 17:30:27 +0800 Subject: [PATCH 0038/1298] internal/poll: fix the verbose condition in splice Change-Id: I0b433ea1a78632de20ea58c48c9be0f1fb6eb083 Reviewed-on: https://go-review.googlesource.com/c/go/+/271499 Reviewed-by: Tobias Klauser Reviewed-by: Ian Lance Taylor Trust: Tobias Klauser Run-TryBot: Tobias Klauser --- src/internal/poll/splice_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go index 01baf14ed7..968bc44a5f 100644 --- a/src/internal/poll/splice_linux.go +++ b/src/internal/poll/splice_linux.go @@ -52,7 +52,7 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, // If inPipe == 0 && err == nil, src is at EOF, and the // transfer is complete. handled = handled || (err != syscall.EINVAL) - if err != nil || (inPipe == 0 && err == nil) { + if err != nil || inPipe == 0 { break } n, err = splicePump(dst, prfd, inPipe) -- GitLab From b3b65f21762fad1ec37bdb0cd47f79a53814bb16 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Tue, 8 Dec 2020 04:14:34 +1100 Subject: [PATCH 0039/1298] runtime: enable race detector on openbsd/amd64 Now that this commit[1] has landed in LLVM the .syso file can be generated for OpenBSD. With the changes to src/runtime running the sample race[2] detects the data race as expected. Based on golang/go#39464 (https://go-review.googlesource.com/c/go/+/237057) from Aaron Bieber , however the race_openbsd_amd64.syso file has been built on OpenBSD 6.4 and necessary changes added to race.bash. [1] https://github.com/llvm/llvm-project/commit/fcf6ae2f070eba73074b6ec8d8281e54d29dbeeb [2] https://golang.org/doc/articles/race_detector.html Change-Id: Ic2479ccfa91d6b2cb4585346a11d813d96450f68 Reviewed-on: https://go-review.googlesource.com/c/go/+/275892 Trust: Joel Sing Run-TryBot: Joel Sing TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/dist/test.go | 2 +- src/cmd/internal/sys/supported.go | 2 +- src/race.bash | 7 ++++++- src/runtime/race/README | 1 + src/runtime/race/race.go | 4 ++-- src/runtime/race/race_openbsd_amd64.syso | Bin 0 -> 688784 bytes 6 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 src/runtime/race/race_openbsd_amd64.syso diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index a22397aa16..0c8e2c56bc 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1633,7 +1633,7 @@ func raceDetectorSupported(goos, goarch string) bool { return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" case "darwin": return goarch == "amd64" || goarch == "arm64" - case "freebsd", "netbsd", "windows": + case "freebsd", "netbsd", "openbsd", "windows": return goarch == "amd64" default: return false diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index ef7c017bd4..291acf0862 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -15,7 +15,7 @@ func RaceDetectorSupported(goos, goarch string) bool { return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" case "darwin": return goarch == "amd64" || goarch == "arm64" - case "freebsd", "netbsd", "windows": + case "freebsd", "netbsd", "openbsd", "windows": return goarch == "amd64" default: return false diff --git a/src/race.bash b/src/race.bash index e2b96bcffe..81fb4be606 100755 --- a/src/race.bash +++ b/src/race.bash @@ -9,7 +9,7 @@ set -e function usage { - echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2 + echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, openbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2 exit 1 } @@ -34,6 +34,11 @@ case $(uname) in usage fi ;; +"OpenBSD") + if [ $(uname -m) != "amd64" ]; then + usage + fi + ;; *) usage ;; diff --git a/src/runtime/race/README b/src/runtime/race/README index 178ab94ab5..dbff42dc8a 100644 --- a/src/runtime/race/README +++ b/src/runtime/race/README @@ -12,3 +12,4 @@ race_netbsd_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 race_windows_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b. race_linux_arm64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b. race_darwin_arm64.syso built with LLVM 00da38ce2d36c07f12c287dc515d37bb7bc410e9 and Go fe70a3a0fd31441bcbb9932ecab11a6083cf2119. +race_openbsd_amd64.syso built with LLVM fcf6ae2f070eba73074b6ec8d8281e54d29dbeeb and Go 8f2db14cd35bbd674cb2988a508306de6655e425. diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go index fe50900ec8..84050e8771 100644 --- a/src/runtime/race/race.go +++ b/src/runtime/race/race.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) -// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 +//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64) +// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 race,openbsd,amd64 package race diff --git a/src/runtime/race/race_openbsd_amd64.syso b/src/runtime/race/race_openbsd_amd64.syso new file mode 100644 index 0000000000000000000000000000000000000000..9fefd87ec63d71e7f4f421aa33c9f42b41bd138e GIT binary patch literal 688784 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%0AK5_UsK`Q_PNSAfQkK;t{0 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�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%0Acw;=9OCmXVpo3vP22(+ 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 Cry3Rj literal 0 HcmV?d00001 -- GitLab From e5159b2a2f0fdd47c644d1655f5a7b57ec7dd509 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Wed, 6 Jan 2021 13:27:17 -0500 Subject: [PATCH 0040/1298] cmd/internal/dwarf: minor cleanups Remove a stale comment, demote PutInlinedFunc from public to private, and remove an unused interface originally used for sorting vars. No change in functionality. Change-Id: I5ee1ad2b10b78b158e2223c6979bab830202db95 Reviewed-on: https://go-review.googlesource.com/c/go/+/295009 Trust: Than McIntosh Run-TryBot: Than McIntosh Reviewed-by: Jeremy Faller Reviewed-by: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/internal/dwarf/dwarf.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index 8de4096f06..70d792fec6 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -318,8 +318,6 @@ const ( ) // Index into the abbrevs table below. -// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go. -// ispubtype considers >= NULLTYPE public const ( DW_ABRV_NULL = iota DW_ABRV_COMPUNIT @@ -1257,7 +1255,7 @@ func PutAbstractFunc(ctxt Context, s *FnState) error { // its corresponding 'abstract' DIE (containing location-independent // attributes such as name, type, etc). Inlined subroutine DIEs can // have other inlined subroutine DIEs as children. -func PutInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error { +func putInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error { ic := s.InlCalls.Calls[callIdx] callee := ic.AbsFunSym @@ -1268,7 +1266,7 @@ func PutInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error Uleb128put(ctxt, s.Info, int64(abbrev)) if logDwarf { - ctxt.Logf("PutInlinedFunc(caller=%v,callee=%v,abbrev=%d)\n", callersym, callee, abbrev) + ctxt.Logf("putInlinedFunc(caller=%v,callee=%v,abbrev=%d)\n", callersym, callee, abbrev) } // Abstract origin. @@ -1304,7 +1302,7 @@ func PutInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error // Children of this inline. for _, sib := range inlChildren(callIdx, &s.InlCalls) { absfn := s.InlCalls.Calls[sib].AbsFunSym - err := PutInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, absfn, sib) if err != nil { return err } @@ -1346,7 +1344,7 @@ func PutConcreteFunc(ctxt Context, s *FnState) error { // Inlined subroutines. for _, sib := range inlChildren(-1, &s.InlCalls) { absfn := s.InlCalls.Calls[sib].AbsFunSym - err := PutInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, absfn, sib) if err != nil { return err } @@ -1394,7 +1392,7 @@ func PutDefaultFunc(ctxt Context, s *FnState) error { // Inlined subroutines. for _, sib := range inlChildren(-1, &s.InlCalls) { absfn := s.InlCalls.Calls[sib].AbsFunSym - err := PutInlinedFunc(ctxt, s, absfn, sib) + err := putInlinedFunc(ctxt, s, absfn, sib) if err != nil { return err } @@ -1600,14 +1598,6 @@ func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, // Var has no children => no terminator } -// VarsByOffset attaches the methods of sort.Interface to []*Var, -// sorting in increasing StackOffset. -type VarsByOffset []*Var - -func (s VarsByOffset) Len() int { return len(s) } -func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset } -func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // byChildIndex implements sort.Interface for []*dwarf.Var by child index. type byChildIndex []*Var -- GitLab From a51daac840482d71d89742871b860a023dbdba0e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 14 Feb 2021 00:04:48 +0100 Subject: [PATCH 0041/1298] cmd/link: set SizeOfRawData rather than VirtualSize in COFF files for .bss section GCC and Clang both set the SizeOfRawData field rather than the VirtualSize field for communicating the size of the .bss section. As a consequence, LLD does not look at VirtualSize and collapses the .bss section into whatever is around it, resulting in runtime crashes. This commit changes the logic so that if the requested "file size" is 0, then the SizeOfRawData field is set rather than the VirtualSize field as the sole length marker. Fixes #44250. Fixes #39326. Updates #38755. Updates #36439. Updates #43800. Change-Id: Ied89ddaa0a717fed840238244c6e4848845aeeb6 Reviewed-on: https://go-review.googlesource.com/c/go/+/291630 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/pe.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 36c8e0da9a..46e3df5df1 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -418,14 +418,16 @@ func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection name: name, shortName: name, index: len(f.sections) + 1, - virtualSize: uint32(sectsize), virtualAddress: f.nextSectOffset, pointerToRawData: f.nextFileOffset, } f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN)) if filesize > 0 { + sect.virtualSize = uint32(sectsize) sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN)) f.nextFileOffset += sect.sizeOfRawData + } else { + sect.sizeOfRawData = uint32(sectsize) } f.sections = append(f.sections, sect) return sect -- GitLab From 811167e2c94e1480328513575cdddbc9ad9a7447 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 14 Feb 2021 14:44:14 +0100 Subject: [PATCH 0042/1298] cmd/link: do not pass -Bsymbolic for PE DLLs This is only a valid option on ELF. Binutils accepts it, but LLVM rejects it, so for Windows, it's best to just omit it. Updates #44250. Updates #39326. Updates #38755. Updates #36439. Updates #43800. Change-Id: Iffd2345d757f23dd737e63bd464cd412527077c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/291632 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/lib.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 314896824a..28713456c4 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1343,8 +1343,6 @@ func (ctxt *Link) hostlink() { if ctxt.HeadType == objabi.Hdarwin { argv = append(argv, "-dynamiclib") } else { - // ELF. - argv = append(argv, "-Wl,-Bsymbolic") if ctxt.UseRelro() { argv = append(argv, "-Wl,-z,relro") } @@ -1357,6 +1355,8 @@ func (ctxt *Link) hostlink() { // Pass -z nodelete to mark the shared library as // non-closeable: a dlclose will do nothing. argv = append(argv, "-Wl,-z,nodelete") + // Only pass Bsymbolic on non-Windows. + argv = append(argv, "-Wl,-Bsymbolic") } } case BuildModeShared: -- GitLab From 91cfbf39e45b130562bbc5b353aa041cfe315faa Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 14 Feb 2021 19:01:39 +0100 Subject: [PATCH 0043/1298] cmd/link: set .ctors COFF section to writable and aligned Without setting these flags, LLVM's LLD ignores the .ctors section when merging objects. Updates #44250. Updates #39326. Updates #38755. Updates #36439. Updates #43800. Change-Id: I8766104508f7acd832088a590ee7d68afa0d6065 Reviewed-on: https://go-review.googlesource.com/c/go/+/291633 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/pe.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 46e3df5df1..a0aba866dc 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -66,6 +66,8 @@ const ( IMAGE_SCN_MEM_WRITE = 0x80000000 IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 + IMAGE_SCN_ALIGN_4BYTES = 0x300000 + IMAGE_SCN_ALIGN_8BYTES = 0x400000 IMAGE_SCN_ALIGN_32BYTES = 0x600000 ) @@ -478,20 +480,19 @@ func (f *peFile) addInitArray(ctxt *Link) *peSection { // However, the entire Go runtime is initialized from just one function, so it is unlikely // that this will need to grow in the future. var size int + var alignment uint32 switch objabi.GOARCH { default: Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", objabi.GOARCH) - case "386": - size = 4 - case "amd64": - size = 8 - case "arm": + case "386", "arm": size = 4 - case "arm64": + alignment = IMAGE_SCN_ALIGN_4BYTES + case "amd64", "arm64": size = 8 + alignment = IMAGE_SCN_ALIGN_8BYTES } sect := f.addSection(".ctors", size, size) - sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ + sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | alignment sect.sizeOfRawData = uint32(size) ctxt.Out.SeekSet(int64(sect.pointerToRawData)) sect.checkOffset(ctxt.Out.Offset()) -- GitLab From ab331c0254d4462dde6640ec9b00fecc828f4162 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 14 Feb 2021 19:43:31 +0100 Subject: [PATCH 0044/1298] runtime/cgo: use correct lean and mean macro WIN64_LEAN_AND_MEAN is not the correct macro to use and doesn't ever exist. Change-Id: I32a5523cc0f7cc3f3a4d022071cf81f88db39aa9 Reviewed-on: https://go-review.googlesource.com/c/go/+/291634 Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- src/runtime/cgo/gcc_libinit_windows.c | 2 +- src/runtime/cgo/gcc_windows_amd64.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c index 2732248bdc..ad5038667a 100644 --- a/src/runtime/cgo/gcc_libinit_windows.c +++ b/src/runtime/cgo/gcc_libinit_windows.c @@ -4,7 +4,7 @@ // +build cgo -#define WIN64_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #include #include diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c index 25cfd086dd..9df9b9b1e4 100644 --- a/src/runtime/cgo/gcc_windows_amd64.c +++ b/src/runtime/cgo/gcc_windows_amd64.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#define WIN64_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #include #include #include -- GitLab From 55d7dcc3cd4b3ee6bca0ab7101866d785776ff51 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 10 Nov 2020 21:02:18 +0800 Subject: [PATCH 0045/1298] runtime: optimize the memory padding in p struct Since allocation for p struct will be rounded up to the next size class, the two relevant adjacent classes for this case are 9728 bytes and 10240 bytes. A p is currently 10072 bytes, so it gets rounded up to 10240 bytes when we allocate one, So the pad in p struct is unnecessary, eliminate it and add comments for warning the false sharing. Change-Id: Iae8b32931d1beddbfff1f58044d8401703da6407 Reviewed-on: https://go-review.googlesource.com/c/go/+/268759 Reviewed-by: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Trust: Ian Lance Taylor --- src/runtime/runtime2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 5bd283d12f..f5318e6f11 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -5,7 +5,6 @@ package runtime import ( - "internal/cpu" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -713,7 +712,8 @@ type p struct { // scheduler ASAP (regardless of what G is running on it). preempt bool - pad cpu.CacheLinePad + // Padding is no longer needed. False sharing is now not a worry because p is large enough + // that its size class is an integer multiple of the cache line size (for any of our architectures). } type schedt struct { -- GitLab From 5e94fe931613111c170e4798131790b3db2bbe90 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Tue, 23 Feb 2021 15:05:33 +0100 Subject: [PATCH 0046/1298] go/build/constraint: fix splitPlusBuild func doc comment Noticed while reading the code of the new package; likely a copy-paste from the splitGoBuild function, which is almost identical. Change-Id: I869272123708d25d237a4f0445f8e853865747f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/295469 Trust: Alberto Donizetti Reviewed-by: Russ Cox --- src/go/build/constraint/expr.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 3b278702f8..1ef707ceac 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -355,8 +355,8 @@ func IsPlusBuild(line string) bool { return ok } -// splitGoBuild splits apart the leading //go:build prefix in line from the build expression itself. -// It returns "", false if the input is not a //go:build line or if the input contains multiple lines. +// splitPlusBuild splits apart the leading // +build prefix in line from the build expression itself. +// It returns "", false if the input is not a // +build line or if the input contains multiple lines. func splitPlusBuild(line string) (expr string, ok bool) { // A single trailing newline is OK; otherwise multiple lines are not. if len(line) > 0 && line[len(line)-1] == '\n' { -- GitLab From c7f596f919d779dc01a60f876cbd9d8cc2cd70b2 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sat, 21 Nov 2020 15:27:00 +0800 Subject: [PATCH 0047/1298] cmd/go: resolve TODO by replacing InDir() function Change-Id: Idf886bbc4e66c9ee2a41c90034075301e0a21a58 Reviewed-on: https://go-review.googlesource.com/c/go/+/271909 Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Trust: Jay Conrod --- src/cmd/go/internal/search/search.go | 1 - src/cmd/go/internal/test/test.go | 17 +++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go index 18738cf59e..faf3a321dd 100644 --- a/src/cmd/go/internal/search/search.go +++ b/src/cmd/go/internal/search/search.go @@ -571,7 +571,6 @@ func IsRelativePath(pattern string) bool { // If so, InDir returns an equivalent path relative to dir. // If not, InDir returns an empty string. // InDir makes some effort to succeed even in the presence of symbolic links. -// TODO(rsc): Replace internal/test.inDir with a call to this function for Go 1.12. func InDir(path, dir string) string { if rel := inDirLex(path, dir); rel != "" { return rel diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 7fc9e8fbdc..ea9dfbe4e8 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -29,6 +29,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/lockedfile" + "cmd/go/internal/search" "cmd/go/internal/str" "cmd/go/internal/trace" "cmd/go/internal/work" @@ -1499,7 +1500,7 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) if !filepath.IsAbs(name) { name = filepath.Join(pwd, name) } - if a.Package.Root == "" || !inDir(name, a.Package.Root) { + if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" { // Do not recheck files outside the module, GOPATH, or GOROOT root. break } @@ -1508,7 +1509,7 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) if !filepath.IsAbs(name) { name = filepath.Join(pwd, name) } - if a.Package.Root == "" || !inDir(name, a.Package.Root) { + if a.Package.Root == "" || search.InDir(name, a.Package.Root) == "" { // Do not recheck files outside the module, GOPATH, or GOROOT root. break } @@ -1526,18 +1527,6 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) return sum, nil } -func inDir(path, dir string) bool { - if str.HasFilePathPrefix(path, dir) { - return true - } - xpath, err1 := filepath.EvalSymlinks(path) - xdir, err2 := filepath.EvalSymlinks(dir) - if err1 == nil && err2 == nil && str.HasFilePathPrefix(xpath, xdir) { - return true - } - return false -} - func hashGetenv(name string) cache.ActionID { h := cache.NewHash("getenv") v, ok := os.LookupEnv(name) -- GitLab From bf5fa2d19887bd86891447761b45041e500c2a07 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 22 Feb 2021 19:45:21 -0500 Subject: [PATCH 0048/1298] cmd/compile: guard special register usage with GOEXPERIMENT=regabi Previously, some special register uses are only guarded with ABI wrapper generation (-abiwrap). This CL makes it also guarded with the GOEXPERIMENT. This way we can enable only the wrapper generation without fully the new ABI, for benchmarking purposes. Change-Id: I90fc34afa1dc17c9c73e7b06e940e79e4c4bf7f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/295289 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/compile/internal/amd64/ssa.go | 13 +++++++------ src/cmd/compile/internal/ssa/gen/AMD64.rules | 2 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 4938e4b0e3..6944ba7ce7 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -16,6 +16,7 @@ import ( "cmd/compile/internal/types" "cmd/internal/obj" "cmd/internal/obj/x86" + "cmd/internal/objabi" ) // markMoves marks any MOVXconst ops that need to avoid clobbering flags. @@ -845,7 +846,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { if s.ABI != obj.ABIInternal { v.Fatalf("MOVOstorezero can be only used in ABIInternal functions") } - if !base.Flag.ABIWrap { + if !(objabi.Regabi_enabled == 1 && base.Flag.ABIWrap) { // zeroing X15 manually if wrappers are not used opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) } @@ -945,7 +946,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { if s.ABI != obj.ABIInternal { v.Fatalf("MOVOconst can be only used in ABIInternal functions") } - if !base.Flag.ABIWrap { + if !(objabi.Regabi_enabled == 1 && base.Flag.ABIWrap) { // zeroing X15 manually if wrappers are not used opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) } @@ -1017,20 +1018,20 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // Closure pointer is DX. ssagen.CheckLoweredGetClosurePtr(v) case ssa.OpAMD64LoweredGetG: - if base.Flag.ABIWrap { + if objabi.Regabi_enabled == 1 && base.Flag.ABIWrap { v.Fatalf("LoweredGetG should not appear in new ABI") } r := v.Reg() getgFromTLS(s, r) case ssa.OpAMD64CALLstatic: - if s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal { + if objabi.Regabi_enabled == 1 && s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) // set G register from TLS getgFromTLS(s, x86.REG_R14) } s.Call(v) - if s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 { + if objabi.Regabi_enabled == 1 && s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 { // zeroing X15 when entering ABIInternal from ABI0 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) // set G register from TLS @@ -1333,7 +1334,7 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { case ssa.BlockRet: s.Prog(obj.ARET) case ssa.BlockRetJmp: - if s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal { + if objabi.Regabi_enabled == 1 && s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal { // zeroing X15 when entering ABIInternal from ABI0 opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15) // set G register from TLS diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 3c75bcfa05..acd2170ea7 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -459,7 +459,7 @@ (IsInBounds idx len) => (SETB (CMPQ idx len)) (IsSliceInBounds idx len) => (SETBE (CMPQ idx len)) (NilCheck ...) => (LoweredNilCheck ...) -(GetG mem) && !base.Flag.ABIWrap => (LoweredGetG mem) // only lower in old ABI. in new ABI we have a G register. +(GetG mem) && !(objabi.Regabi_enabled == 1 && base.Flag.ABIWrap) => (LoweredGetG mem) // only lower in old ABI. in new ABI we have a G register. (GetClosurePtr ...) => (LoweredGetClosurePtr ...) (GetCallerPC ...) => (LoweredGetCallerPC ...) (GetCallerSP ...) => (LoweredGetCallerSP ...) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 03498c719c..4074d37d35 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -4,6 +4,7 @@ package ssa import "math" +import "cmd/internal/objabi" import "cmd/compile/internal/base" import "cmd/compile/internal/types" @@ -30129,11 +30130,11 @@ func rewriteValueAMD64_OpFloor(v *Value) bool { func rewriteValueAMD64_OpGetG(v *Value) bool { v_0 := v.Args[0] // match: (GetG mem) - // cond: !base.Flag.ABIWrap + // cond: !(objabi.Regabi_enabled == 1 && base.Flag.ABIWrap) // result: (LoweredGetG mem) for { mem := v_0 - if !(!base.Flag.ABIWrap) { + if !(!(objabi.Regabi_enabled == 1 && base.Flag.ABIWrap)) { break } v.reset(OpAMD64LoweredGetG) -- GitLab From f1562c761014111ce359b14016718ddabd24c2f2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 15 Feb 2021 20:20:15 +0100 Subject: [PATCH 0049/1298] cmd/go: recognize DLL magic from llvm binaries When using LLD with c-shared, the magic in the output DLL is slightly different than for EXEs. Change-Id: Icc5f34f7bb61f11a9d75494236b7797cc1988b40 Reviewed-on: https://go-review.googlesource.com/c/go/+/291638 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/go/internal/work/exec.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 422e83c224..d957fa1fcd 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1841,6 +1841,7 @@ var objectMagic = [][]byte{ {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc + {0x4d, 0x5a, 0x78, 0x00, 0x01, 0x00}, // PE (Windows) as generated by llvm for dll {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm -- GitLab From 42cd40ee74050391e4714eefa8aeb0242b93b0f5 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 12 Feb 2021 15:55:25 -0800 Subject: [PATCH 0050/1298] cmd/compile: improve bit test code Some bit test instruction generation stopped triggering after the change to addressing modes. I suspect this was just because ANDQload was being generated before the rewrite rules could discover the BTQ. Fix that by decomposing the ANDQload when it is surrounded by a TESTQ (thus re-enabling the BTQ rules). Fixes #44228 Change-Id: I489b4a5a7eb01c65fc8db0753f8cec54097cadb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/291749 Trust: Keith Randall Trust: Josh Bleecher Snyder Run-TryBot: Keith Randall Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/gen/AMD64.rules | 5 ++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 54 ++++++++++++++++++++ test/codegen/bits.go | 9 ++++ 3 files changed, 68 insertions(+) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index acd2170ea7..01a8a16456 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -2191,6 +2191,11 @@ && clobber(l) => @l.Block (CMP(Q|L|W|B)constload {sym} [makeValAndOff64(0, int64(off))] ptr mem) +// Convert ANDload to MOVload when we can do the AND in a containing TEST op. +// Only do when it's within the same block, so we don't have flags live across basic block boundaries. +// See issue 44228. +(TEST(Q|L) a:(AND(Q|L)load [off] {sym} x ptr mem) a) && a.Uses == 2 && a.Block == v.Block && clobber(a) => (TEST(Q|L) (MOV(Q|L)load [off] {sym} ptr mem) x) + (MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read8(sym, int64(off)))]) (MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVLload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 4074d37d35..5fb6c303fd 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -27141,6 +27141,33 @@ func rewriteValueAMD64_OpAMD64TESTL(v *Value) bool { } break } + // match: (TESTL a:(ANDLload [off] {sym} x ptr mem) a) + // cond: a.Uses == 2 && a.Block == v.Block && clobber(a) + // result: (TESTL (MOVLload [off] {sym} ptr mem) x) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + a := v_0 + if a.Op != OpAMD64ANDLload { + continue + } + off := auxIntToInt32(a.AuxInt) + sym := auxToSym(a.Aux) + mem := a.Args[2] + x := a.Args[0] + ptr := a.Args[1] + if a != v_1 || !(a.Uses == 2 && a.Block == v.Block && clobber(a)) { + continue + } + v.reset(OpAMD64TESTL) + v0 := b.NewValue0(a.Pos, OpAMD64MOVLload, a.Type) + v0.AuxInt = int32ToAuxInt(off) + v0.Aux = symToAux(sym) + v0.AddArg2(ptr, mem) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValueAMD64_OpAMD64TESTLconst(v *Value) bool { @@ -27246,6 +27273,33 @@ func rewriteValueAMD64_OpAMD64TESTQ(v *Value) bool { } break } + // match: (TESTQ a:(ANDQload [off] {sym} x ptr mem) a) + // cond: a.Uses == 2 && a.Block == v.Block && clobber(a) + // result: (TESTQ (MOVQload [off] {sym} ptr mem) x) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + a := v_0 + if a.Op != OpAMD64ANDQload { + continue + } + off := auxIntToInt32(a.AuxInt) + sym := auxToSym(a.Aux) + mem := a.Args[2] + x := a.Args[0] + ptr := a.Args[1] + if a != v_1 || !(a.Uses == 2 && a.Block == v.Block && clobber(a)) { + continue + } + v.reset(OpAMD64TESTQ) + v0 := b.NewValue0(a.Pos, OpAMD64MOVQload, a.Type) + v0.AuxInt = int32ToAuxInt(off) + v0.Aux = symToAux(sym) + v0.AddArg2(ptr, mem) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValueAMD64_OpAMD64TESTQconst(v *Value) bool { diff --git a/test/codegen/bits.go b/test/codegen/bits.go index 4508eba487..806dad13c8 100644 --- a/test/codegen/bits.go +++ b/test/codegen/bits.go @@ -352,3 +352,12 @@ func cont0Mask64U(x uint64) uint64 { // s390x:"RISBGZ\t[$]48, [$]15, [$]0," return x & 0xffff00000000ffff } + +func issue44228a(a []int64, i int) bool { + // amd64: "BTQ", -"SHL" + return a[i>>6]&(1<<(i&63)) != 0 +} +func issue44228b(a []int32, i int) bool { + // amd64: "BTL", -"SHL" + return a[i>>5]&(1<<(i&31)) != 0 +} -- GitLab From 74cac8d47937af01bd9653df8d601b08843d3808 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 7 Oct 2020 09:44:16 -0400 Subject: [PATCH 0051/1298] cmd/compile: add AMD64 parameter register defs, Arg ops, plumb to ssa.Config This is partial plumbing recycled from the original register abi test work; these are the parts that translate easily. Some other bits are deferred till later when they are ready to be used. For #40724. Change-Id: Ica8c55a4526793446189725a2bc3839124feb38f Reviewed-on: https://go-review.googlesource.com/c/go/+/260539 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/config.go | 56 ++++++++++------- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 25 ++++---- .../compile/internal/ssa/gen/genericOps.go | 6 ++ src/cmd/compile/internal/ssa/gen/main.go | 62 ++++++++++++++----- src/cmd/compile/internal/ssa/op.go | 4 ++ src/cmd/compile/internal/ssa/opGen.go | 36 +++++++++++ src/runtime/stack.go | 2 +- 7 files changed, 141 insertions(+), 50 deletions(-) diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index f3a3a88a66..07508d6e83 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -5,6 +5,7 @@ package ssa import ( + "cmd/compile/internal/abi" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" @@ -21,29 +22,33 @@ type Config struct { PtrSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize RegSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.RegSize Types Types - lowerBlock blockRewriter // lowering function - lowerValue valueRewriter // lowering function - splitLoad valueRewriter // function for splitting merged load ops; only used on some architectures - registers []Register // machine registers - gpRegMask regMask // general purpose integer register mask - fpRegMask regMask // floating point register mask - fp32RegMask regMask // floating point register mask - fp64RegMask regMask // floating point register mask - specialRegMask regMask // special register mask - GCRegMap []*Register // garbage collector register map, by GC register index - FPReg int8 // register number of frame pointer, -1 if not used - LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used - hasGReg bool // has hardware g register - ctxt *obj.Link // Generic arch information - optimize bool // Do optimization - noDuffDevice bool // Don't use Duff's device - useSSE bool // Use SSE for non-float operations - useAvg bool // Use optimizations that need Avg* operations - useHmul bool // Use optimizations that need Hmul* operations - SoftFloat bool // - Race bool // race detector enabled - BigEndian bool // - UseFMA bool // Use hardware FMA operation + lowerBlock blockRewriter // lowering function + lowerValue valueRewriter // lowering function + splitLoad valueRewriter // function for splitting merged load ops; only used on some architectures + registers []Register // machine registers + gpRegMask regMask // general purpose integer register mask + fpRegMask regMask // floating point register mask + fp32RegMask regMask // floating point register mask + fp64RegMask regMask // floating point register mask + specialRegMask regMask // special register mask + intParamRegs []int8 // register numbers of integer param (in/out) registers + floatParamRegs []int8 // register numbers of floating param (in/out) registers + ABI1 *abi.ABIConfig // "ABIInternal" under development // TODO change comment when this becomes current + ABI0 *abi.ABIConfig + GCRegMap []*Register // garbage collector register map, by GC register index + FPReg int8 // register number of frame pointer, -1 if not used + LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used + hasGReg bool // has hardware g register + ctxt *obj.Link // Generic arch information + optimize bool // Do optimization + noDuffDevice bool // Don't use Duff's device + useSSE bool // Use SSE for non-float operations + useAvg bool // Use optimizations that need Avg* operations + useHmul bool // Use optimizations that need Hmul* operations + SoftFloat bool // + Race bool // race detector enabled + BigEndian bool // + UseFMA bool // Use hardware FMA operation } type ( @@ -195,6 +200,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.gpRegMask = gpRegMaskAMD64 c.fpRegMask = fpRegMaskAMD64 c.specialRegMask = specialRegMaskAMD64 + c.intParamRegs = paramIntRegAMD64 + c.floatParamRegs = paramFloatRegAMD64 c.FPReg = framepointerRegAMD64 c.LinkReg = linkRegAMD64 c.hasGReg = base.Flag.ABIWrap @@ -326,6 +333,9 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.useSSE = true c.UseFMA = true + c.ABI0 = abi.NewABIConfig(0, 0) + c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs)) + // On Plan 9, floating point operations are not allowed in note handler. if objabi.GOOS == "plan9" { // Don't use FMA on Plan 9 diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 043162e544..96475672a8 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main @@ -929,16 +930,18 @@ func init() { } archs = append(archs, arch{ - name: "AMD64", - pkg: "cmd/internal/obj/x86", - genfile: "../../amd64/ssa.go", - ops: AMD64ops, - blocks: AMD64blocks, - regnames: regNamesAMD64, - gpregmask: gp, - fpregmask: fp, - specialregmask: x15, - framepointerreg: int8(num["BP"]), - linkreg: -1, // not used + name: "AMD64", + pkg: "cmd/internal/obj/x86", + genfile: "../../amd64/ssa.go", + ops: AMD64ops, + blocks: AMD64blocks, + regnames: regNamesAMD64, + ParamIntRegNames: "AX BX CX DI SI R8 R9 R10 R11", + ParamFloatRegNames: "X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14", + gpregmask: gp, + fpregmask: fp, + specialregmask: x15, + framepointerreg: int8(num["BP"]), + linkreg: -1, // not used }) } diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 8cfda35c22..23a2d74b14 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore package main @@ -332,6 +333,11 @@ var genericOps = []opData{ {name: "InitMem", zeroWidth: true}, // memory input to the function. {name: "Arg", aux: "SymOff", symEffect: "Read", zeroWidth: true}, // argument to the function. aux=GCNode of arg, off = offset in that arg. + // Like Arg, these are generic ops that survive lowering. AuxInt is a register index, and the actual output register for each index is defined by the architecture. + // AuxInt = integer argument index (not a register number). ABI-specified spill loc obtained from function + {name: "ArgIntReg", aux: "Int8", zeroWidth: true}, // argument to the function in an int reg. + {name: "ArgFloatReg", aux: "Int8", zeroWidth: true}, // argument to the function in a float reg. + // The address of a variable. arg0 is the base pointer. // If the variable is a global, the base pointer will be SB and // the Aux field will be a *obj.LSym. diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go index e7a4ef0629..f5385389c3 100644 --- a/src/cmd/compile/internal/ssa/gen/main.go +++ b/src/cmd/compile/internal/ssa/gen/main.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build ignore // +build ignore // The gen command generates Go code (in the parent directory) for all @@ -30,21 +31,23 @@ import ( // apart from type names, and avoid awkward func parameters like "arch arch". type arch struct { - name string - pkg string // obj package to import for this arch. - genfile string // source file containing opcode code generation. - ops []opData - blocks []blockData - regnames []string - gpregmask regMask - fpregmask regMask - fp32regmask regMask - fp64regmask regMask - specialregmask regMask - framepointerreg int8 - linkreg int8 - generic bool - imports []string + name string + pkg string // obj package to import for this arch. + genfile string // source file containing opcode code generation. + ops []opData + blocks []blockData + regnames []string + ParamIntRegNames string + ParamFloatRegNames string + gpregmask regMask + fpregmask regMask + fp32regmask regMask + fp64regmask regMask + specialregmask regMask + framepointerreg int8 + linkreg int8 + generic bool + imports []string } type opData struct { @@ -412,7 +415,9 @@ func genOp() { } fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) var gcRegN int + num := map[string]int8{} for i, r := range a.regnames { + num[r] = int8(i) pkg := a.pkg[len("cmd/internal/obj/"):] var objname string // name in cmd/internal/obj/$ARCH switch r { @@ -435,11 +440,38 @@ func genOp() { } fmt.Fprintf(w, " {%d, %s, %d, \"%s\"},\n", i, objname, gcRegIdx, r) } + parameterRegisterList := func(paramNamesString string) []int8 { + paramNamesString = strings.TrimSpace(paramNamesString) + if paramNamesString == "" { + return nil + } + paramNames := strings.Split(paramNamesString, " ") + var paramRegs []int8 + for _, regName := range paramNames { + if regName == "" { + // forgive extra spaces + continue + } + if regNum, ok := num[regName]; ok { + paramRegs = append(paramRegs, regNum) + delete(num, regName) + } else { + log.Fatalf("parameter register %s for architecture %s not a register name (or repeated in parameter list)", regName, a.name) + } + } + return paramRegs + } + + paramIntRegs := parameterRegisterList(a.ParamIntRegNames) + paramFloatRegs := parameterRegisterList(a.ParamFloatRegNames) + if gcRegN > 32 { // Won't fit in a uint32 mask. log.Fatalf("too many GC registers (%d > 32) on %s", gcRegN, a.name) } fmt.Fprintln(w, "}") + fmt.Fprintf(w, "var paramIntReg%s = %#v\n", a.name, paramIntRegs) + fmt.Fprintf(w, "var paramFloatReg%s = %#v\n", a.name, paramFloatRegs) fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask) fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask) if a.fp32regmask != 0 { diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index f41d014d41..cf0d2affc7 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -79,6 +79,7 @@ type AuxCall struct { Fn *obj.LSym args []Param // Includes receiver for method calls. Does NOT include hidden closure pointer. results []Param + reg *regInfo // regInfo for this call // TODO for now nil means ignore } // ResultForOffset returns the index of the result at a particular offset among the results @@ -186,16 +187,19 @@ func (a *AuxCall) String() string { // StaticAuxCall returns an AuxCall for a static call. func StaticAuxCall(sym *obj.LSym, args []Param, results []Param) *AuxCall { + // TODO Create regInfo for AuxCall return &AuxCall{Fn: sym, args: args, results: results} } // InterfaceAuxCall returns an AuxCall for an interface call. func InterfaceAuxCall(args []Param, results []Param) *AuxCall { + // TODO Create regInfo for AuxCall return &AuxCall{Fn: nil, args: args, results: results} } // ClosureAuxCall returns an AuxCall for a closure call. func ClosureAuxCall(args []Param, results []Param) *AuxCall { + // TODO Create regInfo for AuxCall return &AuxCall{Fn: nil, args: args, results: results} } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index e4087bd021..ba170968ae 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -2747,6 +2747,8 @@ const ( OpConstSlice OpInitMem OpArg + OpArgIntReg + OpArgFloatReg OpAddr OpLocalAddr OpSP @@ -35253,6 +35255,20 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, generic: true, }, + { + name: "ArgIntReg", + auxType: auxInt8, + argLen: 0, + zeroWidth: true, + generic: true, + }, + { + name: "ArgFloatReg", + auxType: auxInt8, + argLen: 0, + zeroWidth: true, + generic: true, + }, { name: "Addr", auxType: auxSym, @@ -36141,6 +36157,8 @@ var registers386 = [...]Register{ {15, x86.REG_X7, -1, "X7"}, {16, 0, -1, "SB"}, } +var paramIntReg386 = []int8(nil) +var paramFloatReg386 = []int8(nil) var gpRegMask386 = regMask(239) var fpRegMask386 = regMask(65280) var specialRegMask386 = regMask(0) @@ -36181,6 +36199,8 @@ var registersAMD64 = [...]Register{ {31, x86.REG_X15, -1, "X15"}, {32, 0, -1, "SB"}, } +var paramIntRegAMD64 = []int8{0, 3, 1, 7, 6, 8, 9, 10, 11} +var paramFloatRegAMD64 = []int8{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30} var gpRegMaskAMD64 = regMask(49135) var fpRegMaskAMD64 = regMask(2147418112) var specialRegMaskAMD64 = regMask(2147483648) @@ -36221,6 +36241,8 @@ var registersARM = [...]Register{ {31, arm.REG_F15, -1, "F15"}, {32, 0, -1, "SB"}, } +var paramIntRegARM = []int8(nil) +var paramFloatRegARM = []int8(nil) var gpRegMaskARM = regMask(21503) var fpRegMaskARM = regMask(4294901760) var specialRegMaskARM = regMask(0) @@ -36292,6 +36314,8 @@ var registersARM64 = [...]Register{ {62, arm64.REG_F31, -1, "F31"}, {63, 0, -1, "SB"}, } +var paramIntRegARM64 = []int8(nil) +var paramFloatRegARM64 = []int8(nil) var gpRegMaskARM64 = regMask(670826495) var fpRegMaskARM64 = regMask(9223372034707292160) var specialRegMaskARM64 = regMask(0) @@ -36347,6 +36371,8 @@ var registersMIPS = [...]Register{ {46, mips.REG_LO, -1, "LO"}, {47, 0, -1, "SB"}, } +var paramIntRegMIPS = []int8(nil) +var paramFloatRegMIPS = []int8(nil) var gpRegMaskMIPS = regMask(335544318) var fpRegMaskMIPS = regMask(35183835217920) var specialRegMaskMIPS = regMask(105553116266496) @@ -36417,6 +36443,8 @@ var registersMIPS64 = [...]Register{ {61, mips.REG_LO, -1, "LO"}, {62, 0, -1, "SB"}, } +var paramIntRegMIPS64 = []int8(nil) +var paramFloatRegMIPS64 = []int8(nil) var gpRegMaskMIPS64 = regMask(167772158) var fpRegMaskMIPS64 = regMask(1152921504338411520) var specialRegMaskMIPS64 = regMask(3458764513820540928) @@ -36488,6 +36516,8 @@ var registersPPC64 = [...]Register{ {62, ppc64.REG_F30, -1, "F30"}, {63, ppc64.REG_F31, -1, "F31"}, } +var paramIntRegPPC64 = []int8(nil) +var paramFloatRegPPC64 = []int8(nil) var gpRegMaskPPC64 = regMask(1073733624) var fpRegMaskPPC64 = regMask(576460743713488896) var specialRegMaskPPC64 = regMask(0) @@ -36559,6 +36589,8 @@ var registersRISCV64 = [...]Register{ {62, riscv.REG_F31, -1, "F31"}, {63, 0, -1, "SB"}, } +var paramIntRegRISCV64 = []int8(nil) +var paramFloatRegRISCV64 = []int8(nil) var gpRegMaskRISCV64 = regMask(1006632948) var fpRegMaskRISCV64 = regMask(9223372034707292160) var specialRegMaskRISCV64 = regMask(0) @@ -36599,6 +36631,8 @@ var registersS390X = [...]Register{ {31, s390x.REG_F15, -1, "F15"}, {32, 0, -1, "SB"}, } +var paramIntRegS390X = []int8(nil) +var paramFloatRegS390X = []int8(nil) var gpRegMaskS390X = regMask(23551) var fpRegMaskS390X = regMask(4294901760) var specialRegMaskS390X = regMask(0) @@ -36657,6 +36691,8 @@ var registersWasm = [...]Register{ {49, wasm.REGG, -1, "g"}, {50, 0, -1, "SB"}, } +var paramIntRegWasm = []int8(nil) +var paramFloatRegWasm = []int8(nil) var gpRegMaskWasm = regMask(65535) var fpRegMaskWasm = regMask(281474976645120) var fp32RegMaskWasm = regMask(4294901760) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index d971e5e26f..c572f7296f 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -112,7 +112,7 @@ const ( stackDebug = 0 stackFromSystem = 0 // allocate stacks from system memory instead of the heap stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free - stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy + stackPoisonCopy = 1 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy stackNoCache = 0 // disable per-P small stack caches // check the BP links during traceback. -- GitLab From 080119799bb9cbace0d20bcc671497a53e3ec14e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 23 Feb 2021 11:38:24 -0500 Subject: [PATCH 0052/1298] runtime: fix usleep on windows/arm Changed calling convention to pre-multiply the argument by -100, and then deleted the * 100 but not the negation in the windows/arm assembly. Delete the negation. Fixes the current all.bash breakage on windows/arm builder. (Maybe that will uncover more.) Change-Id: I13006a44866ecc007586deb180a49c038d70aa99 Reviewed-on: https://go-review.googlesource.com/c/go/+/295529 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/runtime/sys_windows_arm.s | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s index 4be5ce7da0..9a5d9b1dd4 100644 --- a/src/runtime/sys_windows_arm.s +++ b/src/runtime/sys_windows_arm.s @@ -375,12 +375,11 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0 // duration (in -100ns units) is in dt+0(FP). // g may be nil. TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0-4 - MOVW dt+0(FP), R0 + MOVW dt+0(FP), R3 MOVM.DB.W [R4, R14], (R13) // push {r4, lr} MOVW R13, R4 // Save SP SUB $8, R13 // R13 = R13 - 8 BIC $0x7, R13 // Align SP for ABI - RSB $0, R0, R3 // R3 = -R0 MOVW $0, R1 // R1 = FALSE (alertable) MOVW $-1, R0 // R0 = handle MOVW R13, R2 // R2 = pTime -- GitLab From c584f42dcf43351e4cd1e5df22a063f020c00777 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 30 Nov 2020 23:47:27 +1100 Subject: [PATCH 0053/1298] cmd/compile: change riscv64 Eq32/Neq32 to zero extend before subtraction As done with other equality tests, zero extend before subtraction rather than after (or in this case, at the same time). While at face value this appears to require more instructions, in reality it allows for most sign extensions to be completely eliminated due to correctly typed loads. Existing optimisations (such as subtraction of zero) then become more effective. This removes more than 10,000 instructions from the Go binary and in particular, a writeBarrier check only requires three instructions (AUIPC, LWU, BNEZ) instead of the current four (AUIPC, LWU, NEGW, BNEZ). Change-Id: I7afdc1921c4916ddbd414c3b3f5c2089107ec016 Reviewed-on: https://go-review.googlesource.com/c/go/+/274066 Trust: Joel Sing Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang --- .../compile/internal/ssa/gen/RISCV64.rules | 4 ++-- .../compile/internal/ssa/rewriteRISCV64.go | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules index 4380a5efef..15361fd37a 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules @@ -251,7 +251,7 @@ (EqPtr x y) => (SEQZ (SUB x y)) (Eq64 x y) => (SEQZ (SUB x y)) -(Eq32 x y) => (SEQZ (SUBW x y)) +(Eq32 x y) => (SEQZ (SUB (ZeroExt32to64 x) (ZeroExt32to64 y))) (Eq16 x y) => (SEQZ (SUB (ZeroExt16to64 x) (ZeroExt16to64 y))) (Eq8 x y) => (SEQZ (SUB (ZeroExt8to64 x) (ZeroExt8to64 y))) (Eq64F ...) => (FEQD ...) @@ -259,7 +259,7 @@ (NeqPtr x y) => (SNEZ (SUB x y)) (Neq64 x y) => (SNEZ (SUB x y)) -(Neq32 x y) => (SNEZ (SUBW x y)) +(Neq32 x y) => (SNEZ (SUB (ZeroExt32to64 x) (ZeroExt32to64 y))) (Neq16 x y) => (SNEZ (SUB (ZeroExt16to64 x) (ZeroExt16to64 y))) (Neq8 x y) => (SNEZ (SUB (ZeroExt8to64 x) (ZeroExt8to64 y))) (Neq64F ...) => (FNED ...) diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index fb507b65c4..1abdf1aa06 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -890,14 +890,19 @@ func rewriteValueRISCV64_OpEq32(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + typ := &b.Func.Config.Types // match: (Eq32 x y) - // result: (SEQZ (SUBW x y)) + // result: (SEQZ (SUB (ZeroExt32to64 x) (ZeroExt32to64 y))) for { x := v_0 y := v_1 v.reset(OpRISCV64SEQZ) - v0 := b.NewValue0(v.Pos, OpRISCV64SUBW, x.Type) - v0.AddArg2(x, y) + v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type) + v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64) + v1.AddArg(x) + v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64) + v2.AddArg(y) + v0.AddArg2(v1, v2) v.AddArg(v0) return true } @@ -2466,14 +2471,19 @@ func rewriteValueRISCV64_OpNeq32(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block + typ := &b.Func.Config.Types // match: (Neq32 x y) - // result: (SNEZ (SUBW x y)) + // result: (SNEZ (SUB (ZeroExt32to64 x) (ZeroExt32to64 y))) for { x := v_0 y := v_1 v.reset(OpRISCV64SNEZ) - v0 := b.NewValue0(v.Pos, OpRISCV64SUBW, x.Type) - v0.AddArg2(x, y) + v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type) + v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64) + v1.AddArg(x) + v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64) + v2.AddArg(y) + v0.AddArg2(v1, v2) v.AddArg(v0) return true } -- GitLab From a671e33c6daded6639e0cd97b4791c4468475e71 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 12 Nov 2020 17:42:58 -0500 Subject: [PATCH 0054/1298] all: use more precise build tags s/!gccgo/gc/ in files which use gc-syntax assembly. Change-Id: Ifdadb62edd1210ebc70e7cd415648b752afaf067 Reviewed-on: https://go-review.googlesource.com/c/go/+/269957 Reviewed-by: Than McIntosh Trust: David Chase Trust: Matthew Dempsky --- misc/cgo/test/testdata/issue9400/asm_386.s | 2 +- misc/cgo/test/testdata/issue9400/asm_amd64x.s | 2 +- misc/cgo/test/testdata/issue9400/asm_arm.s | 2 +- misc/cgo/test/testdata/issue9400/asm_arm64.s | 2 +- misc/cgo/test/testdata/issue9400/asm_mips64x.s | 2 +- misc/cgo/test/testdata/issue9400/asm_mipsx.s | 2 +- misc/cgo/test/testdata/issue9400/asm_ppc64x.s | 2 +- misc/cgo/test/testdata/issue9400/asm_riscv64.s | 2 +- misc/cgo/test/testdata/issue9400/asm_s390x.s | 2 +- misc/cgo/testshared/testdata/depBase/asm.s | 2 +- misc/cgo/testshared/testdata/depBase/stubs.go | 2 +- src/cmd/dist/util_gc.go | 4 ++-- src/cmd/go/testdata/script/build_overlay.txt | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/misc/cgo/test/testdata/issue9400/asm_386.s b/misc/cgo/test/testdata/issue9400/asm_386.s index 7f158b5c39..96b8b60c10 100644 --- a/misc/cgo/test/testdata/issue9400/asm_386.s +++ b/misc/cgo/test/testdata/issue9400/asm_386.s @@ -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 !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_amd64x.s b/misc/cgo/test/testdata/issue9400/asm_amd64x.s index 48b86190a5..99509bce5e 100644 --- a/misc/cgo/test/testdata/issue9400/asm_amd64x.s +++ b/misc/cgo/test/testdata/issue9400/asm_amd64x.s @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build amd64 amd64p32 -// +build !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_arm.s b/misc/cgo/test/testdata/issue9400/asm_arm.s index 96c278520f..cc92856c2f 100644 --- a/misc/cgo/test/testdata/issue9400/asm_arm.s +++ b/misc/cgo/test/testdata/issue9400/asm_arm.s @@ -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 !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_arm64.s b/misc/cgo/test/testdata/issue9400/asm_arm64.s index 2ebbfcca3b..2565793f9a 100644 --- a/misc/cgo/test/testdata/issue9400/asm_arm64.s +++ b/misc/cgo/test/testdata/issue9400/asm_arm64.s @@ -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 !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_mips64x.s b/misc/cgo/test/testdata/issue9400/asm_mips64x.s index 63dc90605e..693231ddfe 100644 --- a/misc/cgo/test/testdata/issue9400/asm_mips64x.s +++ b/misc/cgo/test/testdata/issue9400/asm_mips64x.s @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build mips64 mips64le -// +build !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_mipsx.s b/misc/cgo/test/testdata/issue9400/asm_mipsx.s index 7a92735194..63261bbf9d 100644 --- a/misc/cgo/test/testdata/issue9400/asm_mipsx.s +++ b/misc/cgo/test/testdata/issue9400/asm_mipsx.s @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build mips mipsle -// +build !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_ppc64x.s b/misc/cgo/test/testdata/issue9400/asm_ppc64x.s index c88ec3b21e..b5613fb6ec 100644 --- a/misc/cgo/test/testdata/issue9400/asm_ppc64x.s +++ b/misc/cgo/test/testdata/issue9400/asm_ppc64x.s @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build ppc64 ppc64le -// +build !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_riscv64.s b/misc/cgo/test/testdata/issue9400/asm_riscv64.s index 20fcc0066d..244dadac35 100644 --- a/misc/cgo/test/testdata/issue9400/asm_riscv64.s +++ b/misc/cgo/test/testdata/issue9400/asm_riscv64.s @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build riscv64 -// +build !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/test/testdata/issue9400/asm_s390x.s b/misc/cgo/test/testdata/issue9400/asm_s390x.s index fc9ad724c1..4856492958 100644 --- a/misc/cgo/test/testdata/issue9400/asm_s390x.s +++ b/misc/cgo/test/testdata/issue9400/asm_s390x.s @@ -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 !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/testshared/testdata/depBase/asm.s b/misc/cgo/testshared/testdata/depBase/asm.s index a8acf77f0b..0f1111f392 100644 --- a/misc/cgo/testshared/testdata/depBase/asm.s +++ b/misc/cgo/testshared/testdata/depBase/asm.s @@ -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 !gccgo +// +build gc #include "textflag.h" diff --git a/misc/cgo/testshared/testdata/depBase/stubs.go b/misc/cgo/testshared/testdata/depBase/stubs.go index 04534f38dd..c77953803b 100644 --- a/misc/cgo/testshared/testdata/depBase/stubs.go +++ b/misc/cgo/testshared/testdata/depBase/stubs.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 !gccgo +// +build gc package depBase diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go index 2db6d3a25e..875784d383 100644 --- a/src/cmd/dist/util_gc.go +++ b/src/cmd/dist/util_gc.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !gccgo -// +build !gccgo +//go:build gc +// +build gc package main diff --git a/src/cmd/go/testdata/script/build_overlay.txt b/src/cmd/go/testdata/script/build_overlay.txt index b11cd96014..2932b94e6c 100644 --- a/src/cmd/go/testdata/script/build_overlay.txt +++ b/src/cmd/go/testdata/script/build_overlay.txt @@ -238,7 +238,7 @@ void say_hello(); void say_hello() { puts("hello cgo\n"); fflush(stdout); } -- m/overlay/asm_gc.s -- -// +build !gccgo +// +build gc TEXT ·foo(SB),0,$0 RET -- GitLab From d434c2338b11b9ecf19865e8ec3f2721706f29cf Mon Sep 17 00:00:00 2001 From: zhengjianxun Date: Tue, 23 Feb 2021 03:12:56 +0000 Subject: [PATCH 0055/1298] runtime: clarify GC fractional mode description nowdays, in runtime/mgc.go,we can see the comment descrition : The fractional worker is necessary when GOMAXPROCS*gcBackgroundUtilization is not an integer. but it not true such as GOMAXPROCS=5. in the implemet of startCycle() , Fractional Mode happend only when GOMAXPROCS<=3 or GOMAXPROCS=6. so utilization can closest to 25%. Fixes #44380 Change-Id: Id0dd6d9f37759c2c9231f164a013a014216dd442 GitHub-Last-Rev: 5910e76324b2fa908235c325c8b1edafca496256 GitHub-Pull-Request: golang/go#44381 Reviewed-on: https://go-review.googlesource.com/c/go/+/293630 Reviewed-by: Austin Clements Trust: Michael Pratt --- src/runtime/mgc.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 185d3201ca..7c7239beb8 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -302,9 +302,11 @@ const ( // gcMarkWorkerFractionalMode indicates that a P is currently // running the "fractional" mark worker. The fractional worker // is necessary when GOMAXPROCS*gcBackgroundUtilization is not - // an integer. The fractional worker should run until it is - // preempted and will be scheduled to pick up the fractional - // part of GOMAXPROCS*gcBackgroundUtilization. + // an integer and using only dedicated workers would result in + // utilization too far from the target of gcBackgroundUtilization. + // The fractional worker should run until it is preempted and + // will be scheduled to pick up the fractional part of + // GOMAXPROCS*gcBackgroundUtilization. gcMarkWorkerFractionalMode // gcMarkWorkerIdleMode indicates that a P is running the mark -- GitLab From d2911d76127deaa08644979cec7d990559f0aa54 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 9 Dec 2020 14:59:40 -0800 Subject: [PATCH 0056/1298] cmd/compile: fold MOV*nop and MOV*const MOV*nop and MOV*reg seem superfluous. They are there to keep type information around that would otherwise get thrown away. Not sure what we need it for. I think our compiler needs a normalization of how types are represented in SSA, especially after lowering. MOV*nop gets in the way of some optimization rules firing, like for load combining. For now, just fold MOV*nop and MOV*const. It's certainly safe to do that, as the type info on the MOV*const isn't ever useful. R=go1.17 Change-Id: I3630a80afc2455a8e9cd9fde10c7abe05ddc3767 Reviewed-on: https://go-review.googlesource.com/c/go/+/276792 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/gen/ARM.rules | 4 ++++ src/cmd/compile/internal/ssa/gen/ARM64.rules | 4 ++++ src/cmd/compile/internal/ssa/gen/MIPS.rules | 4 ++++ src/cmd/compile/internal/ssa/gen/MIPS64.rules | 4 ++++ src/cmd/compile/internal/ssa/gen/RISCV64.rules | 4 ++++ src/cmd/compile/internal/ssa/rewriteARM.go | 17 +++++++++++++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 17 +++++++++++++++++ src/cmd/compile/internal/ssa/rewriteMIPS.go | 17 +++++++++++++++++ src/cmd/compile/internal/ssa/rewriteMIPS64.go | 17 +++++++++++++++++ src/cmd/compile/internal/ssa/rewriteRISCV64.go | 17 +++++++++++++++++ 10 files changed, 105 insertions(+) diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index de0df363e4..cbafd12a4f 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -546,6 +546,10 @@ // MOVWnop doesn't emit instruction, only for ensuring the type. (MOVWreg x) && x.Uses == 1 => (MOVWnop x) +// TODO: we should be able to get rid of MOVWnop all together. +// But for now, this is enough to get rid of lots of them. +(MOVWnop (MOVWconst [c])) => (MOVWconst [c]) + // mul by constant (MUL x (MOVWconst [c])) && int32(c) == -1 => (RSBconst [0] x) (MUL _ (MOVWconst [0])) => (MOVWconst [0]) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index a0e2a0d5e2..4531c38a7a 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -1127,6 +1127,10 @@ // MOVDnop doesn't emit instruction, only for ensuring the type. (MOVDreg x) && x.Uses == 1 => (MOVDnop x) +// TODO: we should be able to get rid of MOVDnop all together. +// But for now, this is enough to get rid of lots of them. +(MOVDnop (MOVDconst [c])) => (MOVDconst [c]) + // fold constant into arithmatic ops (ADD x (MOVDconst [c])) => (ADDconst [c] x) (SUB x (MOVDconst [c])) => (SUBconst [c] x) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index 8ad2c90ac3..bc1ce82940 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -559,6 +559,10 @@ // MOVWnop doesn't emit instruction, only for ensuring the type. (MOVWreg x) && x.Uses == 1 => (MOVWnop x) +// TODO: we should be able to get rid of MOVWnop all together. +// But for now, this is enough to get rid of lots of them. +(MOVWnop (MOVWconst [c])) => (MOVWconst [c]) + // fold constant into arithmatic ops (ADD x (MOVWconst [c])) => (ADDconst [c] x) (SUB x (MOVWconst [c])) => (SUBconst [c] x) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules index 088c9b1ac4..e3f7633274 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules @@ -558,6 +558,10 @@ // MOVVnop doesn't emit instruction, only for ensuring the type. (MOVVreg x) && x.Uses == 1 => (MOVVnop x) +// TODO: we should be able to get rid of MOVVnop all together. +// But for now, this is enough to get rid of lots of them. +(MOVVnop (MOVVconst [c])) => (MOVVconst [c]) + // fold constant into arithmatic ops (ADDV x (MOVVconst [c])) && is32Bit(c) => (ADDVconst [c] x) (SUBV x (MOVVconst [c])) && is32Bit(c) => (SUBVconst [c] x) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules index 15361fd37a..9119ebc0e8 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules @@ -673,6 +673,10 @@ // MOVnop does not emit an instruction, only for ensuring the type. (MOVDreg x) && x.Uses == 1 => (MOVDnop x) +// TODO: we should be able to get rid of MOVDnop all together. +// But for now, this is enough to get rid of lots of them. +(MOVDnop (MOVDconst [c])) => (MOVDconst [c]) + // Fold constant into immediate instructions where possible. (ADD (MOVBconst [val]) x) => (ADDI [int64(val)] x) (ADD (MOVHconst [val]) x) => (ADDI [int64(val)] x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index c958aae2c4..1adbceb0ad 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -202,6 +202,8 @@ func rewriteValueARM(v *Value) bool { return rewriteValueARM_OpARMMOVWloadshiftRA(v) case OpARMMOVWloadshiftRL: return rewriteValueARM_OpARMMOVWloadshiftRL(v) + case OpARMMOVWnop: + return rewriteValueARM_OpARMMOVWnop(v) case OpARMMOVWreg: return rewriteValueARM_OpARMMOVWreg(v) case OpARMMOVWstore: @@ -6501,6 +6503,21 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value) bool { } return false } +func rewriteValueARM_OpARMMOVWnop(v *Value) bool { + v_0 := v.Args[0] + // match: (MOVWnop (MOVWconst [c])) + // result: (MOVWconst [c]) + for { + if v_0.Op != OpARMMOVWconst { + break + } + c := auxIntToInt32(v_0.AuxInt) + v.reset(OpARMMOVWconst) + v.AuxInt = int32ToAuxInt(c) + return true + } + return false +} func rewriteValueARM_OpARMMOVWreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVWreg x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index ff1156d901..ba146c7043 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -189,6 +189,8 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpARM64MOVDloadidx(v) case OpARM64MOVDloadidx8: return rewriteValueARM64_OpARM64MOVDloadidx8(v) + case OpARM64MOVDnop: + return rewriteValueARM64_OpARM64MOVDnop(v) case OpARM64MOVDreg: return rewriteValueARM64_OpARM64MOVDreg(v) case OpARM64MOVDstore: @@ -9011,6 +9013,21 @@ func rewriteValueARM64_OpARM64MOVDloadidx8(v *Value) bool { } return false } +func rewriteValueARM64_OpARM64MOVDnop(v *Value) bool { + v_0 := v.Args[0] + // match: (MOVDnop (MOVDconst [c])) + // result: (MOVDconst [c]) + for { + if v_0.Op != OpARM64MOVDconst { + break + } + c := auxIntToInt64(v_0.AuxInt) + v.reset(OpARM64MOVDconst) + v.AuxInt = int64ToAuxInt(c) + return true + } + return false +} func rewriteValueARM64_OpARM64MOVDreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVDreg x) diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index 3fc5527955..0c074364df 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -297,6 +297,8 @@ func rewriteValueMIPS(v *Value) bool { return rewriteValueMIPS_OpMIPSMOVHstorezero(v) case OpMIPSMOVWload: return rewriteValueMIPS_OpMIPSMOVWload(v) + case OpMIPSMOVWnop: + return rewriteValueMIPS_OpMIPSMOVWnop(v) case OpMIPSMOVWreg: return rewriteValueMIPS_OpMIPSMOVWreg(v) case OpMIPSMOVWstore: @@ -3647,6 +3649,21 @@ func rewriteValueMIPS_OpMIPSMOVWload(v *Value) bool { } return false } +func rewriteValueMIPS_OpMIPSMOVWnop(v *Value) bool { + v_0 := v.Args[0] + // match: (MOVWnop (MOVWconst [c])) + // result: (MOVWconst [c]) + for { + if v_0.Op != OpMIPSMOVWconst { + break + } + c := auxIntToInt32(v_0.AuxInt) + v.reset(OpMIPSMOVWconst) + v.AuxInt = int32ToAuxInt(c) + return true + } + return false +} func rewriteValueMIPS_OpMIPSMOVWreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVWreg x) diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index d78f6089af..073cf8726c 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -339,6 +339,8 @@ func rewriteValueMIPS64(v *Value) bool { return rewriteValueMIPS64_OpMIPS64MOVHstorezero(v) case OpMIPS64MOVVload: return rewriteValueMIPS64_OpMIPS64MOVVload(v) + case OpMIPS64MOVVnop: + return rewriteValueMIPS64_OpMIPS64MOVVnop(v) case OpMIPS64MOVVreg: return rewriteValueMIPS64_OpMIPS64MOVVreg(v) case OpMIPS64MOVVstore: @@ -3584,6 +3586,21 @@ func rewriteValueMIPS64_OpMIPS64MOVVload(v *Value) bool { } return false } +func rewriteValueMIPS64_OpMIPS64MOVVnop(v *Value) bool { + v_0 := v.Args[0] + // match: (MOVVnop (MOVVconst [c])) + // result: (MOVVconst [c]) + for { + if v_0.Op != OpMIPS64MOVVconst { + break + } + c := auxIntToInt64(v_0.AuxInt) + v.reset(OpMIPS64MOVVconst) + v.AuxInt = int64ToAuxInt(c) + return true + } + return false +} func rewriteValueMIPS64_OpMIPS64MOVVreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVVreg x) diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index 1abdf1aa06..bc47d76e87 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -435,6 +435,8 @@ func rewriteValueRISCV64(v *Value) bool { return rewriteValueRISCV64_OpRISCV64MOVDconst(v) case OpRISCV64MOVDload: return rewriteValueRISCV64_OpRISCV64MOVDload(v) + case OpRISCV64MOVDnop: + return rewriteValueRISCV64_OpRISCV64MOVDnop(v) case OpRISCV64MOVDreg: return rewriteValueRISCV64_OpRISCV64MOVDreg(v) case OpRISCV64MOVDstore: @@ -3349,6 +3351,21 @@ func rewriteValueRISCV64_OpRISCV64MOVDload(v *Value) bool { } return false } +func rewriteValueRISCV64_OpRISCV64MOVDnop(v *Value) bool { + v_0 := v.Args[0] + // match: (MOVDnop (MOVDconst [c])) + // result: (MOVDconst [c]) + for { + if v_0.Op != OpRISCV64MOVDconst { + break + } + c := auxIntToInt64(v_0.AuxInt) + v.reset(OpRISCV64MOVDconst) + v.AuxInt = int64ToAuxInt(c) + return true + } + return false +} func rewriteValueRISCV64_OpRISCV64MOVDreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVDreg x) -- GitLab From c49c7a675a2c8ee7591a2d6243255813856b65ce Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 1 Feb 2021 00:45:41 -0800 Subject: [PATCH 0057/1298] runtime: save R15 before checking AVX state When in dynlink mode, reading a global can clobber R15. Just to be safe, save R15 before checking the AVX state to see if we need to VZEROUPPER or not. This could cause a problem in buildmodes that aren't supported yet. Change-Id: I8fda62d3fbe808584774fa5e8d9810a4612a84e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/288452 Trust: Keith Randall Reviewed-by: Cherry Zhang --- src/runtime/mkpreempt.go | 19 +++++++++++++------ src/runtime/preempt_amd64.s | 10 +++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go index 3069d6ed04..3a9e6cc478 100644 --- a/src/runtime/mkpreempt.go +++ b/src/runtime/mkpreempt.go @@ -230,12 +230,16 @@ func genAMD64() { if reg == "SP" || reg == "BP" { continue } - if strings.HasPrefix(reg, "X") { - l.add("MOVUPS", reg, 16) - } else { + if !strings.HasPrefix(reg, "X") { l.add("MOVQ", reg, 8) } } + lSSE := layout{stack: l.stack, sp: "SP"} + for _, reg := range regNamesAMD64 { + if strings.HasPrefix(reg, "X") { + lSSE.add("MOVUPS", reg, 16) + } + } // TODO: MXCSR register? @@ -244,10 +248,12 @@ func genAMD64() { p("// Save flags before clobbering them") p("PUSHFQ") p("// obj doesn't understand ADD/SUB on SP, but does understand ADJSP") - p("ADJSP $%d", l.stack) + p("ADJSP $%d", lSSE.stack) p("// But vet doesn't know ADJSP, so suppress vet stack checking") p("NOP SP") + l.save() + // Apparently, the signal handling code path in darwin kernel leaves // the upper bits of Y registers in a dirty state, which causes // many SSE operations (128-bit and narrower) become much slower. @@ -259,10 +265,11 @@ func genAMD64() { p("VZEROUPPER") p("#endif") - l.save() + lSSE.save() p("CALL ·asyncPreempt2(SB)") + lSSE.restore() l.restore() - p("ADJSP $%d", -l.stack) + p("ADJSP $%d", -lSSE.stack) p("POPFQ") p("POPQ BP") p("RET") diff --git a/src/runtime/preempt_amd64.s b/src/runtime/preempt_amd64.s index 92c664d79a..dc7af806d3 100644 --- a/src/runtime/preempt_amd64.s +++ b/src/runtime/preempt_amd64.s @@ -13,11 +13,6 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 ADJSP $368 // But vet doesn't know ADJSP, so suppress vet stack checking NOP SP - #ifdef GOOS_darwin - CMPB internal∕cpu·X86+const_offsetX86HasAVX(SB), $0 - JE 2(PC) - VZEROUPPER - #endif MOVQ AX, 0(SP) MOVQ CX, 8(SP) MOVQ DX, 16(SP) @@ -32,6 +27,11 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVQ R13, 88(SP) MOVQ R14, 96(SP) MOVQ R15, 104(SP) + #ifdef GOOS_darwin + CMPB internal∕cpu·X86+const_offsetX86HasAVX(SB), $0 + JE 2(PC) + VZEROUPPER + #endif MOVUPS X0, 112(SP) MOVUPS X1, 128(SP) MOVUPS X2, 144(SP) -- GitLab From a4dac8bd220ff893d7df9cb6fbaf56ecfdd66ad4 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 3 Feb 2021 12:25:46 -0800 Subject: [PATCH 0058/1298] runtime: use BX instead of R15 in race detector If the race detector were runnable in dynamic linking mode, then R15 would get clobbered. I don't think it is, so maybe not a problem, but can't hurt to clean it up. It also lets CL 283474 pass cleanly when checking the whole stdlib (together with CL 288452). Change-Id: I5a5021ecc7e7b8bed1cd3a7067c39b24c09e0783 Reviewed-on: https://go-review.googlesource.com/c/go/+/289270 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/runtime/race_amd64.s | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index c3b7bbfbfe..e10c21c7f3 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -184,7 +184,7 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 // Common code for racefuncenter/racefuncenterfp // R11 = caller's return address TEXT racefuncenter<>(SB), NOSPLIT, $0-0 - MOVQ DX, R15 // save function entry context (for closures) + MOVQ DX, BX // save function entry context (for closures) #ifndef GOEXPERIMENT_REGABI get_tls(R12) MOVQ g(R12), R14 @@ -193,9 +193,9 @@ TEXT racefuncenter<>(SB), NOSPLIT, $0-0 MOVQ R11, RARG1 // void __tsan_func_enter(ThreadState *thr, void *pc); MOVQ $__tsan_func_enter(SB), AX - // racecall<> preserves R15 + // racecall<> preserves BX CALL racecall<>(SB) - MOVQ R15, DX // restore function entry context + MOVQ BX, DX // restore function entry context RET // func runtime·racefuncexit() @@ -376,7 +376,7 @@ racecallatomic_ignore: // Addr is outside the good range. // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. // An attempt to synchronize on the address would cause crash. - MOVQ AX, R15 // remember the original function + MOVQ AX, BX // remember the original function MOVQ $__tsan_go_ignore_sync_begin(SB), AX #ifndef GOEXPERIMENT_REGABI get_tls(R12) @@ -384,7 +384,7 @@ racecallatomic_ignore: #endif MOVQ g_racectx(R14), RARG0 // goroutine context CALL racecall<>(SB) - MOVQ R15, AX // restore the original function + MOVQ BX, AX // restore the original function // Call the atomic function. MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ 8(SP), RARG1 // caller pc -- GitLab From fa40c0232c79f1e8eb6bda6c63604958bdf1102f Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 22 Feb 2021 15:04:25 -0500 Subject: [PATCH 0059/1298] cmd/go: reproduce issue #44497 in TestScript/mod_edit For #44497 Change-Id: Ie5285b9c526506b6b1280a590a5dcbee4074f57b Reviewed-on: https://go-review.googlesource.com/c/go/+/295149 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/testdata/script/mod_edit.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt index d7e681e831..02d2d40bbb 100644 --- a/src/cmd/go/testdata/script/mod_edit.txt +++ b/src/cmd/go/testdata/script/mod_edit.txt @@ -26,6 +26,25 @@ cmpenv go.mod $WORK/go.mod.edit2 stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$' ! go mod edit -retract=bad stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$' +cmpenv go.mod $WORK/go.mod.edit2 + +cp go.mod go.mod.beforebugs + +# BUG(#44497): -exclude accepts a mismatched major version without +incompatible, but should not. +go mod edit -exclude=example.com/m@v2.0.0 +! go mod edit -json +stderr '^go: errors parsing go.mod:\n.*[/\\]go.mod:16: exclude example\.com/m: version "v2\.0\.0" invalid: should be v0 or v1, not v2$' +cp go.mod.beforebugs go.mod + +# BUG(#44497): -exclude accepts a v1 version for a v2 module, but should not. +go mod edit -exclude=example.com/m/v2@v1.0.0 +! go mod edit -json +stderr '^go: errors parsing go.mod:\n.*[/\\]go.mod:16: exclude example\.com/m/v2: version "v1\.0\.0" invalid: should be v2, not v1$' +cp go.mod.beforebugs go.mod + +# BUG(#44497): -exclude rejects a +incompatible version for an unversioned +# module path, but should not. +! go mod edit -exclude=example.com/m@v2.0.0+incompatible # go mod edit -json go mod edit -json -- GitLab From 74903553bc91cef8f31067ad69ef2aa7d60ceb00 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Mon, 22 Feb 2021 17:21:10 -0500 Subject: [PATCH 0060/1298] doc: start draft go1.17 release notes, move go1.16 to x/website This template is based on CL 248198 and previous ones like it. Continue to eagerly include often-used sections, and clarify that the TODO is about completing the section, or removing if it turns out not to be needed. Move the Go 1.16 release notes to x/website, since that's the new home for past Go release notes as of CL 291711. They're added to x/website in CL 295249. 'relnote -html' does not report any CLs with RELNOTE annotations since 2021/02/01. For #44513. Updates #40700. Change-Id: Idd389335500ec4dec2764cbbaa385918cc8a79ad Reviewed-on: https://go-review.googlesource.com/c/go/+/295209 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Alexander Rakoczy Reviewed-by: Carlos Amedee --- doc/go1.16.html | 1220 ----------------------------------------------- doc/go1.17.html | 84 ++++ 2 files changed, 84 insertions(+), 1220 deletions(-) delete mode 100644 doc/go1.16.html create mode 100644 doc/go1.17.html diff --git a/doc/go1.16.html b/doc/go1.16.html deleted file mode 100644 index f2370e8363..0000000000 --- a/doc/go1.16.html +++ /dev/null @@ -1,1220 +0,0 @@ - - - - - - -

    Introduction to Go 1.16

    - -

    - The latest Go release, version 1.16, arrives six months after Go 1.15. - Most of its changes are in the implementation of the toolchain, runtime, and libraries. - As always, the release maintains the Go 1 promise of compatibility. - We expect almost all Go programs to continue to compile and run as before. -

    - -

    Changes to the language

    - -

    - There are no changes to the language. -

    - -

    Ports

    - -

    Darwin and iOS

    - -

    - Go 1.16 adds support of 64-bit ARM architecture on macOS (also known as - Apple Silicon) with GOOS=darwin, GOARCH=arm64. - Like the darwin/amd64 port, the darwin/arm64 - port supports cgo, internal and external linking, c-archive, - c-shared, and pie build modes, and the race - detector. -

    - -

    - The iOS port, which was previously darwin/arm64, has - been renamed to ios/arm64. GOOS=ios - implies the - darwin build tag, just as GOOS=android - implies the linux build tag. This change should be - transparent to anyone using gomobile to build iOS apps. -

    - -

    - Go 1.16 adds an ios/amd64 port, which targets the iOS - simulator running on AMD64-based macOS. Previously this was - unofficially supported through darwin/amd64 with - the ios build tag set. See also - misc/ios/README for - details about how to build programs for iOS and iOS simulator. -

    - -

    - Go 1.16 is the last release that will run on macOS 10.12 Sierra. - Go 1.17 will require macOS 10.13 High Sierra or later. -

    - -

    NetBSD

    - -

    - Go now supports the 64-bit ARM architecture on NetBSD (the - netbsd/arm64 port). -

    - -

    OpenBSD

    - -

    - Go now supports the MIPS64 architecture on OpenBSD - (the openbsd/mips64 port). This port does not yet - support cgo. -

    - -

    - On the 64-bit x86 and 64-bit ARM architectures on OpenBSD (the - openbsd/amd64 and openbsd/arm64 ports), system - calls are now made through libc, instead of directly using - the SYSCALL/SVC instruction. This ensures - forward-compatibility with future versions of OpenBSD. In particular, - OpenBSD 6.9 onwards will require system calls to be made through - libc for non-static Go binaries. -

    - -

    386

    - -

    - As announced in the Go 1.15 release notes, - Go 1.16 drops support for x87 mode compilation (GO386=387). - Support for non-SSE2 processors is now available using soft float - mode (GO386=softfloat). - Users running on non-SSE2 processors should replace GO386=387 - with GO386=softfloat. -

    - -

    RISC-V

    - -

    - The linux/riscv64 port now supports cgo and - -buildmode=pie. This release also includes performance - optimizations and code generation improvements for RISC-V. -

    - -

    Tools

    - -

    Go command

    - -

    Modules

    - -

    - Module-aware mode is enabled by default, regardless of whether a - go.mod file is present in the current working directory or a - parent directory. More precisely, the GO111MODULE environment - variable now defaults to on. To switch to the previous behavior, - set GO111MODULE to auto. -

    - -

    - Build commands like go build and go - test no longer modify go.mod and go.sum - by default. Instead, they report an error if a module requirement or checksum - needs to be added or updated (as if the -mod=readonly flag were - used). Module requirements and sums may be adjusted with go - mod tidy or go get. -

    - -

    - go install now accepts arguments with - version suffixes (for example, go install - example.com/cmd@v1.0.0). This causes go - install to build and install packages in module-aware mode, - ignoring the go.mod file in the current directory or any parent - directory, if there is one. This is useful for installing executables without - affecting the dependencies of the main module. -

    - -

    - go install, with or without a version suffix (as - described above), is now the recommended way to build and install packages in - module mode. go get should be used with the - -d flag to adjust the current module's dependencies without - building packages, and use of go get to build and - install packages is deprecated. In a future release, the -d flag - will always be enabled. -

    - -

    - retract directives may now be used in a go.mod file - to indicate that certain published versions of the module should not be used - by other modules. A module author may retract a version after a severe problem - is discovered or if the version was published unintentionally. -

    - -

    - The go mod vendor - and go mod tidy subcommands now accept - the -e flag, which instructs them to proceed despite errors in - resolving missing packages. -

    - -

    - The go command now ignores requirements on module versions - excluded by exclude directives in the main module. Previously, - the go command used the next version higher than an excluded - version, but that version could change over time, resulting in - non-reproducible builds. -

    - -

    - In module mode, the go command now disallows import paths that - include non-ASCII characters or path elements with a leading dot character - (.). Module paths with these characters were already disallowed - (see Module paths and versions), - so this change affects only paths within module subdirectories. -

    - -

    Embedding Files

    - -

    - The go command now supports including - static files and file trees as part of the final executable, - using the new //go:embed directive. - See the documentation for the new - embed - package for details. -

    - -

    go test

    - -

    - When using go test, a test that - calls os.Exit(0) during execution of a test function - will now be considered to fail. - This will help catch cases in which a test calls code that calls - os.Exit(0) and thereby stops running all future tests. - If a TestMain function calls os.Exit(0) - that is still considered to be a passing test. -

    - -

    - go test reports an error when the -c - or -i flags are used together with unknown flags. Normally, - unknown flags are passed to tests, but when -c or -i - are used, tests are not run. -

    - -

    go get

    - -

    - The go get -insecure flag is - deprecated and will be removed in a future version. This flag permits - fetching from repositories and resolving custom domains using insecure - schemes such as HTTP, and also bypasses module sum validation using the - checksum database. To permit the use of insecure schemes, use the - GOINSECURE environment variable instead. To bypass module - sum validation, use GOPRIVATE or GONOSUMDB. - See go help environment for details. -

    - -

    - go get example.com/mod@patch now - requires that some version of example.com/mod already be - required by the main module. - (However, go get -u=patch continues - to patch even newly-added dependencies.) -

    - -

    GOVCS environment variable

    - -

    - GOVCS is a new environment variable that limits which version - control tools the go command may use to download source code. - This mitigates security issues with tools that are typically used in trusted, - authenticated environments. By default, git and hg - may be used to download code from any repository. svn, - bzr, and fossil may only be used to download code - from repositories with module paths or package paths matching patterns in - the GOPRIVATE environment variable. See - go - help vcs for details. -

    - -

    The all pattern

    - -

    - When the main module's go.mod file - declares go 1.16 or higher, the all - package pattern now matches only those packages that are transitively imported - by a package or test found in the main module. (Packages imported by tests - of packages imported by the main module are no longer included.) This is - the same set of packages retained - by go mod vendor since Go 1.11. -

    - -

    The -toolexec build flag

    - -

    - When the -toolexec build flag is specified to use a program when - invoking toolchain programs like compile or asm, the environment variable - TOOLEXEC_IMPORTPATH is now set to the import path of the package - being built. -

    - -

    The -i build flag

    - -

    - The -i flag accepted by go build, - go install, and go test is - now deprecated. The -i flag instructs the go command - to install packages imported by packages named on the command line. Since - the build cache was introduced in Go 1.10, the -i flag no longer - has a significant effect on build times, and it causes errors when the install - directory is not writable. -

    - -

    The list command

    - -

    - When the -export flag is specified, the BuildID - field is now set to the build ID of the compiled package. This is equivalent - to running go tool buildid on - go list -exported -f {{.Export}}, - but without the extra step. -

    - -

    The -overlay flag

    - -

    - The -overlay flag specifies a JSON configuration file containing - a set of file path replacements. The -overlay flag may be used - with all build commands and go mod subcommands. - It is primarily intended to be used by editor tooling such as gopls to - understand the effects of unsaved changes to source files. The config file - maps actual file paths to replacement file paths and the go - command and its builds will run as if the actual file paths exist with the - contents given by the replacement file paths, or don't exist if the replacement - file paths are empty. -

    - -

    Cgo

    - -

    - The cgo tool will no longer try to translate - C struct bitfields into Go struct fields, even if their size can be - represented in Go. The order in which C bitfields appear in memory - is implementation dependent, so in some cases the cgo tool produced - results that were silently incorrect. -

    - -

    Vet

    - -

    New warning for invalid testing.T use in -goroutines

    - -

    - The vet tool now warns about invalid calls to the testing.T - method Fatal from within a goroutine created during the test. - This also warns on calls to Fatalf, FailNow, and - Skip{,f,Now} methods on testing.T tests or - testing.B benchmarks. -

    - -

    - Calls to these methods stop the execution of the created goroutine and not - the Test* or Benchmark* function. So these are - required to be called by the goroutine - running the test or benchmark function. For example: -

    - -
    -func TestFoo(t *testing.T) {
    -    go func() {
    -        if condition() {
    -            t.Fatal("oops") // This exits the inner func instead of TestFoo.
    -        }
    -        ...
    -    }()
    -}
    -
    - -

    - Code calling t.Fatal (or a similar method) from a created - goroutine should be rewritten to signal the test failure using - t.Error and exit the goroutine early using an alternative - method, such as using a return statement. The previous example - could be rewritten as: -

    - -
    -func TestFoo(t *testing.T) {
    -    go func() {
    -        if condition() {
    -            t.Error("oops")
    -            return
    -        }
    -        ...
    -    }()
    -}
    -
    - -

    New warning for frame pointer

    - -

    - The vet tool now warns about amd64 assembly that clobbers the BP - register (the frame pointer) without saving and restoring it, - contrary to the calling convention. Code that doesn't preserve the - BP register must be modified to either not use BP at all or preserve - BP by saving and restoring it. An easy way to preserve BP is to set - the frame size to a nonzero value, which causes the generated - prologue and epilogue to preserve the BP register for you. - See CL 248260 for example - fixes. -

    - -

    New warning for asn1.Unmarshal

    - -

    - The vet tool now warns about incorrectly passing a non-pointer or nil argument to - asn1.Unmarshal. - This is like the existing checks for - encoding/json.Unmarshal - and encoding/xml.Unmarshal. -

    - -

    Runtime

    - -

    - The new runtime/metrics package - introduces a stable interface for reading - implementation-defined metrics from the Go runtime. - It supersedes existing functions like - runtime.ReadMemStats - and - debug.GCStats - and is significantly more general and efficient. - See the package documentation for more details. -

    - -

    - Setting the GODEBUG environment variable - to inittrace=1 now causes the runtime to emit a single - line to standard error for each package init, - summarizing its execution time and memory allocation. This trace can - be used to find bottlenecks or regressions in Go startup - performance. - The GODEBUG - documentation describes the format. -

    - -

    - On Linux, the runtime now defaults to releasing memory to the - operating system promptly (using MADV_DONTNEED), rather - than lazily when the operating system is under memory pressure - (using MADV_FREE). This means process-level memory - statistics like RSS will more accurately reflect the amount of - physical memory being used by Go processes. Systems that are - currently using GODEBUG=madvdontneed=1 to improve - memory monitoring behavior no longer need to set this environment - variable. -

    - -

    - Go 1.16 fixes a discrepancy between the race detector and - the Go memory model. The race detector now - more precisely follows the channel synchronization rules of the - memory model. As a result, the detector may now report races it - previously missed. -

    - -

    Compiler

    - -

    - The compiler can now inline functions with - non-labeled for loops, method values, and type - switches. The inliner can also detect more indirect calls where - inlining is possible. -

    - -

    Linker

    - -

    - This release includes additional improvements to the Go linker, - reducing linker resource usage (both time and memory) and improving - code robustness/maintainability. These changes form the second half - of a two-release project to - modernize the Go - linker. -

    - -

    - The linker changes in 1.16 extend the 1.15 improvements to all - supported architecture/OS combinations (the 1.15 performance improvements - were primarily focused on ELF-based OSes and - amd64 architectures). For a representative set of - large Go programs, linking is 20-25% faster than 1.15 and requires - 5-15% less memory on average for linux/amd64, with larger - improvements for other architectures and OSes. Most binaries are - also smaller as a result of more aggressive symbol pruning. -

    - -

    - On Windows, go build -buildmode=c-shared now generates Windows - ASLR DLLs by default. ASLR can be disabled with --ldflags=-aslr=false. -

    - -

    Core library

    - -

    Embedded Files

    - -

    - The new embed package - provides access to files embedded in the program during compilation - using the new //go:embed directive. -

    - -

    File Systems

    - -

    - The new io/fs package - defines the fs.FS interface, - an abstraction for read-only trees of files. - The standard library packages have been adapted to make use - of the interface as appropriate. -

    - -

    - On the producer side of the interface, - the new embed.FS type - implements fs.FS, as does - zip.Reader. - The new os.DirFS function - provides an implementation of fs.FS backed by a tree - of operating system files. -

    - -

    - On the consumer side, - the new http.FS - function converts an fs.FS to an - http.FileSystem. - Also, the html/template - and text/template - packages’ ParseFS - functions and methods read templates from an fs.FS. -

    - -

    - For testing code that implements fs.FS, - the new testing/fstest - package provides a TestFS - function that checks for and reports common mistakes. - It also provides a simple in-memory file system implementation, - MapFS, - which can be useful for testing code that accepts fs.FS - implementations. -

    - -

    Deprecation of io/ioutil

    - -

    - The io/ioutil package has - turned out to be a poorly defined and hard to understand collection - of things. All functionality provided by the package has been moved - to other packages. The io/ioutil package remains and - will continue to work as before, but we encourage new code to use - the new definitions in the io and - os packages. - - Here is a list of the new locations of the names exported - by io/ioutil: -

    -

    - - - -

    Minor changes to the library

    - -

    - As always, there are various minor changes and updates to the library, - made with the Go 1 promise of compatibility - in mind. -

    - -
    archive/zip
    -
    -

    - The new Reader.Open - method implements the fs.FS - interface. -

    -
    -
    - -
    crypto/dsa
    -
    -

    - The crypto/dsa package is now deprecated. - See issue #40337. -

    -
    -
    - -
    crypto/hmac
    -
    -

    - New will now panic if - separate calls to the hash generation function fail to return new values. - Previously, the behavior was undefined and invalid outputs were sometimes - generated. -

    -
    -
    - -
    crypto/tls
    -
    -

    - I/O operations on closing or closed TLS connections can now be detected - using the new net.ErrClosed - error. A typical use would be errors.Is(err, net.ErrClosed). -

    - -

    - A default write deadline is now set in - Conn.Close - before sending the "close notify" alert, in order to prevent blocking - indefinitely. -

    - -

    - Clients now return a handshake error if the server selects - - an ALPN protocol that was not in - - the list advertised by the client. -

    - -

    - Servers will now prefer other available AEAD cipher suites (such as ChaCha20Poly1305) - over AES-GCM cipher suites if either the client or server doesn't have AES hardware - support, unless both - Config.PreferServerCipherSuites - and Config.CipherSuites - are set. The client is assumed not to have AES hardware support if it does - not signal a preference for AES-GCM cipher suites. -

    - -

    - Config.Clone now - returns nil if the receiver is nil, rather than panicking. -

    -
    -
    - -
    crypto/x509
    -
    -

    - The GODEBUG=x509ignoreCN=0 flag will be removed in Go 1.17. - It enables the legacy behavior of treating the CommonName - field on X.509 certificates as a host name when no Subject Alternative - Names are present. -

    - -

    - ParseCertificate and - CreateCertificate - now enforce string encoding restrictions for the DNSNames, - EmailAddresses, and URIs fields. These fields - can only contain strings with characters within the ASCII range. -

    - -

    - CreateCertificate - now verifies the generated certificate's signature using the signer's - public key. If the signature is invalid, an error is returned, instead of - a malformed certificate. -

    - -

    - DSA signature verification is no longer supported. Note that DSA signature - generation was never supported. - See issue #40337. -

    - -

    - On Windows, Certificate.Verify - will now return all certificate chains that are built by the platform - certificate verifier, instead of just the highest ranked chain. -

    - -

    - The new SystemRootsError.Unwrap - method allows accessing the Err - field through the errors package functions. -

    - -

    - On Unix systems, the crypto/x509 package is now more - efficient in how it stores its copy of the system cert pool. - Programs that use only a small number of roots will use around a - half megabyte less memory. -

    - -
    -
    - -
    debug/elf
    -
    -

    - More DT - and PT - constants have been added. -

    -
    -
    - -
    encoding/asn1
    -
    -

    - Unmarshal and - UnmarshalWithParams - now return an error instead of panicking when the argument is not - a pointer or is nil. This change matches the behavior of other - encoding packages such as encoding/json. -

    -
    -
    - -
    encoding/json
    -
    -

    - The json struct field tags understood by - Marshal, - Unmarshal, - and related functionality now permit semicolon characters within - a JSON object name for a Go struct field. -

    -
    -
    - -
    encoding/xml
    -
    -

    - The encoder has always taken care to avoid using namespace prefixes - beginning with xml, which are reserved by the XML - specification. - Now, following the specification more closely, that check is - case-insensitive, so that prefixes beginning - with XML, XmL, and so on are also - avoided. -

    -
    -
    - -
    flag
    -
    -

    - The new Func function - allows registering a flag implemented by calling a function, - as a lighter-weight alternative to implementing the - Value interface. -

    -
    -
    - -
    go/build
    -
    -

    - The Package - struct has new fields that report information - about //go:embed directives in the package: - EmbedPatterns, - EmbedPatternPos, - TestEmbedPatterns, - TestEmbedPatternPos, - XTestEmbedPatterns, - XTestEmbedPatternPos. -

    - -

    - The Package field - IgnoredGoFiles - will no longer include files that start with "_" or ".", - as those files are always ignored. - IgnoredGoFiles is for files ignored because of - build constraints. -

    - -

    - The new Package - field IgnoredOtherFiles - has a list of non-Go files ignored because of build constraints. -

    -
    -
    - -
    go/build/constraint
    -
    -

    - The new - go/build/constraint - package parses build constraint lines, both the original - // +build syntax and the //go:build - syntax that will be introduced in Go 1.17. - This package exists so that tools built with Go 1.16 will be able - to process Go 1.17 source code. - See https://golang.org/design/draft-gobuild - for details about the build constraint syntaxes and the planned - transition to the //go:build syntax. - Note that //go:build lines are not supported - in Go 1.16 and should not be introduced into Go programs yet. -

    -
    -
    - -
    html/template
    -
    -

    - The new template.ParseFS - function and template.Template.ParseFS - method are like template.ParseGlob - and template.Template.ParseGlob, - but read the templates from an fs.FS. -

    -
    -
    - -
    io
    -
    -

    - The package now defines a - ReadSeekCloser interface. -

    - -

    - The package now defines - Discard, - NopCloser, and - ReadAll, - to be used instead of the same names in the - io/ioutil package. -

    -
    -
    - -
    log
    -
    -

    - The new Default function - provides access to the default Logger. -

    -
    -
    - -
    log/syslog
    -
    -

    - The Writer - now uses the local message format - (omitting the host name and using a shorter time stamp) - when logging to custom Unix domain sockets, - matching the format already used for the default log socket. -

    -
    -
    - -
    mime/multipart
    -
    -

    - The Reader's - ReadForm - method no longer rejects form data - when passed the maximum int64 value as a limit. -

    -
    -
    - -
    net
    -
    -

    - The case of I/O on a closed network connection, or I/O on a network - connection that is closed before any of the I/O completes, can now - be detected using the new ErrClosed - error. A typical use would be errors.Is(err, net.ErrClosed). - In earlier releases the only way to reliably detect this case was to - match the string returned by the Error method - with "use of closed network connection". -

    - -

    - In previous Go releases the default TCP listener backlog size on Linux systems, - set by /proc/sys/net/core/somaxconn, was limited to a maximum of 65535. - On Linux kernel version 4.1 and above, the maximum is now 4294967295. -

    - -

    - On Linux, host name lookups no longer use DNS before checking - /etc/hosts when /etc/nsswitch.conf - is missing; this is common on musl-based systems and makes - Go programs match the behavior of C programs on those systems. -

    -
    -
    - -
    net/http
    -
    -

    - In the net/http package, the - behavior of StripPrefix - has been changed to strip the prefix from the request URL's - RawPath field in addition to its Path field. - In past releases, only the Path field was trimmed, and so if the - request URL contained any escaped characters the URL would be modified to - have mismatched Path and RawPath fields. - In Go 1.16, StripPrefix trims both fields. - If there are escaped characters in the prefix part of the request URL the - handler serves a 404 instead of its previous behavior of invoking the - underlying handler with a mismatched Path/RawPath pair. -

    - -

    - The net/http package now rejects HTTP range requests - of the form "Range": "bytes=--N" where "-N" is a negative suffix length, for - example "Range": "bytes=--2". It now replies with a 416 "Range Not Satisfiable" response. -

    - -

    - Cookies set with SameSiteDefaultMode - now behave according to the current spec (no attribute is set) instead of - generating a SameSite key without a value. -

    - -

    - The Client now sends - an explicit Content-Length: 0 - header in PATCH requests with empty bodies, - matching the existing behavior of POST and PUT. -

    - -

    - The ProxyFromEnvironment - function no longer returns the setting of the HTTP_PROXY - environment variable for https:// URLs when - HTTPS_PROXY is unset. -

    - -

    - The Transport - type has a new field - GetProxyConnectHeader - which may be set to a function that returns headers to send to a - proxy during a CONNECT request. - In effect GetProxyConnectHeader is a dynamic - version of the existing field - ProxyConnectHeader; - if GetProxyConnectHeader is not nil, - then ProxyConnectHeader is ignored. -

    - -

    - The new http.FS - function converts an fs.FS - to an http.FileSystem. -

    -
    -
    - -
    net/http/httputil
    -
    -

    - ReverseProxy - now flushes buffered data more aggressively when proxying - streamed responses with unknown body lengths. -

    -
    -
    - -
    net/smtp
    -
    -

    - The Client's - Mail - method now sends the SMTPUTF8 directive to - servers that support it, signaling that addresses are encoded in UTF-8. -

    -
    -
    - -
    os
    -
    -

    - Process.Signal now - returns ErrProcessDone - instead of the unexported errFinished when the process has - already finished. -

    - -

    - The package defines a new type - DirEntry - as an alias for fs.DirEntry. - The new ReadDir - function and the new - File.ReadDir - method can be used to read the contents of a directory into a - slice of DirEntry. - The File.Readdir - method (note the lower case d in dir) - still exists, returning a slice of - FileInfo, but for - most programs it will be more efficient to switch to - File.ReadDir. -

    - -

    - The package now defines - CreateTemp, - MkdirTemp, - ReadFile, and - WriteFile, - to be used instead of functions defined in the - io/ioutil package. -

    - -

    - The types FileInfo, - FileMode, and - PathError - are now aliases for types of the same name in the - io/fs package. - Function signatures in the os - package have been updated to refer to the names in the - io/fs package. - This should not affect any existing code. -

    - -

    - The new DirFS function - provides an implementation of - fs.FS backed by a tree - of operating system files. -

    -
    -
    - -
    os/signal
    -
    -

    - The new - NotifyContext - function allows creating contexts that are canceled upon arrival of - specific signals. -

    -
    -
    - -
    path
    -
    -

    - The Match function now - returns an error if the unmatched part of the pattern has a - syntax error. Previously, the function returned early on a failed - match, and thus did not report any later syntax error in the - pattern. -

    -
    -
    - -
    path/filepath
    -
    -

    - The new function - WalkDir - is similar to - Walk, - but is typically more efficient. - The function passed to WalkDir receives a - fs.DirEntry - instead of a - fs.FileInfo. - (To clarify for those who recall the Walk function - as taking an os.FileInfo, - os.FileInfo is now an alias for fs.FileInfo.) -

    - -

    - The Match and - Glob functions now - return an error if the unmatched part of the pattern has a - syntax error. Previously, the functions returned early on a failed - match, and thus did not report any later syntax error in the - pattern. -

    -
    -
    - -
    runtime/debug
    -
    -

    - The runtime.Error values - used when SetPanicOnFault is enabled may now have an - Addr method. If that method exists, it returns the memory - address that triggered the fault. -

    -
    -
    - -
    strconv
    -
    -

    - ParseFloat now uses - the Eisel-Lemire - algorithm, improving performance by up to a factor of 2. This can - also speed up decoding textual formats like encoding/json. -

    -
    -
    - -
    syscall
    -
    -

    - NewCallback - and - NewCallbackCDecl - now correctly support callback functions with multiple - sub-uintptr-sized arguments in a row. This may - require changing uses of these functions to eliminate manual - padding between small arguments. -

    - -

    - SysProcAttr on Windows has a new NoInheritHandles field that disables inheriting handles when creating a new process. -

    - -

    - DLLError on Windows now has an Unwrap method for unwrapping its underlying error. -

    - -

    - On Linux, - Setgid, - Setuid, - and related calls are now implemented. - Previously, they returned an syscall.EOPNOTSUPP error. -

    - -

    - On Linux, the new functions - AllThreadsSyscall - and AllThreadsSyscall6 - may be used to make a system call on all Go threads in the process. - These functions may only be used by programs that do not use cgo; - if a program uses cgo, they will always return - syscall.ENOTSUP. -

    -
    -
    - -
    testing/iotest
    -
    -

    - The new - ErrReader - function returns an - io.Reader that always - returns an error. -

    - -

    - The new - TestReader - function tests that an io.Reader - behaves correctly. -

    -
    -
    - -
    text/template
    -
    -

    - Newlines characters are now allowed inside action delimiters, - permitting actions to span multiple lines. -

    - -

    - The new template.ParseFS - function and template.Template.ParseFS - method are like template.ParseGlob - and template.Template.ParseGlob, - but read the templates from an fs.FS. -

    -
    -
    - -
    text/template/parse
    -
    -

    - A new CommentNode - was added to the parse tree. The Mode - field in the parse.Tree enables access to it. -

    -
    -
    - -
    time/tzdata
    -
    -

    - The slim timezone data format is now used for the timezone database in - $GOROOT/lib/time/zoneinfo.zip and the embedded copy in this - package. This reduces the size of the timezone database by about 350 KB. -

    -
    -
    - -
    unicode
    -
    -

    - The unicode package and associated - support throughout the system has been upgraded from Unicode 12.0.0 to - Unicode 13.0.0, - which adds 5,930 new characters, including four new scripts, and 55 new emoji. - Unicode 13.0.0 also designates plane 3 (U+30000-U+3FFFF) as the tertiary - ideographic plane. -

    -
    -
    diff --git a/doc/go1.17.html b/doc/go1.17.html new file mode 100644 index 0000000000..79cd4f7b61 --- /dev/null +++ b/doc/go1.17.html @@ -0,0 +1,84 @@ + + + + + + +

    DRAFT RELEASE NOTES — Introduction to Go 1.17

    + +

    + + Go 1.17 is not yet released. These are work-in-progress + release notes. Go 1.17 is expected to be released in August 2021. + +

    + +

    Changes to the language

    + +

    + TODO: complete this section +

    + +

    Ports

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Tools

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Go command

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Runtime

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Compiler

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Linker

    + +

    + TODO: complete this section, or delete if not needed +

    + +

    Core library

    + +

    + TODO: complete this section +

    + +

    Minor changes to the library

    + +

    + As always, there are various minor changes and updates to the library, + made with the Go 1 promise of compatibility + in mind. +

    + +

    + TODO: complete this section +

    -- GitLab From 0458d8c9830f80e8063c384bf4282843ed36a946 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 23 Feb 2021 12:47:08 -0800 Subject: [PATCH 0061/1298] go/types, types2: constraints may be parenthesized and that includes "any" Change-Id: I9a234cc1f04ca762375b51ec8ef009fb264c7ed1 Reviewed-on: https://go-review.googlesource.com/c/go/+/295689 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/decl.go | 2 +- src/cmd/compile/internal/types2/testdata/typeparams.go2 | 4 ++++ src/go/types/decl.go | 2 +- src/go/types/testdata/typeparams.go2 | 4 ++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 677172d40f..f0a037adb0 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -707,7 +707,7 @@ func (check *Checker) collectTypeParams(list []*syntax.Field) (tparams []*TypeNa // The predeclared identifier "any" is visible only as a constraint // in a type parameter list. Look for it before general constraint // resolution. - if tident, _ := f.Type.(*syntax.Name); tident != nil && tident.Value == "any" && check.lookup("any") == nil { + if tident, _ := unparen(f.Type).(*syntax.Name); tident != nil && tident.Value == "any" && check.lookup("any") == nil { bound = universeAny } else { bound = check.typ(f.Type) diff --git a/src/cmd/compile/internal/types2/testdata/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/typeparams.go2 index 04f563029f..41306b6e23 100644 --- a/src/cmd/compile/internal/types2/testdata/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/typeparams.go2 @@ -19,6 +19,10 @@ func _[_ any](x int) int func _[T any](T /* ERROR redeclared */ T)() func _[T, T /* ERROR redeclared */ any]() +// Constraints (incl. any) may be parenthesized. +func _[_ (any)]() {} +func _[_ (interface{})]() {} + func reverse[T any](list []T) []T { rlist := make([]T, len(list)) i := len(list) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index c97b1a66bb..1134607e92 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -726,7 +726,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam // The predeclared identifier "any" is visible only as a constraint // in a type parameter list. Look for it before general constraint // resolution. - if tident, _ := f.Type.(*ast.Ident); tident != nil && tident.Name == "any" && check.lookup("any") == nil { + if tident, _ := unparen(f.Type).(*ast.Ident); tident != nil && tident.Name == "any" && check.lookup("any") == nil { bound = universeAny } else { bound = check.typ(f.Type) diff --git a/src/go/types/testdata/typeparams.go2 b/src/go/types/testdata/typeparams.go2 index 2dd8f64dc0..bb7f016a83 100644 --- a/src/go/types/testdata/typeparams.go2 +++ b/src/go/types/testdata/typeparams.go2 @@ -19,6 +19,10 @@ func _[_ any](x int) int func _[T any](T /* ERROR redeclared */ T)() func _[T, T /* ERROR redeclared */ any]() +// Constraints (incl. any) may be parenthesized. +func _[_ (any)]() {} +func _[_ (interface{})]() {} + func reverse[T any](list []T) []T { rlist := make([]T, len(list)) i := len(list) -- GitLab From fbed561f8a596ddbd2bb599a17ea3c6e0b223602 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 23 Feb 2021 14:02:33 -0500 Subject: [PATCH 0062/1298] runtime: reset stack poison flag accidentally set See if this clears failure on openbsd-amd64-68 (ahem). Change-Id: Ifa60ef711a95e5de8ad91433ffa425f75b36c76f Reviewed-on: https://go-review.googlesource.com/c/go/+/295629 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/runtime/stack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stack.go b/src/runtime/stack.go index c572f7296f..d971e5e26f 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -112,7 +112,7 @@ const ( stackDebug = 0 stackFromSystem = 0 // allocate stacks from system memory instead of the heap stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free - stackPoisonCopy = 1 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy + stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy stackNoCache = 0 // disable per-P small stack caches // check the BP links during traceback. -- GitLab From aaed6cbced238030053df4e54f676a1d59df89d7 Mon Sep 17 00:00:00 2001 From: "Daniel S. Fava" Date: Fri, 12 Feb 2021 09:54:50 +0100 Subject: [PATCH 0063/1298] testing/race: fixing intermittent test failure Test NoRaceMutexPureHappensBefore in runtime/race/testdata/mutex_test.go expects the second spawned goroutine to run after the first. The test attempts to force this scheduling with a 10 millisecond wait. Following a suggestion by Bryan Mills, we force this scheduling using a shared variable whose access take place within the existing mutex. Fixes #35745. Change-Id: Ib23ec51492ecfeed4752e020401dd25755a669ed Reviewed-on: https://go-review.googlesource.com/c/go/+/291292 Reviewed-by: Bryan C. Mills Reviewed-by: Dmitry Vyukov Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/runtime/race/testdata/mutex_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/runtime/race/testdata/mutex_test.go b/src/runtime/race/testdata/mutex_test.go index cbed2d370c..9dbed9a2c9 100644 --- a/src/runtime/race/testdata/mutex_test.go +++ b/src/runtime/race/testdata/mutex_test.go @@ -78,16 +78,23 @@ func TestNoRaceMutexPureHappensBefore(t *testing.T) { var mu sync.Mutex var x int16 = 0 _ = x + written := false ch := make(chan bool, 2) go func() { x = 1 mu.Lock() + written = true mu.Unlock() ch <- true }() go func() { - <-time.After(1e5) + time.Sleep(100 * time.Microsecond) mu.Lock() + for !written { + mu.Unlock() + time.Sleep(100 * time.Microsecond) + mu.Lock() + } mu.Unlock() x = 1 ch <- true -- GitLab From 42b9e3a8dfb31f18829c45f0995cbf3c78fc90fb Mon Sep 17 00:00:00 2001 From: Keiichi Hirobe Date: Sun, 21 Feb 2021 12:22:13 +0900 Subject: [PATCH 0064/1298] context: fix XTestInterlockedCancels The test does not use Done channel, so fix that. Change-Id: I795feab2e95de815b8b6ee7a7fd90f19f7af7db1 Reviewed-on: https://go-review.googlesource.com/c/go/+/294749 Reviewed-by: Sameer Ajmani Trust: Sameer Ajmani Trust: Cody Oss Run-TryBot: Sameer Ajmani TryBot-Result: Go Bot --- src/context/context_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/context_test.go b/src/context/context_test.go index 6b392a29da..84eef01da1 100644 --- a/src/context/context_test.go +++ b/src/context/context_test.go @@ -525,7 +525,7 @@ func XTestInterlockedCancels(t testingT) { parent, cancelParent := WithCancel(Background()) child, cancelChild := WithCancel(parent) go func() { - parent.Done() + <-parent.Done() cancelChild() }() cancelParent() -- GitLab From 6cc8aa7ece96aca282db19f08aa5c98ed13695d9 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 23 Feb 2021 11:48:15 -0500 Subject: [PATCH 0065/1298] go/types: minor updates to comments to align with types2 Change-Id: Ic4fcd67cd9222eae6b72d9e91e37f3b0293b0b8d Reviewed-on: https://go-review.googlesource.com/c/go/+/295530 Reviewed-by: Robert Griesemer Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot --- src/go/types/conversions.go | 2 +- src/go/types/issues_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go index 69463f0ca6..d93ff465bb 100644 --- a/src/go/types/conversions.go +++ b/src/go/types/conversions.go @@ -142,7 +142,7 @@ func isUintptr(typ Type) bool { } func isUnsafePointer(typ Type) bool { - // TODO(gri): Is this asBasic() instead of typ.(*Basic) correct? + // TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct? // (The former calls under(), while the latter doesn't.) // The spec does not say so, but gc claims it is. See also // issue 6326. diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 9ed2934c74..a773a362c7 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -385,9 +385,9 @@ func TestIssue28005(t *testing.T) { } } if obj == nil { - t.Fatal("interface not found") + t.Fatal("object X not found") } - iface := obj.Type().Underlying().(*Interface) // I must be an interface + iface := obj.Type().Underlying().(*Interface) // object X 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. -- GitLab From 0694fb3d78f9ce2add154203dbd42a7a5a07c2da Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 10 Nov 2020 17:56:33 +0800 Subject: [PATCH 0066/1298] image: resolve the TODO of doc comment style Change-Id: Ic7701a9e4635fe1a331c9a1df776ed580759eb9d Reviewed-on: https://go-review.googlesource.com/c/go/+/268758 Reviewed-by: Nigel Tao Reviewed-by: Rob Pike Trust: Nigel Tao Trust: Alberto Donizetti Trust: Rob Pike --- src/image/jpeg/reader.go | 3 --- src/image/png/writer.go | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index 4a4706ffe7..b34072396c 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -14,9 +14,6 @@ import ( "io" ) -// TODO(nigeltao): fix up the doc comment style so that sentences start with -// the name of the type or function that they annotate. - // A FormatError reports that the input is not a valid JPEG. type FormatError string diff --git a/src/image/png/writer.go b/src/image/png/writer.go index 53adc1633c..cbcdb9e798 100644 --- a/src/image/png/writer.go +++ b/src/image/png/writer.go @@ -51,6 +51,7 @@ type encoder struct { bw *bufio.Writer } +// CompressionLevel indicates the compression level. type CompressionLevel int const ( -- GitLab From 37805292550e7144200b09320ffb61f21d421f8d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 25 Dec 2020 12:02:55 -0500 Subject: [PATCH 0067/1298] unicode: correctly handle negative runes Is and isExcludingLatin did not handle negative runes when dispatching to is16. TestNegativeRune covers this along with the existing uint32 casts in IsGraphic, etc. (For tests, I picked the smallest non-Latin-1 code point in each range.) Updates #43254 Change-Id: I17261b91f0d2b5b5125d19219411b45c480df74f Reviewed-on: https://go-review.googlesource.com/c/go/+/280493 Run-TryBot: Rob Pike TryBot-Result: Go Bot Reviewed-by: Rob Pike Trust: Emmanuel Odeke --- src/unicode/letter.go | 6 ++- src/unicode/letter_test.go | 79 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/unicode/letter.go b/src/unicode/letter.go index a57566f0a5..268e457a87 100644 --- a/src/unicode/letter.go +++ b/src/unicode/letter.go @@ -154,7 +154,8 @@ func is32(ranges []Range32, r uint32) bool { // Is reports whether the rune is in the specified table of ranges. func Is(rangeTab *RangeTable, r rune) bool { r16 := rangeTab.R16 - if len(r16) > 0 && r <= rune(r16[len(r16)-1].Hi) { + // Compare as uint32 to correctly handle negative runes. + if len(r16) > 0 && uint32(r) <= uint32(r16[len(r16)-1].Hi) { return is16(r16, uint16(r)) } r32 := rangeTab.R32 @@ -166,7 +167,8 @@ func Is(rangeTab *RangeTable, r rune) bool { func isExcludingLatin(rangeTab *RangeTable, r rune) bool { r16 := rangeTab.R16 - if off := rangeTab.LatinOffset; len(r16) > off && r <= rune(r16[len(r16)-1].Hi) { + // Compare as uint32 to correctly handle negative runes. + if off := rangeTab.LatinOffset; len(r16) > off && uint32(r) <= uint32(r16[len(r16)-1].Hi) { return is16(r16[off:], uint16(r)) } r32 := rangeTab.R32 diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go index 19ee535d57..a91e3a326f 100644 --- a/src/unicode/letter_test.go +++ b/src/unicode/letter_test.go @@ -563,3 +563,82 @@ func TestSpecialCaseNoMapping(t *testing.T) { t.Errorf("got %q; want %q", got, want) } } + +func TestNegativeRune(t *testing.T) { + // Issue 43254 + // These tests cover negative rune handling by testing values which, + // when cast to uint8 or uint16, look like a particular valid rune. + // This package has Latin-1-specific optimizations, so we test all of + // Latin-1 and representative non-Latin-1 values in the character + // categories covered by IsGraphic, etc. + nonLatin1 := []uint32{ + // Lu: LATIN CAPITAL LETTER A WITH MACRON + 0x0100, + // Ll: LATIN SMALL LETTER A WITH MACRON + 0x0101, + // Lt: LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON + 0x01C5, + // M: COMBINING GRAVE ACCENT + 0x0300, + // Nd: ARABIC-INDIC DIGIT ZERO + 0x0660, + // P: GREEK QUESTION MARK + 0x037E, + // S: MODIFIER LETTER LEFT ARROWHEAD + 0x02C2, + // Z: OGHAM SPACE MARK + 0x1680, + } + for i := 0; i < MaxLatin1+len(nonLatin1); i++ { + base := uint32(i) + if i >= MaxLatin1 { + base = nonLatin1[i-MaxLatin1] + } + + // Note r is negative, but uint8(r) == uint8(base) and + // uint16(r) == uint16(base). + r := rune(base - 1<<31) + if Is(Letter, r) { + t.Errorf("Is(Letter, 0x%x - 1<<31) = true, want false", base) + } + if IsControl(r) { + t.Errorf("IsControl(0x%x - 1<<31) = true, want false", base) + } + if IsDigit(r) { + t.Errorf("IsDigit(0x%x - 1<<31) = true, want false", base) + } + if IsGraphic(r) { + t.Errorf("IsGraphic(0x%x - 1<<31) = true, want false", base) + } + if IsLetter(r) { + t.Errorf("IsLetter(0x%x - 1<<31) = true, want false", base) + } + if IsLower(r) { + t.Errorf("IsLower(0x%x - 1<<31) = true, want false", base) + } + if IsMark(r) { + t.Errorf("IsMark(0x%x - 1<<31) = true, want false", base) + } + if IsNumber(r) { + t.Errorf("IsNumber(0x%x - 1<<31) = true, want false", base) + } + if IsPrint(r) { + t.Errorf("IsPrint(0x%x - 1<<31) = true, want false", base) + } + if IsPunct(r) { + t.Errorf("IsPunct(0x%x - 1<<31) = true, want false", base) + } + if IsSpace(r) { + t.Errorf("IsSpace(0x%x - 1<<31) = true, want false", base) + } + if IsSymbol(r) { + t.Errorf("IsSymbol(0x%x - 1<<31) = true, want false", base) + } + if IsTitle(r) { + t.Errorf("IsTitle(0x%x - 1<<31) = true, want false", base) + } + if IsUpper(r) { + t.Errorf("IsUpper(0x%x - 1<<31) = true, want false", base) + } + } +} -- GitLab From 43652dc46f770253b3603f47165b1568b439b0b5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 25 Dec 2020 12:02:04 -0500 Subject: [PATCH 0068/1298] bufio, bytes, strings: handle negative runes in WriteRune Updates #43254 Change-Id: I7d4bf3b99cc36ca2156af5bb01a1c595419d1d3c Reviewed-on: https://go-review.googlesource.com/c/go/+/280492 Reviewed-by: Emmanuel Odeke Reviewed-by: Rob Pike Trust: Emmanuel Odeke Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot --- src/bufio/bufio.go | 3 ++- src/bufio/bufio_test.go | 14 ++++++++++++++ src/bytes/buffer.go | 3 ++- src/bytes/buffer_test.go | 11 +++++++++++ src/strings/builder.go | 3 ++- src/strings/builder_test.go | 11 +++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go index 6baf9b9e40..ec928e7ad6 100644 --- a/src/bufio/bufio.go +++ b/src/bufio/bufio.go @@ -670,7 +670,8 @@ func (b *Writer) WriteByte(c byte) error { // WriteRune writes a single Unicode code point, returning // the number of bytes written and any error. func (b *Writer) WriteRune(r rune) (size int, err error) { - if r < utf8.RuneSelf { + // Compare as uint32 to correctly handle negative runes. + if uint32(r) < utf8.RuneSelf { err = b.WriteByte(byte(r)) if err != nil { return 0, err diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go index d7b34bd0d8..ebcc711db9 100644 --- a/src/bufio/bufio_test.go +++ b/src/bufio/bufio_test.go @@ -534,6 +534,20 @@ func TestReadWriteRune(t *testing.T) { } } +func TestWriteInvalidRune(t *testing.T) { + // Invalid runes, including negative ones, should be written as the + // replacement character. + for _, r := range []rune{-1, utf8.MaxRune + 1} { + var buf bytes.Buffer + w := NewWriter(&buf) + w.WriteRune(r) + w.Flush() + if s := buf.String(); s != "\uFFFD" { + t.Errorf("WriteRune(%d) wrote %q, not replacement character", r, s) + } + } +} + func TestReadStringAllocs(t *testing.T) { r := strings.NewReader(" foo foo 42 42 42 42 42 42 42 42 4.2 4.2 4.2 4.2\n") buf := NewReader(r) diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index f19a4cfff0..549b077708 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -275,7 +275,8 @@ func (b *Buffer) WriteByte(c byte) error { // included to match bufio.Writer's WriteRune. The buffer is grown as needed; // if it becomes too large, WriteRune will panic with ErrTooLarge. func (b *Buffer) WriteRune(r rune) (n int, err error) { - if r < utf8.RuneSelf { + // Compare as uint32 to correctly handle negative runes. + if uint32(r) < utf8.RuneSelf { b.WriteByte(byte(r)) return 1, nil } diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index fec5ef8a35..9c9b7440ff 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -6,6 +6,7 @@ package bytes_test import ( . "bytes" + "fmt" "io" "math/rand" "testing" @@ -387,6 +388,16 @@ func TestRuneIO(t *testing.T) { } } +func TestWriteInvalidRune(t *testing.T) { + // Invalid runes, including negative ones, should be written as + // utf8.RuneError. + for _, r := range []rune{-1, utf8.MaxRune + 1} { + var buf Buffer + buf.WriteRune(r) + check(t, fmt.Sprintf("TestWriteInvalidRune (%d)", r), &buf, "\uFFFD") + } +} + func TestNext(t *testing.T) { b := []byte{0, 1, 2, 3, 4} tmp := make([]byte, 5) diff --git a/src/strings/builder.go b/src/strings/builder.go index 6ff151d74b..547e52e84d 100644 --- a/src/strings/builder.go +++ b/src/strings/builder.go @@ -103,7 +103,8 @@ func (b *Builder) WriteByte(c byte) error { // It returns the length of r and a nil error. func (b *Builder) WriteRune(r rune) (int, error) { b.copyCheck() - if r < utf8.RuneSelf { + // Compare as uint32 to correctly handle negative runes. + if uint32(r) < utf8.RuneSelf { b.buf = append(b.buf, byte(r)) return 1, nil } diff --git a/src/strings/builder_test.go b/src/strings/builder_test.go index b662efe7a5..e3d239266f 100644 --- a/src/strings/builder_test.go +++ b/src/strings/builder_test.go @@ -8,6 +8,7 @@ import ( "bytes" . "strings" "testing" + "unicode/utf8" ) func check(t *testing.T, b *Builder, want string) { @@ -301,6 +302,16 @@ func TestBuilderCopyPanic(t *testing.T) { } } +func TestBuilderWriteInvalidRune(t *testing.T) { + // Invalid runes, including negative ones, should be written as + // utf8.RuneError. + for _, r := range []rune{-1, utf8.MaxRune + 1} { + var b Builder + b.WriteRune(r) + check(t, &b, "\uFFFD") + } +} + var someBytes = []byte("some bytes sdljlk jsklj3lkjlk djlkjw") var sinkS string -- GitLab From 6ba4a300d894b33fd8bf076dec08a5e3245d3a2c Mon Sep 17 00:00:00 2001 From: John Bampton Date: Wed, 17 Feb 2021 01:48:21 +0000 Subject: [PATCH 0069/1298] docs: fix spelling Change-Id: Ib689e5793d9cb372e759c4f34af71f004010c822 GitHub-Last-Rev: d63798388e5dcccb984689b0ae39b87453b97393 GitHub-Pull-Request: golang/go#44259 Reviewed-on: https://go-review.googlesource.com/c/go/+/291949 Reviewed-by: Emmanuel Odeke Reviewed-by: Ian Lance Taylor Trust: Matthew Dempsky Trust: Robert Griesemer --- src/cmd/compile/internal/ssa/value.go | 2 +- .../mod/example.com_split-incompatible_subpkg_v0.1.0.txt | 2 +- src/cmd/go/testdata/script/mod_empty_err.txt | 2 +- src/cmd/go/testdata/script/mod_outside.txt | 2 +- src/cmd/go/testdata/script/test_chatty_parallel_fail.txt | 2 +- src/cmd/go/testdata/script/test_chatty_parallel_success.txt | 2 +- .../testdata/script/test_chatty_parallel_success_sleepy.txt | 2 +- src/cmd/internal/archive/archive_test.go | 4 ++-- src/cmd/internal/goobj/objfile.go | 2 +- src/cmd/internal/obj/objfile.go | 4 ++-- src/cmd/internal/obj/pcln.go | 2 +- src/cmd/internal/obj/x86/asm6.go | 2 +- src/cmd/link/internal/ld/pcln.go | 4 ++-- src/cmd/link/internal/loader/loader.go | 2 +- src/crypto/tls/handshake_client_test.go | 6 +++--- src/internal/poll/copy_file_range_linux.go | 6 +++--- src/os/readfrom_linux_test.go | 6 +++--- src/runtime/chan_test.go | 4 ++-- src/runtime/lockrank_on.go | 2 +- src/runtime/metrics.go | 2 +- src/runtime/mgcscavenge.go | 2 +- test/prove.go | 2 +- 22 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index d000b7cce0..6539631b9c 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -484,7 +484,7 @@ func (v *Value) removeable() bool { if v.Type.IsMemory() { // All memory ops aren't needed here, but we do need // to keep calls at least (because they might have - // syncronization operations we can't see). + // synchronization operations we can't see). return false } if v.Op.HasSideEffects() { diff --git a/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt b/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt index 8f9e49176c..edf5d48788 100644 --- a/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt +++ b/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt @@ -1,6 +1,6 @@ Written by hand. Test case for getting a package that has been moved to a nested module, -with a +incompatible verison (and thus no go.mod file) at the root module. +with a +incompatible version (and thus no go.mod file) at the root module. -- .mod -- module example.com/split-incompatible/subpkg diff --git a/src/cmd/go/testdata/script/mod_empty_err.txt b/src/cmd/go/testdata/script/mod_empty_err.txt index 982e6b2e51..c4359bcccc 100644 --- a/src/cmd/go/testdata/script/mod_empty_err.txt +++ b/src/cmd/go/testdata/script/mod_empty_err.txt @@ -1,4 +1,4 @@ -# This test checks error messages for non-existant packages in module mode. +# This test checks error messages for non-existent packages in module mode. # Veries golang.org/issue/35414 env GO111MODULE=on cd $WORK diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt index 8f01b5d242..7b45f1a209 100644 --- a/src/cmd/go/testdata/script/mod_outside.txt +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -200,7 +200,7 @@ stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example go install cmd/addr2line ! stderr . -# 'go run' with a verison should fail due to syntax. +# 'go run' with a version should fail due to syntax. ! go run example.com/printversion@v1.0.0 stderr 'can only use path@version syntax with' diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt index 3f7360b659..3b2791cb89 100644 --- a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt +++ b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt @@ -14,7 +14,7 @@ stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"comma stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:38: error from sub-2\\n"}' -- chatty_parallel_test.go -- -package chatty_paralell_test +package chatty_parallel_test import ( "testing" diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt index 4a86d74f19..58b5ab7267 100644 --- a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt @@ -13,7 +13,7 @@ stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"comma stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:32: this is sub-2\\n"}' -- chatty_parallel_test.go -- -package chatty_paralell_test +package chatty_parallel_test import ( "testing" diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt index 5952a87bea..e651a7ed24 100644 --- a/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt @@ -5,7 +5,7 @@ go test -parallel 3 chatty_parallel_test.go -v stdout '--- PASS: TestFast \([0-9.]{4}s\)\n=== CONT TestSlow\n chatty_parallel_test.go:31: this is the second TestSlow log\n--- PASS: TestSlow \([0-9.]{4}s\)' -- chatty_parallel_test.go -- -package chatty_paralell_test +package chatty_parallel_test import ( "testing" diff --git a/src/cmd/internal/archive/archive_test.go b/src/cmd/internal/archive/archive_test.go index cb4eb842b4..c284a9cf0d 100644 --- a/src/cmd/internal/archive/archive_test.go +++ b/src/cmd/internal/archive/archive_test.go @@ -173,7 +173,7 @@ func TestParseGoobj(t *testing.T) { continue } if e.Type != EntryGoObj { - t.Errorf("wrong type of object: wnat EntryGoObj, got %v", e.Type) + t.Errorf("wrong type of object: want EntryGoObj, got %v", e.Type) } if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) @@ -204,7 +204,7 @@ func TestParseArchive(t *testing.T) { continue } if e.Type != EntryGoObj { - t.Errorf("wrong type of object: wnat EntryGoObj, got %v", e.Type) + t.Errorf("wrong type of object: want EntryGoObj, got %v", e.Type) } if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go index d1b838f676..247cc695f0 100644 --- a/src/cmd/internal/goobj/objfile.go +++ b/src/cmd/internal/goobj/objfile.go @@ -481,7 +481,7 @@ func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } -// Used to construct an artifically large array type when reading an +// Used to construct an artificially large array type when reading an // item from the object file relocs section or aux sym section (needs // to work on 32-bit as well as 64-bit). See issue 41621. const huge = (1<<31 - 1) / RelocSize diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 85f0570e5d..b031afbc36 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -383,7 +383,7 @@ func (w *writer) Sym(s *LSym) { func (w *writer) Hash64(s *LSym) { if !s.ContentAddressable() || len(s.R) != 0 { - panic("Hash of non-content-addresable symbol") + panic("Hash of non-content-addressable symbol") } b := contentHash64(s) w.Bytes(b[:]) @@ -391,7 +391,7 @@ func (w *writer) Hash64(s *LSym) { func (w *writer) Hash(s *LSym) { if !s.ContentAddressable() { - panic("Hash of non-content-addresable symbol") + panic("Hash of non-content-addressable symbol") } b := w.contentHash(s) w.Bytes(b[:]) diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go index 67c4f9a62b..7af81335fb 100644 --- a/src/cmd/internal/obj/pcln.go +++ b/src/cmd/internal/obj/pcln.go @@ -37,7 +37,7 @@ func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym, oldval := val fn := func_.Func() if fn.Text == nil { - // Return the emtpy symbol we've built so far. + // Return the empty symbol we've built so far. return sym } diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index a6b85ac4a0..fa670d5c18 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -1887,7 +1887,7 @@ func lookForJCC(p *obj.Prog) *obj.Prog { func fusedJump(p *obj.Prog) (bool, uint8) { var fusedSize uint8 - // The first instruction in a macro fused pair may be preceeded by the LOCK prefix, + // The first instruction in a macro fused pair may be preceded by the LOCK prefix, // or possibly an XACQUIRE/XRELEASE prefix followed by a LOCK prefix. If it is, we // need to be careful to insert any padding before the locks rather than directly after them. diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index fb733117be..61b64f4f5a 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -50,7 +50,7 @@ type pclntab struct { } // addGeneratedSym adds a generator symbol to pclntab, returning the new Sym. -// It is the caller's responsibilty to save they symbol in state. +// It is the caller's responsibility to save they symbol in state. func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym { size = Rnd(size, int64(ctxt.Arch.PtrSize)) state.size += size @@ -360,7 +360,7 @@ func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.Compilat // then not loading extra filenames), and just use the hash value of the // symbol name to do this cataloging. // - // TOOD: Store filenames as symbols. (Note this would be easiest if you + // TODO: Store filenames as symbols. (Note this would be easiest if you // also move strings to ALWAYS using the larger content addressable hash // function, and use that hash value for uniqueness testing.) cuEntries := make([]goobj.CUFileIndex, len(compUnits)) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 68dc3de273..c05309a141 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -1547,7 +1547,7 @@ func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit { // regular compiler-generated Go symbols), but in the case of // building with "-linkshared" (when a symbol is read from a // shared library), will hold the library name. -// NOTE: this correspondes to sym.Symbol.File field. +// NOTE: this corresponds to sym.Symbol.File field. func (l *Loader) SymPkg(i Sym) string { if f, ok := l.symPkg[i]; ok { return f diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 12b0254123..0e6c5a6370 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -1528,7 +1528,7 @@ func testVerifyConnection(t *testing.T, version uint16) { } if c.DidResume { return nil - // The SCTs and OCSP Responce are dropped on resumption. + // The SCTs and OCSP Response are dropped on resumption. // See http://golang.org/issue/39075. } if len(c.OCSPResponse) == 0 { @@ -1569,7 +1569,7 @@ func testVerifyConnection(t *testing.T, version uint16) { } if c.DidResume { return nil - // The SCTs and OCSP Responce are dropped on resumption. + // The SCTs and OCSP Response are dropped on resumption. // See http://golang.org/issue/39075. } if len(c.OCSPResponse) == 0 { @@ -1619,7 +1619,7 @@ func testVerifyConnection(t *testing.T, version uint16) { } if c.DidResume { return nil - // The SCTs and OCSP Responce are dropped on resumption. + // The SCTs and OCSP Response are dropped on resumption. // See http://golang.org/issue/39075. } if len(c.OCSPResponse) == 0 { diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go index 01b242a4ea..5b9e5d4020 100644 --- a/src/internal/poll/copy_file_range_linux.go +++ b/src/internal/poll/copy_file_range_linux.go @@ -78,7 +78,7 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // Go supports Linux >= 2.6.33, so the system call // may not be present. // - // If we see ENOSYS, we have certainly not transfered + // If we see ENOSYS, we have certainly not transferred // any data, so we can tell the caller that we // couldn't handle the transfer and let them fall // back to more generic code. @@ -91,13 +91,13 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // Prior to Linux 5.3, it was not possible to // copy_file_range across file systems. Similarly to // the ENOSYS case above, if we see EXDEV, we have - // not transfered any data, and we can let the caller + // not transferred any data, and we can let the caller // fall back to generic code. // // As for EINVAL, that is what we see if, for example, // dst or src refer to a pipe rather than a regular // file. This is another case where no data has been - // transfered, so we consider it unhandled. + // transferred, so we consider it unhandled. // // If src and dst are on CIFS, we can see EIO. // See issue #42334. diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go index 1d145dadb0..cb6a59abdb 100644 --- a/src/os/readfrom_linux_test.go +++ b/src/os/readfrom_linux_test.go @@ -106,7 +106,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") @@ -130,7 +130,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") @@ -162,7 +162,7 @@ func TestCopyFileRange(t *testing.T) { t.Fatal(err) } if n != int64(len(data)) { - t.Fatalf("transfered %d, want %d", n, len(data)) + t.Fatalf("transferred %d, want %d", n, len(data)) } if !hook.called { t.Fatalf("should have called poll.CopyFileRange") diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go index 756bbbeccf..003d6a9fb3 100644 --- a/src/runtime/chan_test.go +++ b/src/runtime/chan_test.go @@ -631,7 +631,7 @@ func TestNoShrinkStackWhileParking(t *testing.T) { // channel. See issue 40641 for more details on the problem. // // The way we try to induce this failure is to set up two - // goroutines: a sender and a reciever that communicate across + // goroutines: a sender and a receiver that communicate across // a channel. We try to set up a situation where the sender // grows its stack temporarily then *fully* blocks on a channel // often. Meanwhile a GC is triggered so that we try to get a @@ -671,7 +671,7 @@ func TestNoShrinkStackWhileParking(t *testing.T) { go send(c, done) // Wait a little bit before triggering // the GC to make sure the sender and - // reciever have gotten into their groove. + // receiver have gotten into their groove. time.Sleep(50 * time.Microsecond) runtime.GC() <-done diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go index 702bf5f24c..7d45debaca 100644 --- a/src/runtime/lockrank_on.go +++ b/src/runtime/lockrank_on.go @@ -220,7 +220,7 @@ func releaseLockRank(rank lockRank) { func lockWithRankMayAcquire(l *mutex, rank lockRank) { gp := getg() if gp.m.locksHeldLen == 0 { - // No possibilty of lock ordering problem if no other locks held + // No possibility of lock ordering problem if no other locks held return } diff --git a/src/runtime/metrics.go b/src/runtime/metrics.go index 3e8dbda0ca..ce3bac9d8f 100644 --- a/src/runtime/metrics.go +++ b/src/runtime/metrics.go @@ -481,7 +481,7 @@ func readMetrics(samplesp unsafe.Pointer, len int, cap int) { // Acquire the metricsSema but with handoff. This operation // is expensive enough that queueing up goroutines and handing - // off between them will be noticably better-behaved. + // off between them will be noticeably better-behaved. semacquire1(&metricsSema, true, 0, 0) // Ensure the map is initialized. diff --git a/src/runtime/mgcscavenge.go b/src/runtime/mgcscavenge.go index a7c5bc49b8..46a40632bf 100644 --- a/src/runtime/mgcscavenge.go +++ b/src/runtime/mgcscavenge.go @@ -207,7 +207,7 @@ func wakeScavenger() { // Ready the goroutine by injecting it. We use injectglist instead // of ready or goready in order to allow us to run this function // without a P. injectglist also avoids placing the goroutine in - // the current P's runnext slot, which is desireable to prevent + // the current P's runnext slot, which is desirable to prevent // the scavenger from interfering with user goroutine scheduling // too much. var list gList diff --git a/test/prove.go b/test/prove.go index af9c06a6f7..83b0380838 100644 --- a/test/prove.go +++ b/test/prove.go @@ -1013,7 +1013,7 @@ func sh64noopt(n int64) int64 { // opt, an earlier pass, has already replaced it. // The fix for this issue allows prove to zero a right shift that was added as // part of the less-than-optimal reqwrite. That change by prove then allows -// lateopt to clean up all the unneccesary parts of the original division +// lateopt to clean up all the unnecessary parts of the original division // replacement. See issue #36159. func divShiftClean(n int) int { if n < 0 { -- GitLab From 084b07d6f6104bf9585ffe71fc2477046102c1da Mon Sep 17 00:00:00 2001 From: DQNEO Date: Wed, 10 Feb 2021 22:34:09 +0900 Subject: [PATCH 0070/1298] spec: improve sentence structure for passing a slice Change-Id: I453d06da2f596eb0b99905aec46a05547d73c62c Reviewed-on: https://go-review.googlesource.com/c/go/+/290872 Trust: Emmanuel Odeke Trust: Robert Griesemer Trust: Ian Lance Taylor Reviewed-by: Robert Griesemer Reviewed-by: Rob Pike --- doc/go_spec.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e22fabd699..2a1322fb0f 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -3532,9 +3532,9 @@ within Greeting, who will have the value

    -If the final argument is assignable to a slice type []T, it is -passed unchanged as the value for a ...T parameter if the argument -is followed by .... In this case no new slice is created. +If the final argument is assignable to a slice type []T and +is followed by ..., it is passed unchanged as the value +for a ...T parameter. In this case no new slice is created.

    -- GitLab From eb863240dcc857b4207b06eb33385446696b7b1c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 23 Feb 2021 15:35:43 +0100 Subject: [PATCH 0071/1298] runtime: remove unused const stackSystem on dragonfly Change-Id: I778c2bd7cf0b12275bae344cb2130a7959500481 Reviewed-on: https://go-review.googlesource.com/c/go/+/295470 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/runtime/os_dragonfly.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index b786c8ab5f..2e930b6e94 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -65,8 +65,6 @@ func setNonblock(fd int32) func pipe() (r, w int32, errno int32) -const stackSystem = 0 - // From DragonFly's const ( _CTL_HW = 6 -- GitLab From 35b80eac7d2ba6cd632b3dc195f8588d95212fbf Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sun, 14 Feb 2021 11:19:39 +0100 Subject: [PATCH 0072/1298] hash/maphash: remove duplicate from Hash documentation Fixes #44255 Change-Id: I14d2edbee0a0c39e04111414a57d70ee2fdfb6af Reviewed-on: https://go-review.googlesource.com/c/go/+/291631 Trust: Alberto Donizetti Reviewed-by: Keith Randall --- src/hash/maphash/maphash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash/maphash/maphash.go b/src/hash/maphash/maphash.go index ecc147d599..f7ef1b41e8 100644 --- a/src/hash/maphash/maphash.go +++ b/src/hash/maphash/maphash.go @@ -34,7 +34,7 @@ type Seed struct { // // The zero Hash is a valid Hash ready to use. // A zero Hash chooses a random seed for itself during -// the first call to a Reset, Write, Seed, Sum64, or Seed method. +// the first call to a Reset, Write, Seed, or Sum64 method. // For control over the seed, use SetSeed. // // The computed hash values depend only on the initial seed and -- GitLab From 26001d109ed3da33c728b96e547fa380c7e2a300 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 23 Feb 2021 12:01:26 -0500 Subject: [PATCH 0073/1298] go/types: review of call.go The changes from the (reviewed) dev.regabi copy of call.go can be seen by comparing patchset 1 and 4. The actual changes are removing the "// REVIEW INCOMPLETE" marker, deleting some leftover handling of type instantiation in Checker.call, and adding a comment that exprOrTypeList should be refactored. I started to refactor exprOrTypeList, but thought it best to mark this code as reviewed before diverging from types2. Change-Id: Icf7fbff5a8def49c5f1781472fd7ba7b73dd9a9c Reviewed-on: https://go-review.googlesource.com/c/go/+/295531 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/call.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/go/types/call.go b/src/go/types/call.go index b502122a26..e56f741370 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -1,4 +1,3 @@ -// REVIEW INCOMPLETE // Copyright 2013 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. @@ -114,19 +113,9 @@ func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind { return statement case typexpr: - // conversion or type instantiation + // conversion T := x.typ x.mode = invalid - if isGeneric(T) { - // type instantiation - x.typ = check.typ(call) - if x.typ != Typ[Invalid] { - x.mode = typexpr - } - return expression - } - - // conversion switch n := len(call.Args); n { case 0: check.errorf(inNode(call, call.Rparen), _WrongArgCount, "missing argument in conversion to %s", T) @@ -217,6 +206,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind { // exprOrTypeList returns a list of operands and reports an error if the // list contains a mix of values and types (ignoring invalid operands). +// TODO(rFindley) Now we can split this into exprList and typeList. func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand, ok bool) { ok = true @@ -437,8 +427,6 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper } // check arguments - // TODO(gri) Possible optimization (may be tricky): We could avoid - // checking arguments from which we inferred type arguments. for i, a := range args { check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun)) } -- GitLab From e49612089196be102b4b7f86c417b8cfba2521aa Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 1 Feb 2021 08:35:36 -0800 Subject: [PATCH 0074/1298] database: remove race in TestTxContextWait This test contained a data race. On line 437, db.BeginTx starts a goroutine that runs tx.awaitDone, which reads tx.keepConnOnRollback. On line 445, the test writes to tx.keepConnOnRollback. tx.awaitDone waits on ctx, but because ctx is timeout-based, there's no ordering guarantee between the write and the read. The race detector never caught this before because the context package implementation of Done contained enough synchronization to make it safe. That synchronization is not package of the context API or guarantees, and the first several releases it was not present. Another commit soon will remove that synchronization, exposing the latent data race. To fix the race, emulate a time-based context using an explicit cancellation-based context. This gives us enough control to avoid the race. Change-Id: I103fe9b987b1d4c02e7a20ac3c22a682652128b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/288493 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Daniel Theophanes --- src/database/sql/sql_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index c968852ade..99bfd62491 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -431,25 +431,24 @@ func TestTxContextWait(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Millisecond) - defer cancel() + ctx, cancel := context.WithCancel(context.Background()) tx, err := db.BeginTx(ctx, nil) if err != nil { - // Guard against the context being canceled before BeginTx completes. - if err == context.DeadlineExceeded { - t.Skip("tx context canceled prior to first use") - } t.Fatal(err) } tx.keepConnOnRollback = false + go func() { + time.Sleep(15 * time.Millisecond) + cancel() + }() // This will trigger the *fakeConn.Prepare method which will take time // performing the query. The ctxDriverPrepare func will check the context // after this and close the rows and return an error. _, err = tx.QueryContext(ctx, "WAIT|1s|SELECT|people|age,name|") - if err != context.DeadlineExceeded { - t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err) + if err != context.Canceled { + t.Fatalf("expected QueryContext to error with context canceled but returned %v", err) } waitForFree(t, db, 5*time.Second, 0) -- GitLab From 04edf418d285df410745118aae756f9e0a9a00f5 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 18 Nov 2020 12:50:29 -0800 Subject: [PATCH 0075/1298] encoding/json: reduce allocated space in Unmarshal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The decodeState type is a large part of the allocated space during Unmarshal. The errorContext field is infrequently used, and only on error. Extract it into a pointer and allocate it separate when necessary. name old time/op new time/op delta UnmarshalString-8 115ns ± 5% 114ns ± 3% ~ (p=0.170 n=15+15) UnmarshalFloat64-8 113ns ± 2% 106ns ± 1% -6.42% (p=0.000 n=15+14) UnmarshalInt64-8 93.3ns ± 1% 86.9ns ± 4% -6.89% (p=0.000 n=14+15) name old alloc/op new alloc/op delta UnmarshalString-8 192B ± 0% 160B ± 0% -16.67% (p=0.000 n=15+15) UnmarshalFloat64-8 180B ± 0% 148B ± 0% -17.78% (p=0.000 n=15+15) UnmarshalInt64-8 176B ± 0% 144B ± 0% -18.18% (p=0.000 n=15+15) name old allocs/op new allocs/op delta UnmarshalString-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) UnmarshalFloat64-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) UnmarshalInt64-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Change-Id: I53f3f468e6c65f77a12e5138a2626455b197012d Reviewed-on: https://go-review.googlesource.com/c/go/+/271338 Trust: Josh Bleecher Snyder Trust: Daniel Martí Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Daniel Martí --- src/encoding/json/decode.go | 51 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 86d8a69db7..a9917e72c7 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -200,16 +200,19 @@ func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64) } +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + // decodeState represents the state while decoding a JSON value. type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - FieldStack []string - } + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext savedError error useNumber bool disallowUnknownFields bool @@ -229,10 +232,11 @@ func (d *decodeState) init(data []byte) *decodeState { d.data = data d.off = 0 d.savedError = nil - d.errorContext.Struct = nil - - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } return d } @@ -246,12 +250,11 @@ func (d *decodeState) saveError(err error) { // addErrorContext returns a new error enhanced with information from d.errorContext func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { switch err := err.(type) { case *UnmarshalTypeError: err.Struct = d.errorContext.Struct.Name() err.Field = strings.Join(d.errorContext.FieldStack, ".") - return err } } return err @@ -657,7 +660,10 @@ func (d *decodeState) object(v reflect.Value) error { } var mapElem reflect.Value - origErrorContext := d.errorContext + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } for { // Read opening " of string key or closing }. @@ -732,6 +738,9 @@ func (d *decodeState) object(v reflect.Value) error { } subv = subv.Field(i) } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) d.errorContext.Struct = t } else if d.disallowUnknownFields { @@ -812,11 +821,13 @@ func (d *decodeState) object(v reflect.Value) error { if d.opcode == scanSkipSpace { d.scanWhile(scanSkipSpace) } - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } if d.opcode == scanEndObject { break } -- GitLab From 07c658316b411a4b0e71a3a7e78b970b091795ab Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 21 Jan 2021 16:59:29 -0800 Subject: [PATCH 0076/1298] io/ioutil: forward TempFile and TempDir to os package For #42026 Fixes #44311 Change-Id: I3dabcf902d155f95800b4adf1d7578906a194ce6 Reviewed-on: https://go-review.googlesource.com/c/go/+/285378 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/io/ioutil/export_test.go | 7 --- src/io/ioutil/tempfile.go | 108 ++------------------------------- src/io/ioutil/tempfile_test.go | 13 ++-- 3 files changed, 13 insertions(+), 115 deletions(-) delete mode 100644 src/io/ioutil/export_test.go diff --git a/src/io/ioutil/export_test.go b/src/io/ioutil/export_test.go deleted file mode 100644 index dff55f07e2..0000000000 --- a/src/io/ioutil/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2020 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 ioutil - -var ErrPatternHasSeparator = errPatternHasSeparator diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go index af7c6fd7c1..4b272e5a5d 100644 --- a/src/io/ioutil/tempfile.go +++ b/src/io/ioutil/tempfile.go @@ -5,38 +5,9 @@ package ioutil import ( - "errors" "os" - "path/filepath" - "strconv" - "strings" - "sync" - "time" ) -// Random number state. -// We generate random temporary file names so that there's a good -// chance the file doesn't exist yet - keeps the number of tries in -// TempFile to a minimum. -var rand uint32 -var randmu sync.Mutex - -func reseed() uint32 { - return uint32(time.Now().UnixNano() + int64(os.Getpid())) -} - -func nextRandom() string { - randmu.Lock() - r := rand - if r == 0 { - r = reseed() - } - r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r - randmu.Unlock() - return strconv.Itoa(int(1e9 + r%1e9))[1:] -} - // TempFile creates a new temporary file in the directory dir, // opens the file for reading and writing, and returns the resulting *os.File. // The filename is generated by taking pattern and adding a random @@ -48,48 +19,10 @@ func nextRandom() string { // will not choose the same file. The caller can use f.Name() // to find the pathname of the file. It is the caller's responsibility // to remove the file when no longer needed. +// +// As of Go 1.16, this function simply calls os.CreateTemp. func TempFile(dir, pattern string) (f *os.File, err error) { - if dir == "" { - dir = os.TempDir() - } - - prefix, suffix, err := prefixAndSuffix(pattern) - if err != nil { - return - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - name := filepath.Join(dir, prefix+nextRandom()+suffix) - f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - break - } - return -} - -var errPatternHasSeparator = errors.New("pattern contains path separator") - -// prefixAndSuffix splits pattern by the last wildcard "*", if applicable, -// returning prefix as the part before "*" and suffix as the part after "*". -func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { - if strings.ContainsRune(pattern, os.PathSeparator) { - err = errPatternHasSeparator - return - } - if pos := strings.LastIndex(pattern, "*"); pos != -1 { - prefix, suffix = pattern[:pos], pattern[pos+1:] - } else { - prefix = pattern - } - return + return os.CreateTemp(dir, pattern) } // TempDir creates a new temporary directory in the directory dir. @@ -101,37 +34,8 @@ func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { // Multiple programs calling TempDir simultaneously // will not choose the same directory. It is the caller's responsibility // to remove the directory when no longer needed. +// +// As of Go 1.16, this function simply calls os.MkdirTemp. func TempDir(dir, pattern string) (name string, err error) { - if dir == "" { - dir = os.TempDir() - } - - prefix, suffix, err := prefixAndSuffix(pattern) - if err != nil { - return - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - try := filepath.Join(dir, prefix+nextRandom()+suffix) - err = os.Mkdir(try, 0700) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - if os.IsNotExist(err) { - if _, err := os.Stat(dir); os.IsNotExist(err) { - return "", err - } - } - if err == nil { - name = try - } - break - } - return + return os.MkdirTemp(dir, pattern) } diff --git a/src/io/ioutil/tempfile_test.go b/src/io/ioutil/tempfile_test.go index 440c7cffc6..5cef18c33b 100644 --- a/src/io/ioutil/tempfile_test.go +++ b/src/io/ioutil/tempfile_test.go @@ -50,6 +50,9 @@ func TestTempFile_pattern(t *testing.T) { } } +// This string is from os.errPatternHasSeparator. +const patternHasSeparator = "pattern contains path separator" + func TestTempFile_BadPattern(t *testing.T) { tmpDir, err := TempDir("", t.Name()) if err != nil { @@ -81,9 +84,8 @@ func TestTempFile_BadPattern(t *testing.T) { if tt.wantErr { if err == nil { t.Errorf("Expected an error for pattern %q", tt.pattern) - } - if g, w := err, ErrPatternHasSeparator; g != w { - t.Errorf("Error mismatch: got %#v, want %#v for pattern %q", g, w, tt.pattern) + } else if !strings.Contains(err.Error(), patternHasSeparator) { + t.Errorf("Error mismatch: got %#v, want %q for pattern %q", err, patternHasSeparator, tt.pattern) } } else if err != nil { t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern) @@ -183,9 +185,8 @@ func TestTempDir_BadPattern(t *testing.T) { if tt.wantErr { if err == nil { t.Errorf("Expected an error for pattern %q", tt.pattern) - } - if g, w := err, ErrPatternHasSeparator; g != w { - t.Errorf("Error mismatch: got %#v, want %#v for pattern %q", g, w, tt.pattern) + } else if !strings.Contains(err.Error(), patternHasSeparator) { + t.Errorf("Error mismatch: got %#v, want %q for pattern %q", err, patternHasSeparator, tt.pattern) } } else if err != nil { t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern) -- GitLab From b97b1456aed5915f7633f16e573b4912140ee8e9 Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Tue, 9 Jun 2020 04:09:58 +0000 Subject: [PATCH 0077/1298] cmd/go, cmd/cgo: pass -mfp32 and -mhard/soft-float to MIPS GCC For mips32 currently, we are using FP32, while the gcc may be FPXX, which may generate .MIPS.abiflags and .gnu.attributes section with value as FPXX. So the kernel will treat the exe as FPXX, and may choose to use FR=1 FPU mode for it. Currently, in Go, we use 2 lwc1 to load both half of a double value to a pair of even-odd FPR. This behavior can only work with FR=0 mode. In FR=1 mode, all of 32 FPR are 64bit. If we lwc1 the high-half of a double value to an odd FPR, and try to use the previous even FPR to compute, the real high-half of even FPR will be unpredicatable. We set -mfp32 to force the gcc generate FP32 code and section value. More details about FP32/FPXX/FP64 are explained in: https://web.archive.org/web/20180828210612/https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking When GOMIPS/GOMIPS64 is set as softfloat, we should also pass -msoft-float to gcc. Here we also add -mno-odd-spreg option, since Loongson's CPU cannot use odd-number FR in FR=0 mode. Fixes #39435 Change-Id: I54026ad416a815fe43a9261ebf6d02e5519c3930 Reviewed-on: https://go-review.googlesource.com/c/go/+/237058 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Trust: Meng Zhuo --- src/cmd/cgo/gcc.go | 12 ++++++++++-- src/cmd/cgo/main.go | 4 +++- src/cmd/go/internal/work/exec.go | 14 ++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index b5e28e3254..775f20b09f 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1566,9 +1566,17 @@ func (p *Package) gccMachine() []string { case "s390x": return []string{"-m64"} case "mips64", "mips64le": - return []string{"-mabi=64"} + if gomips64 == "hardfloat" { + return []string{"-mabi=64", "-mhard-float"} + } else if gomips64 == "softfloat" { + return []string{"-mabi=64", "-msoft-float"} + } case "mips", "mipsle": - return []string{"-mabi=32"} + if gomips == "hardfloat" { + return []string{"-mabi=32", "-mfp32", "-mhard-float", "-mno-odd-spreg"} + } else if gomips == "softfloat" { + return []string{"-mabi=32", "-msoft-float"} + } } return nil } diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index c1116e28ec..5767c54307 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -245,7 +245,7 @@ var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code") var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths") -var goarch, goos string +var goarch, goos, gomips, gomips64 string func main() { objabi.AddVersionFlag() // -V @@ -405,6 +405,8 @@ func newPackage(args []string) *Package { if s := os.Getenv("GOOS"); s != "" { goos = s } + gomips = objabi.GOMIPS + gomips64 = objabi.GOMIPS64 ptrSize := ptrSizeMap[goarch] if ptrSize == 0 { fatalf("unknown ptrSize for $GOARCH %q", goarch) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index d957fa1fcd..3980c5f898 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -2599,9 +2599,19 @@ func (b *Builder) gccArchArgs() []string { case "s390x": return []string{"-m64", "-march=z196"} case "mips64", "mips64le": - return []string{"-mabi=64"} + args := []string{"-mabi=64"} + if cfg.GOMIPS64 == "hardfloat" { + return append(args, "-mhard-float") + } else if cfg.GOMIPS64 == "softfloat" { + return append(args, "-msoft-float") + } case "mips", "mipsle": - return []string{"-mabi=32", "-march=mips32"} + args := []string{"-mabi=32", "-march=mips32"} + if cfg.GOMIPS == "hardfloat" { + return append(args, "-mhard-float", "-mfp32", "-mno-odd-spreg") + } else if cfg.GOMIPS == "softfloat" { + return append(args, "-msoft-float") + } case "ppc64": if cfg.Goos == "aix" { return []string{"-maix64"} -- GitLab From 691ac806d20616fab66bb50752edfa9e4e9f8151 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 22 Feb 2021 15:05:20 -0500 Subject: [PATCH 0078/1298] cmd/go: fix version validation in 'go mod edit -exclude' The fix is to pull in CL 295089 from the x/mod repo. Fixes #44497 Change-Id: I008b58d0f4bb48c09d4f1e6ed31d11a714f87dc0 Reviewed-on: https://go-review.googlesource.com/c/go/+/295150 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod Reviewed-by: Michael Matloob --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 3 +- src/cmd/go/testdata/script/mod_edit.txt | 27 +++----- .../vendor/golang.org/x/mod/modfile/rule.go | 65 +++++++++++++------ src/cmd/vendor/modules.txt | 2 +- 5 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 24ad6c2432..3c90dca491 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.1 + golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index e9b62f46e1..498b92207f 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -13,8 +13,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 h1:ETedWdSKv0zHgSxvhXszxH25fCWwA6olYCPu9ehlVKs= +golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt index 02d2d40bbb..9da69306da 100644 --- a/src/cmd/go/testdata/script/mod_edit.txt +++ b/src/cmd/go/testdata/script/mod_edit.txt @@ -16,9 +16,9 @@ cmpenv go.mod $WORK/go.mod.init cmpenv go.mod $WORK/go.mod.init # go mod edits -go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 +go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 cmpenv go.mod $WORK/go.mod.edit1 -go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] +go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] cmpenv go.mod $WORK/go.mod.edit2 # -exclude and -retract reject invalid versions. @@ -26,25 +26,17 @@ cmpenv go.mod $WORK/go.mod.edit2 stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$' ! go mod edit -retract=bad stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$' -cmpenv go.mod $WORK/go.mod.edit2 -cp go.mod go.mod.beforebugs +! go mod edit -exclude=example.com/m@v2.0.0 +stderr '^go mod: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$' -# BUG(#44497): -exclude accepts a mismatched major version without +incompatible, but should not. -go mod edit -exclude=example.com/m@v2.0.0 -! go mod edit -json -stderr '^go: errors parsing go.mod:\n.*[/\\]go.mod:16: exclude example\.com/m: version "v2\.0\.0" invalid: should be v0 or v1, not v2$' -cp go.mod.beforebugs go.mod +! go mod edit -exclude=example.com/m/v2@v1.0.0 +stderr '^go mod: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$' -# BUG(#44497): -exclude accepts a v1 version for a v2 module, but should not. -go mod edit -exclude=example.com/m/v2@v1.0.0 -! go mod edit -json -stderr '^go: errors parsing go.mod:\n.*[/\\]go.mod:16: exclude example\.com/m/v2: version "v1\.0\.0" invalid: should be v2, not v1$' -cp go.mod.beforebugs go.mod +! go mod edit -exclude=gopkg.in/example.v1@v2.0.0 +stderr '^go mod: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$' -# BUG(#44497): -exclude rejects a +incompatible version for an unversioned -# module path, but should not. -! go mod edit -exclude=example.com/m@v2.0.0+incompatible +cmpenv go.mod $WORK/go.mod.edit2 # go mod edit -json go mod edit -json @@ -107,6 +99,7 @@ require x.1 v1.0.0 exclude ( x.1 v1.2.0 x.1 v1.2.1 + x.1 v2.0.0+incompatible ) replace ( diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index c6a189dbe0..8fcf96b713 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -835,11 +835,8 @@ func (f *File) DropRequire(path string) error { // AddExclude adds a exclude statement to the mod file. Errors if the provided // version is not a canonical version string func (f *File) AddExclude(path, vers string) error { - if !isCanonicalVersion(vers) { - return &module.InvalidVersionError{ - Version: vers, - Err: errors.New("must be of the form v1.2.3"), - } + if err := checkCanonicalVersion(path, vers); err != nil { + return err } var hint *Line @@ -916,17 +913,15 @@ func (f *File) DropReplace(oldPath, oldVers string) error { // AddRetract adds a retract statement to the mod file. Errors if the provided // version interval does not consist of canonical version strings func (f *File) AddRetract(vi VersionInterval, rationale string) error { - if !isCanonicalVersion(vi.High) { - return &module.InvalidVersionError{ - Version: vi.High, - Err: errors.New("must be of the form v1.2.3"), - } + var path string + if f.Module != nil { + path = f.Module.Mod.Path } - if !isCanonicalVersion(vi.Low) { - return &module.InvalidVersionError{ - Version: vi.Low, - Err: errors.New("must be of the form v1.2.3"), - } + if err := checkCanonicalVersion(path, vi.High); err != nil { + return err + } + if err := checkCanonicalVersion(path, vi.Low); err != nil { + return err } r := &Retract{ @@ -1086,8 +1081,40 @@ func lineRetractLess(li, lj *Line) bool { return semver.Compare(vii.High, vij.High) > 0 } -// isCanonicalVersion tests if the provided version string represents a valid -// canonical version. -func isCanonicalVersion(vers string) bool { - return vers != "" && semver.Canonical(vers) == vers +// checkCanonicalVersion returns a non-nil error if vers is not a canonical +// version string or does not match the major version of path. +// +// If path is non-empty, the error text suggests a format with a major version +// corresponding to the path. +func checkCanonicalVersion(path, vers string) error { + _, pathMajor, pathMajorOk := module.SplitPathVersion(path) + + if vers == "" || vers != module.CanonicalVersion(vers) { + if pathMajor == "" { + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form v1.2.3"), + } + } + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form %s.2.3", module.PathMajorPrefix(pathMajor)), + } + } + + if pathMajorOk { + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + if pathMajor == "" { + // In this context, the user probably wrote "v2.3.4" when they meant + // "v2.3.4+incompatible". Suggest that instead of "v0 or v1". + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("should be %s+incompatible (or module %s/%v)", vers, path, semver.Major(vers)), + } + } + return err + } + } + + return nil } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index abe70ae87e..254cff70dd 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.1 +# golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile -- GitLab From ae1fa08e4138c49c8e7fa10c3eadbfca0233842b Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 29 Jan 2021 15:41:18 -0800 Subject: [PATCH 0079/1298] context: reduce contention in cancelCtx.Done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use an atomic.Value to hold the done channel. Conveniently, we have a mutex handy to coordinate writes to it. name old time/op new time/op delta ContextCancelDone-8 67.5ns ±10% 2.2ns ±11% -96.74% (p=0.000 n=30+28) Fixes #42564 Change-Id: I5d72e0e87fb221d4e230209e5fb4698bea4053c6 Reviewed-on: https://go-review.googlesource.com/c/go/+/288193 Trust: Josh Bleecher Snyder Trust: Sameer Ajmani Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/context/benchmark_test.go | 15 +++++++++++++++ src/context/context.go | 30 +++++++++++++++++------------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/context/benchmark_test.go b/src/context/benchmark_test.go index 5d56863050..c4c72f00f8 100644 --- a/src/context/benchmark_test.go +++ b/src/context/benchmark_test.go @@ -5,6 +5,7 @@ package context_test import ( + "context" . "context" "fmt" "runtime" @@ -138,3 +139,17 @@ func BenchmarkCheckCanceled(b *testing.B) { } }) } + +func BenchmarkContextCancelDone(b *testing.B) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + select { + case <-ctx.Done(): + default: + } + } + }) +} diff --git a/src/context/context.go b/src/context/context.go index b3fdb8277a..733c5f56d9 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -303,10 +303,8 @@ func parentCancelCtx(parent Context) (*cancelCtx, bool) { if !ok { return nil, false } - p.mu.Lock() - ok = p.done == done - p.mu.Unlock() - if !ok { + pdone, _ := p.done.Load().(chan struct{}) + if pdone != done { return nil, false } return p, true @@ -345,7 +343,7 @@ type cancelCtx struct { Context mu sync.Mutex // protects following fields - done chan struct{} // created lazily, closed by first cancel call + done atomic.Value // of chan struct{}, created lazily, closed by first cancel call children map[canceler]struct{} // set to nil by the first cancel call err error // set to non-nil by the first cancel call } @@ -358,13 +356,18 @@ func (c *cancelCtx) Value(key interface{}) interface{} { } func (c *cancelCtx) Done() <-chan struct{} { + d := c.done.Load() + if d != nil { + return d.(chan struct{}) + } c.mu.Lock() - if c.done == nil { - c.done = make(chan struct{}) + defer c.mu.Unlock() + d = c.done.Load() + if d == nil { + d = make(chan struct{}) + c.done.Store(d) } - d := c.done - c.mu.Unlock() - return d + return d.(chan struct{}) } func (c *cancelCtx) Err() error { @@ -401,10 +404,11 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) { return // already canceled } c.err = err - if c.done == nil { - c.done = closedchan + d, _ := c.done.Load().(chan struct{}) + if d == nil { + c.done.Store(closedchan) } else { - close(c.done) + close(d) } for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. -- GitLab From 27684ea195641ead8a8f08cb345925da889a12ed Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 Jan 2021 14:38:55 -0800 Subject: [PATCH 0080/1298] testing: print late arriving log line in panic When you log after a test has completed, the testing package panics. Print the logged line as part of that panic, to aid in debugging. Change-Id: I3d6689d1eed57c03e300afe37db0c15b2f4acda4 Reviewed-on: https://go-review.googlesource.com/c/go/+/283972 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/testing/sub_test.go | 2 +- src/testing/testing.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go index 5b226f85ad..6c7d83aac2 100644 --- a/src/testing/sub_test.go +++ b/src/testing/sub_test.go @@ -822,7 +822,7 @@ func TestLogAfterComplete(t *T) { c2 <- fmt.Sprintf("subtest panic with unexpected value %v", p) return } - const want = "Log in goroutine after TestLateLog has completed" + const want = "Log in goroutine after TestLateLog has completed: log after test" if !strings.Contains(s, want) { c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want) } diff --git a/src/testing/testing.go b/src/testing/testing.go index 80354d5ce8..466dd96981 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -762,7 +762,7 @@ func (c *common) logDepth(s string, depth int) { return } } - panic("Log in goroutine after " + c.name + " has completed") + panic("Log in goroutine after " + c.name + " has completed: " + s) } else { if c.chatty != nil { if c.bench { -- GitLab From adb467ffd2d82b796de12bdd8effa2cfefe01f29 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Sat, 2 Jan 2021 16:28:11 +0200 Subject: [PATCH 0081/1298] cmd/compile: reduce inline cost of OCONVOP OCONVOP doesn't have effect in the compiled code so, it can be safely excluded from inline cost calculation. Also make sequence ODEREF OCONVNOP* OADDR cost 1. This is rather common conversion, such as *(*uint32)(unsafe.Pointer(&x)). Fixes #42788 Change-Id: I5001f7e89d985c198b6405694cdd5b819cf3f47a Reviewed-on: https://go-review.googlesource.com/c/go/+/281232 Reviewed-by: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Trust: Elias Naur --- src/cmd/compile/internal/inline/inl.go | 16 ++++++++++++++++ test/inline.go | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 7d70fca6c9..0e57c17667 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -384,6 +384,22 @@ func (v *hairyVisitor) doNode(n ir.Node) bool { case ir.OAPPEND: v.budget -= inlineExtraAppendCost + case ir.ODEREF: + // *(*X)(unsafe.Pointer(&x)) is low-cost + n := n.(*ir.StarExpr) + + ptr := n.X + for ptr.Op() == ir.OCONVNOP { + ptr = ptr.(*ir.ConvExpr).X + } + if ptr.Op() == ir.OADDR { + v.budget += 1 // undo half of default cost of ir.ODEREF+ir.OADDR + } + + case ir.OCONVNOP: + // This doesn't produce code, but the children might. + v.budget++ // undo default cost + case ir.ODCLCONST, ir.OFALL: // These nodes don't produce code; omit from inlining budget. return false diff --git a/test/inline.go b/test/inline.go index 37965c0d9d..a79f5589fb 100644 --- a/test/inline.go +++ b/test/inline.go @@ -10,6 +10,7 @@ package foo import ( + "math" "runtime" "unsafe" ) @@ -262,3 +263,25 @@ func gd2() int { // ERROR "can inline gd2" func gd3() func() { // ERROR "can inline gd3" return ii } + +// Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost. +func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape" + _ = d[:6] + d[0] = math.Float32bits(x[0]) // ERROR "inlining call to math.Float32bits" + d[1] = math.Float32bits(x[1]) // ERROR "inlining call to math.Float32bits" + d[2] = math.Float32bits(x[2]) // ERROR "inlining call to math.Float32bits" + d[3] = math.Float32bits(x[3]) // ERROR "inlining call to math.Float32bits" + d[4] = math.Float32bits(x[4]) // ERROR "inlining call to math.Float32bits" + d[5] = math.Float32bits(x[5]) // ERROR "inlining call to math.Float32bits" +} + +// Ensure OCONVNOP is zero cost. +func Conv(v uint64) uint64 { // ERROR "can inline Conv" + return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)" +} +func conv2(v uint64) uint64 { // ERROR "can inline conv2" + return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1" +} +func conv1(v uint64) uint64 { // ERROR "can inline conv1" + return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v))))))))))) +} -- GitLab From 7a2f3273c5598bf53e37d0c8a4cb8a8caf7c4ca4 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 21 Jan 2021 12:04:46 -0500 Subject: [PATCH 0082/1298] cmd/compile: plumb abi info into ssagen/ssa Plumb abi information into ssa/ssagen for plain calls and plain functions (not methods). Does not extend all the way through the compiler (yet). One test disabled because it extends far enough to break the test. Normalized all the compiler's register args TODOs to // TODO(register args) ... For #40724. Change-Id: I0173a4579f032ac3c9db3aef1749d40da5ea01ff Reviewed-on: https://go-review.googlesource.com/c/go/+/293389 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 11 +- src/cmd/compile/internal/ir/node.go | 2 +- src/cmd/compile/internal/noder/lex.go | 4 +- src/cmd/compile/internal/ssa/func.go | 5 + .../compile/internal/ssa/loopreschedchecks.go | 3 +- src/cmd/compile/internal/ssa/op.go | 17 ++- src/cmd/compile/internal/ssa/rewrite.go | 2 +- src/cmd/compile/internal/ssa/writebarrier.go | 3 +- src/cmd/compile/internal/ssagen/ssa.go | 134 +++++++++++++----- src/cmd/compile/internal/typecheck/iexport.go | 2 +- src/cmd/compile/internal/typecheck/iimport.go | 2 +- test/abi/regabipragma.go | 4 +- 12 files changed, 137 insertions(+), 52 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index e935821802..7b388ec3dc 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -116,6 +116,13 @@ func NewABIConfig(iRegsCount, fRegsCount int) *ABIConfig { return &ABIConfig{regAmounts: RegAmounts{iRegsCount, fRegsCount}, regsForTypeCache: make(map[*types.Type]int)} } +// Copy returns a copy of an ABIConfig for use in a function's compilation so that access to the cache does not need to be protected with a mutex. +func (a *ABIConfig) Copy() *ABIConfig { + b := *a + b.regsForTypeCache = make(map[*types.Type]int) + return &b +} + // NumParamRegs returns the number of parameter registers used for a given type, // without regard for the number available. func (a *ABIConfig) NumParamRegs(t *types.Type) int { @@ -157,12 +164,12 @@ func (a *ABIConfig) NumParamRegs(t *types.Type) int { // 'config' and analyzes the function to determine how its parameters // and results will be passed (in registers or on the stack), returning // an ABIParamResultInfo object that holds the results of the analysis. -func (config *ABIConfig) ABIAnalyze(t *types.Type) ABIParamResultInfo { +func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { setup() s := assignState{ rTotal: config.regAmounts, } - result := ABIParamResultInfo{config: config} + result := &ABIParamResultInfo{config: config} // Receiver ft := t.FuncType() diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 59643713fa..38f9123582 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -456,7 +456,7 @@ const ( // Go command pragmas GoBuildPragma - RegisterParams // TODO remove after register abi is working + RegisterParams // TODO(register args) remove after register abi is working ) diff --git a/src/cmd/compile/internal/noder/lex.go b/src/cmd/compile/internal/noder/lex.go index cdca9e55f3..36cfb9bc23 100644 --- a/src/cmd/compile/internal/noder/lex.go +++ b/src/cmd/compile/internal/noder/lex.go @@ -28,7 +28,7 @@ const ( ir.Nosplit | ir.Noinline | ir.NoCheckPtr | - ir.RegisterParams | // TODO remove after register abi is working + ir.RegisterParams | // TODO(register args) remove after register abi is working ir.CgoUnsafeArgs | ir.UintptrEscapes | ir.Systemstack | @@ -80,7 +80,7 @@ func pragmaFlag(verb string) ir.PragmaFlag { // in the argument list. // Used in syscall/dll_windows.go. return ir.UintptrEscapes - case "go:registerparams": // TODO remove after register abi is working + case "go:registerparams": // TODO(register args) remove after register abi is working return ir.RegisterParams case "go:notinheap": return ir.NotInHeap diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index de99a8d4af..a36529af03 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -5,6 +5,7 @@ package ssa import ( + "cmd/compile/internal/abi" "cmd/compile/internal/types" "cmd/internal/src" "crypto/sha1" @@ -43,6 +44,10 @@ type Func struct { 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. ruleMatches map[string]int // number of times countRule was called during compilation for any given string + ABI0 *abi.ABIConfig // A copy, for no-sync access + ABI1 *abi.ABIConfig // A copy, for no-sync access + ABISelf *abi.ABIConfig // ABI for function being compiled + ABIDefault *abi.ABIConfig // ABI for rtcall and other no-parsed-signature/pragma functions. scheduled bool // Values in Blocks are in final order laidout bool // Blocks are ordered diff --git a/src/cmd/compile/internal/ssa/loopreschedchecks.go b/src/cmd/compile/internal/ssa/loopreschedchecks.go index 9c73bcff26..5308d1ac48 100644 --- a/src/cmd/compile/internal/ssa/loopreschedchecks.go +++ b/src/cmd/compile/internal/ssa/loopreschedchecks.go @@ -246,7 +246,8 @@ func insertLoopReschedChecks(f *Func) { // mem1 := call resched (mem0) // goto header resched := f.fe.Syslook("goschedguarded") - mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeMem, StaticAuxCall(resched, nil, nil), mem0) + // TODO(register args) -- will need more details + mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, types.TypeMem, StaticAuxCall(resched, nil, nil, nil), mem0) sched.AddEdgeTo(h) headerMemPhi.AddArg(mem1) diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index cf0d2affc7..4bda7369bb 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -5,6 +5,7 @@ package ssa import ( + "cmd/compile/internal/abi" "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/obj" @@ -71,15 +72,18 @@ type auxType int8 type Param struct { Type *types.Type - Offset int32 // Offset of Param if not in a register. + Offset int32 // Offset of Param if not in a register, spill offset if it is in a register input, types.BADWIDTH if it is a register output. + Reg []abi.RegIndex Name *ir.Name // For OwnAux, need to prepend stores with Vardefs } type AuxCall struct { + // TODO(register args) this information is largely redundant with ../abi information, needs cleanup once new ABI is in place. Fn *obj.LSym args []Param // Includes receiver for method calls. Does NOT include hidden closure pointer. results []Param - reg *regInfo // regInfo for this call // TODO for now nil means ignore + reg *regInfo // regInfo for this call // TODO for now nil means ignore + abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information. } // ResultForOffset returns the index of the result at a particular offset among the results @@ -186,9 +190,9 @@ func (a *AuxCall) String() string { } // StaticAuxCall returns an AuxCall for a static call. -func StaticAuxCall(sym *obj.LSym, args []Param, results []Param) *AuxCall { +func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { // TODO Create regInfo for AuxCall - return &AuxCall{Fn: sym, args: args, results: results} + return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo} } // InterfaceAuxCall returns an AuxCall for an interface call. @@ -206,9 +210,10 @@ func ClosureAuxCall(args []Param, results []Param) *AuxCall { func (*AuxCall) CanBeAnSSAAux() {} // OwnAuxCall returns a function's own AuxCall -func OwnAuxCall(fn *obj.LSym, args []Param, results []Param) *AuxCall { + +func OwnAuxCall(fn *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { // TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate. - return &AuxCall{Fn: fn, args: args, results: results} + return &AuxCall{Fn: fn, args: args, results: results, abiInfo: paramResultInfo} } const ( diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index e82aa84cdf..ac6278ab9d 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -765,7 +765,7 @@ func devirt(v *Value, aux Aux, sym Sym, offset int64) *AuxCall { return nil } va := aux.(*AuxCall) - return StaticAuxCall(lsym, va.args, va.results) + return StaticAuxCall(lsym, va.args, va.results, va.abiInfo) } // de-virtualize an InterLECall diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 4378f2d627..7d375da128 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -512,7 +512,8 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va off = round(off, config.PtrSize) // issue call - mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, StaticAuxCall(fn, ACArgs, nil), mem) + // TODO(register args) -- will need more details + mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, StaticAuxCall(fn, ACArgs, nil, nil), mem) mem.AuxInt = off - config.ctxt.FixedFrameSize() return mem } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index cfc54ae0ab..d69eb17ca9 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -357,7 +357,20 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { if fn.Pragma&ir.Nosplit != 0 { s.f.NoSplit = true } - if fn.Pragma&ir.RegisterParams != 0 { // TODO remove after register abi is working + s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-width cache. + s.f.ABI1 = ssaConfig.ABI1.Copy() + + s.f.ABIDefault = s.f.ABI1 // Default ABI for function calls with no parsed signature for a pragma, e.g. rtcall + // TODO(register args) -- remove "true ||"; in the short run, turning on the register ABI experiment still leaves the compiler defaulting to ABI0. + // TODO(register args) -- remove this conditional entirely when register ABI is not an experiment. + if true || objabi.Regabi_enabled == 0 { + s.f.ABIDefault = s.f.ABI0 // reset + } + + s.f.ABISelf = s.f.ABIDefault + + if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + s.f.ABISelf = s.f.ABI1 if strings.Contains(name, ".") { base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) } @@ -449,18 +462,19 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false) } + params := s.f.ABISelf.ABIAnalyze(fn.Type()) + // Generate addresses of local declarations s.decladdrs = map[*ir.Name]*ssa.Value{} - var args []ssa.Param var results []ssa.Param for _, n := range fn.Dcl { switch n.Class { case ir.PPARAM: + // Be aware that blank and unnamed input parameters will not appear here, but do appear in the type s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem) - args = append(args, ssa.Param{Type: n.Type(), Offset: int32(n.FrameOffset())}) case ir.PPARAMOUT: s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem) - results = append(results, ssa.Param{Type: n.Type(), Offset: int32(n.FrameOffset()), Name: n}) + results = append(results, ssa.Param{Name: n}) case ir.PAUTO: // processed at each use, to prevent Addr coming // before the decl. @@ -468,7 +482,36 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { s.Fatalf("local variable with class %v unimplemented", n.Class) } } - s.f.OwnAux = ssa.OwnAuxCall(fn.LSym, args, results) + + // TODO: figure out why base.Ctxt.FixedFrameSize() is not added to these offsets here (compare to calls). + // The input half is ignored unless a register ABI is used. + var args []ssa.Param + for _, p := range params.InParams() { + r := p.Registers + var o int32 + if len(r) == 0 { + o = p.Offset() + } else { + o = p.SpillOffset() + int32(params.SpillAreaOffset()) + } + args = append(args, ssa.Param{Type: p.Type, Offset: o, Reg: r}) + } + + // For now, need the ir.Name attached to these, so update those already created. + for i, p := range params.OutParams() { + r := p.Registers + var o int32 + if len(r) == 0 { + o = p.Offset() + } else { + o = types.BADWIDTH + } + results[i].Type = p.Type + results[i].Offset = o + results[i].Reg = r + } + + s.f.OwnAux = ssa.OwnAuxCall(fn.LSym, args, results, params) // Populate SSAable arguments. for _, n := range fn.Dcl { @@ -1846,7 +1889,7 @@ func (s *state) exit() *ssa.Block { } // Run exit code. Today, this is just racefuncexit, in -race mode. - // TODO this seems risky here with a register-ABI, but not clear it is right to do it earlier either. + // TODO(register args) this seems risky here with a register-ABI, but not clear it is right to do it earlier either. // Spills in register allocation might just fix it. s.stmtList(s.curfn.Exit) @@ -4691,7 +4734,7 @@ func (s *state) openDeferExit() { aux := ssa.ClosureAuxCall(ACArgs, ACResults) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v) } else { - aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults) + aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, nil) // TODO will need types for this. call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) } callArgs = append(callArgs, s.mem()) @@ -4738,18 +4781,9 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val var codeptr *ssa.Value // ptr to target code (if dynamic) var rcvr *ssa.Value // receiver to set fn := n.X - var ACArgs []ssa.Param - var ACResults []ssa.Param - var callArgs []*ssa.Value - res := n.X.Type().Results() - if k == callNormal { - nf := res.NumFields() - for i := 0; i < nf; i++ { - fp := res.Field(i) - ACResults = append(ACResults, ssa.Param{Type: fp.Type, Offset: int32(fp.Offset + base.Ctxt.FixedFrameSize())}) - } - } - + var ACArgs []ssa.Param // AuxCall args + var ACResults []ssa.Param // AuxCall results + var callArgs []*ssa.Value // For late-expansion, the args themselves (not stored, args to the call instead). inRegisters := false switch n.Op() { @@ -4757,7 +4791,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC { fn := fn.(*ir.Name) callee = fn - // TODO remove after register abi is working + // TODO(register args) remove after register abi is working inRegistersImported := fn.Pragma()&ir.RegisterParams != 0 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0 inRegisters = inRegistersImported || inRegistersSamePackage @@ -4790,6 +4824,27 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val types.CalcSize(fn.Type()) stksize := fn.Type().ArgWidth() // includes receiver, args, and results + abi := s.f.ABI1 + if !inRegisters { + abi = s.f.ABI0 + } + + params := abi.ABIAnalyze(n.X.Type()) + + res := n.X.Type().Results() + if k == callNormal { + for _, p := range params.OutParams() { + r := p.Registers + var o int32 + if len(r) == 0 { + o = p.Offset() + } else { + o = p.SpillOffset() + int32(params.SpillAreaOffset()) + } + ACResults = append(ACResults, ssa.Param{Type: p.Type, Offset: o + int32(base.Ctxt.FixedFrameSize()), Reg: r}) + } + } + var call *ssa.Value if k == callDeferStack { // Make a defer struct d on the stack. @@ -4841,14 +4896,14 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // Call runtime.deferprocStack with pointer to _defer record. ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(base.Ctxt.FixedFrameSize())}) - aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, ACArgs, ACResults) + aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, ACArgs, ACResults, nil) callArgs = append(callArgs, addr, s.mem()) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) call.AddArgs(callArgs...) if stksize < int64(types.PtrSize) { // We need room for both the call to deferprocStack and the call to // the deferred function. - // TODO Revisit this if/when we pass args in registers. + // TODO(register args) Revisit this if/when we pass args in registers. stksize = int64(types.PtrSize) } call.AuxInt = stksize @@ -4870,7 +4925,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // Set receiver (for interface calls). if rcvr != nil { - ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)}) + // ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)}) callArgs = append(callArgs, rcvr) } @@ -4880,11 +4935,20 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val if n.Op() == ir.OCALLMETH { base.Fatalf("OCALLMETH missed by walkCall") } - for i, n := range args { - f := t.Params().Field(i) - ACArg, arg := s.putArg(n, f.Type, argStart+f.Offset) + + for _, p := range params.InParams() { + r := p.Registers + var o int32 + if len(r) == 0 { + o = p.Offset() + } else { + o = p.SpillOffset() + int32(params.SpillAreaOffset()) + } + ACArg := ssa.Param{Type: p.Type, Offset: int32(argStart) + o, Reg: r} ACArgs = append(ACArgs, ACArg) - callArgs = append(callArgs, arg) + } + for i, n := range args { + callArgs = append(callArgs, s.putArg(n, t.Params().Field(i).Type)) } callArgs = append(callArgs, s.mem()) @@ -4892,11 +4956,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // call target switch { case k == callDefer: - aux := ssa.StaticAuxCall(ir.Syms.Deferproc, ACArgs, ACResults) + aux := ssa.StaticAuxCall(ir.Syms.Deferproc, ACArgs, ACResults, nil) // TODO paramResultInfo for DeferProc call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) case k == callGo: - aux := ssa.StaticAuxCall(ir.Syms.Newproc, ACArgs, ACResults) - call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) + aux := ssa.StaticAuxCall(ir.Syms.Newproc, ACArgs, ACResults, nil) + call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) // TODO paramResultInfo for NewProc case closure != nil: // rawLoad because loading the code pointer from a // closure is always safe, but IsSanitizerSafeAddr @@ -4910,7 +4974,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val aux := ssa.InterfaceAuxCall(ACArgs, ACResults) call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr) case callee != nil: - aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults) + aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) default: s.Fatalf("bad call type %v %v", n.Op(), n) @@ -5391,7 +5455,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args . // Issue call var call *ssa.Value - aux := ssa.StaticAuxCall(fn, ACArgs, ACResults) + aux := ssa.StaticAuxCall(fn, ACArgs, ACResults, nil) // WILL NEED A TYPE FOR THIS.) callArgs = append(callArgs, s.mem()) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) call.AddArgs(callArgs...) @@ -5539,15 +5603,15 @@ func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) { } } -// putArg evaluates n for the purpose of passing it as an argument to a function and returns the corresponding Param and value for the call. -func (s *state) putArg(n ir.Node, t *types.Type, off int64) (ssa.Param, *ssa.Value) { +// putArg evaluates n for the purpose of passing it as an argument to a function and returns the value for the call. +func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value { var a *ssa.Value if !TypeOK(t) { a = s.newValue2(ssa.OpDereference, t, s.addr(n), s.mem()) } else { a = s.expr(n) } - return ssa.Param{Type: t, Offset: int32(off)}, a + return a } func (s *state) storeArgWithBase(n ir.Node, t *types.Type, base *ssa.Value, off int64) { diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 6fab74e61f..38ac753201 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1025,7 +1025,7 @@ func (w *exportWriter) funcExt(n *ir.Name) { w.linkname(n.Sym()) w.symIdx(n.Sym()) - // TODO remove after register abi is working. + // TODO(register args) remove after register abi is working. w.uint64(uint64(n.Func.Pragma)) // Escape analysis. diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 29090a9178..17aa35549d 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -673,7 +673,7 @@ func (r *importReader) funcExt(n *ir.Name) { r.linkname(n.Sym()) r.symIdx(n.Sym()) - // TODO remove after register abi is working + // TODO(register args) remove after register abi is working n.SetPragma(ir.PragmaFlag(r.uint64())) // Escape analysis. diff --git a/test/abi/regabipragma.go b/test/abi/regabipragma.go index e7ecd58fc8..86f42f9779 100644 --- a/test/abi/regabipragma.go +++ b/test/abi/regabipragma.go @@ -1,3 +1,4 @@ +// skip // runindir -gcflags=-c=1 // +build !windows @@ -5,6 +6,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO May delete or adapt this test once regabi is the default +// TODO(register args) Temporarily disabled now that register abi info is flowing halfway through the compiler. +// TODO(register args) May delete or adapt this test once regabi is the default package ignore -- GitLab From dc4698f52b5ad3f0251e0cc25bc7ffbd10e23f2c Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 23 Feb 2021 13:29:40 +0100 Subject: [PATCH 0083/1298] syscall: do not overflow key memory in GetQueuedCompletionStatus The third argument to GetQueuedCompletionStatus is a pointer to a uintptr, not a uint32. Users of this functions have therefore been corrupting their memory every time they used it. Either that memory corruption was silent (dangerous), or their programs didn't work so they chose a different API to use. Fixes #44538. RELNOTES=yes Change-Id: Idf48d4c712d13da29791e9a460159255f963105b Reviewed-on: https://go-review.googlesource.com/c/go/+/295371 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- api/except.txt | 6 ++++++ src/syscall/syscall_windows.go | 6 +++--- src/syscall/zsyscall_windows.go | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/except.txt b/api/except.txt index 6f6f839ba6..1ddc397d11 100644 --- a/api/except.txt +++ b/api/except.txt @@ -471,6 +471,9 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32 pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-386), func CreateIoCompletionPort(Handle, Handle, uint32, uint32) (Handle, error) +pkg syscall (windows-386), func GetQueuedCompletionStatus(Handle, *uint32, *uint32, **Overlapped, uint32) error +pkg syscall (windows-386), func PostQueuedCompletionStatus(Handle, uint32, uint32, *Overlapped) error pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr @@ -480,6 +483,9 @@ pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintp pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr pkg syscall (windows-386), type RawSockaddrAny struct, Pad [96]int8 pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-amd64), func CreateIoCompletionPort(Handle, Handle, uint32, uint32) (Handle, error) +pkg syscall (windows-amd64), func GetQueuedCompletionStatus(Handle, *uint32, *uint32, **Overlapped, uint32) error +pkg syscall (windows-amd64), func PostQueuedCompletionStatus(Handle, uint32, uint32, *Overlapped) error pkg syscall (windows-amd64), type AddrinfoW struct, Addr uintptr pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 4a576486d1..a958f7aa84 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -213,9 +213,9 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetEndOfFile(handle Handle) (err error) //sys GetSystemTimeAsFileTime(time *Filetime) //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] -//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) -//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) -//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) +//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) +//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) +//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) //sys CancelIo(s Handle) (err error) //sys CancelIoEx(s Handle, o *Overlapped) (err error) //sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 2166be595b..cc44e31a85 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -515,7 +515,7 @@ func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr return } -func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) { +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) handle = Handle(r0) if handle == 0 { @@ -822,7 +822,7 @@ func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, return } -func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) { +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) if r1 == 0 { err = errnoErr(e1) @@ -954,7 +954,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err return } -func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) { +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) if r1 == 0 { err = errnoErr(e1) -- GitLab From c9d9b40b1355a8e6674aaaf6abaf362e66abae47 Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Wed, 24 Feb 2021 09:12:34 -0800 Subject: [PATCH 0084/1298] context: avoid importing context package twice Change-Id: Id0a127e080dda8ee62738922c6de8caf3719dd68 Reviewed-on: https://go-review.googlesource.com/c/go/+/295949 Reviewed-by: Josh Bleecher Snyder Trust: Josh Bleecher Snyder Trust: Kevin Burke Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot --- src/context/benchmark_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/context/benchmark_test.go b/src/context/benchmark_test.go index c4c72f00f8..69d75fff18 100644 --- a/src/context/benchmark_test.go +++ b/src/context/benchmark_test.go @@ -5,7 +5,6 @@ package context_test import ( - "context" . "context" "fmt" "runtime" @@ -141,7 +140,7 @@ func BenchmarkCheckCanceled(b *testing.B) { } func BenchmarkContextCancelDone(b *testing.B) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := WithCancel(Background()) defer cancel() b.RunParallel(func(pb *testing.PB) { -- GitLab From b7f62daa59ea5983d5825e166abc527d4ea69777 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 15 Dec 2020 16:01:34 -0500 Subject: [PATCH 0085/1298] cmd/internal/goobj: add test case for object file reader Add test in which a input Go object file contains a very large number of relocations (more than 1<<20). Updates #41621. Change-Id: If1ebf3c4fefbf55ddec4e05c5299e7c48fc697d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/278493 Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Than McIntosh --- src/cmd/internal/goobj/objfile_test.go | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/cmd/internal/goobj/objfile_test.go b/src/cmd/internal/goobj/objfile_test.go index c6fd427c15..99d02a1bf1 100644 --- a/src/cmd/internal/goobj/objfile_test.go +++ b/src/cmd/internal/goobj/objfile_test.go @@ -9,6 +9,11 @@ import ( "bytes" "cmd/internal/bio" "cmd/internal/objabi" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" "testing" ) @@ -69,3 +74,60 @@ func TestReadWrite(t *testing.T) { t.Errorf("read Aux2 mismatch: got %v %v", a2.Type(), a2.Sym()) } } + +var issue41621prolog = ` +package main +var lines = []string{ +` + +var issue41621epilog = ` +} +func getLines() []string { + return lines +} +func main() { + println(getLines()) +} +` + +func TestIssue41621LargeNumberOfRelocations(t *testing.T) { + if testing.Short() || (objabi.GOARCH != "amd64") { + t.Skipf("Skipping large number of relocations test in short mode or on %s", objabi.GOARCH) + } + testenv.MustHaveGoBuild(t) + + tmpdir, err := ioutil.TempDir("", "lotsofrelocs") + if err != nil { + t.Fatalf("can't create temp directory: %v\n", err) + } + defer os.RemoveAll(tmpdir) + + // Emit testcase. + var w bytes.Buffer + fmt.Fprintf(&w, issue41621prolog) + for i := 0; i < 1048576+13; i++ { + fmt.Fprintf(&w, "\t\"%d\",\n", i) + } + fmt.Fprintf(&w, issue41621epilog) + err = ioutil.WriteFile(tmpdir+"/large.go", w.Bytes(), 0666) + if err != nil { + t.Fatalf("can't write output: %v\n", err) + } + + // Emit go.mod + w.Reset() + fmt.Fprintf(&w, "module issue41621\n\ngo 1.12\n") + err = ioutil.WriteFile(tmpdir+"/go.mod", w.Bytes(), 0666) + if err != nil { + t.Fatalf("can't write output: %v\n", err) + } + w.Reset() + + // Build. + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "large") + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Build failed: %v, output: %s", err, out) + } +} -- GitLab From bf48163e8f2b604f3b9e83951e331cd11edd8495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa=20Montoro?= Date: Wed, 30 Dec 2020 18:41:36 +0100 Subject: [PATCH 0086/1298] cmd/compile: add rule to coalesce writes The code generated when storing eight bytes loaded from memory created a series of small writes instead of a single, large one. The specific pattern of instructions generated stored 1 byte, then 2 bytes, then 4 bytes, and finally 1 byte. The new rules match this specific pattern both for amd64 and for s390x, and convert it into a single instruction to store the 8 bytes. arm64 and ppc64le already generated the right code, but the new codegen test covers also those architectures. Fixes #41663 Change-Id: Ifb9b464be2d59c2ed5034acf7b9c3e473f344030 Reviewed-on: https://go-review.googlesource.com/c/go/+/280456 Reviewed-by: Josh Bleecher Snyder Trust: Josh Bleecher Snyder Trust: Jason A. Donenfeld Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot --- src/cmd/compile/internal/ssa/gen/AMD64.rules | 10 ++++ src/cmd/compile/internal/ssa/gen/S390X.rules | 10 ++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 48 ++++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteS390X.go | 48 ++++++++++++++++++++ test/codegen/memcombine.go | 9 ++++ 5 files changed, 125 insertions(+) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 01a8a16456..f2bcbd2dfc 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -1969,6 +1969,16 @@ && clobber(x) => (MOVQstore [i] {s} p0 w0 mem) +(MOVBstore [7] p1 (SHRQconst [56] w) + x1:(MOVWstore [5] p1 (SHRQconst [40] w) + x2:(MOVLstore [1] p1 (SHRQconst [8] w) + x3:(MOVBstore p1 w mem)))) + && x1.Uses == 1 + && x2.Uses == 1 + && x3.Uses == 1 + && clobber(x1, x2, x3) + => (MOVQstore p1 w mem) + (MOVBstore [i] {s} p x1:(MOVBload [j] {s2} p2 mem) mem2:(MOVBstore [i-1] {s} p diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index c3421da0a2..7111d5e11a 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -1420,6 +1420,16 @@ && clobber(x) => (MOVDBRstore [i-4] {s} p w0 mem) +(MOVBstore [7] p1 (SRDconst w) + x1:(MOVHBRstore [5] p1 (SRDconst w) + x2:(MOVWBRstore [1] p1 (SRDconst w) + x3:(MOVBstore p1 w mem)))) + && x1.Uses == 1 + && x2.Uses == 1 + && x3.Uses == 1 + && clobber(x1, x2, x3) + => (MOVDBRstore p1 w mem) + // Combining byte loads into larger (unaligned) loads. // Big-endian loads diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 5fb6c303fd..599137c806 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -11412,6 +11412,54 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(p0, w0, mem) return true } + // match: (MOVBstore [7] p1 (SHRQconst [56] w) x1:(MOVWstore [5] p1 (SHRQconst [40] w) x2:(MOVLstore [1] p1 (SHRQconst [8] w) x3:(MOVBstore p1 w mem)))) + // cond: x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) + // result: (MOVQstore p1 w mem) + for { + if auxIntToInt32(v.AuxInt) != 7 { + break + } + p1 := v_0 + if v_1.Op != OpAMD64SHRQconst || auxIntToInt8(v_1.AuxInt) != 56 { + break + } + w := v_1.Args[0] + x1 := v_2 + if x1.Op != OpAMD64MOVWstore || auxIntToInt32(x1.AuxInt) != 5 { + break + } + _ = x1.Args[2] + if p1 != x1.Args[0] { + break + } + x1_1 := x1.Args[1] + if x1_1.Op != OpAMD64SHRQconst || auxIntToInt8(x1_1.AuxInt) != 40 || w != x1_1.Args[0] { + break + } + x2 := x1.Args[2] + if x2.Op != OpAMD64MOVLstore || auxIntToInt32(x2.AuxInt) != 1 { + break + } + _ = x2.Args[2] + if p1 != x2.Args[0] { + break + } + x2_1 := x2.Args[1] + if x2_1.Op != OpAMD64SHRQconst || auxIntToInt8(x2_1.AuxInt) != 8 || w != x2_1.Args[0] { + break + } + x3 := x2.Args[2] + if x3.Op != OpAMD64MOVBstore { + break + } + mem := x3.Args[2] + if p1 != x3.Args[0] || w != x3.Args[1] || !(x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3)) { + break + } + v.reset(OpAMD64MOVQstore) + v.AddArg3(p1, w, mem) + return true + } // match: (MOVBstore [i] {s} p x1:(MOVBload [j] {s2} p2 mem) mem2:(MOVBstore [i-1] {s} p x2:(MOVBload [j-1] {s2} p2 mem) mem)) // cond: x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1, x2, mem2) // result: (MOVWstore [i-1] {s} p (MOVWload [j-1] {s2} p2 mem) mem) diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index b52a1b6745..6adae3ff35 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -8880,6 +8880,54 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { v.AddArg3(p, w0, mem) return true } + // match: (MOVBstore [7] p1 (SRDconst w) x1:(MOVHBRstore [5] p1 (SRDconst w) x2:(MOVWBRstore [1] p1 (SRDconst w) x3:(MOVBstore p1 w mem)))) + // cond: x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) + // result: (MOVDBRstore p1 w mem) + for { + if auxIntToInt32(v.AuxInt) != 7 { + break + } + p1 := v_0 + if v_1.Op != OpS390XSRDconst { + break + } + w := v_1.Args[0] + x1 := v_2 + if x1.Op != OpS390XMOVHBRstore || auxIntToInt32(x1.AuxInt) != 5 { + break + } + _ = x1.Args[2] + if p1 != x1.Args[0] { + break + } + x1_1 := x1.Args[1] + if x1_1.Op != OpS390XSRDconst || w != x1_1.Args[0] { + break + } + x2 := x1.Args[2] + if x2.Op != OpS390XMOVWBRstore || auxIntToInt32(x2.AuxInt) != 1 { + break + } + _ = x2.Args[2] + if p1 != x2.Args[0] { + break + } + x2_1 := x2.Args[1] + if x2_1.Op != OpS390XSRDconst || w != x2_1.Args[0] { + break + } + x3 := x2.Args[2] + if x3.Op != OpS390XMOVBstore { + break + } + mem := x3.Args[2] + if p1 != x3.Args[0] || w != x3.Args[1] || !(x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3)) { + break + } + v.reset(OpS390XMOVDBRstore) + v.AddArg3(p1, w, mem) + return true + } return false } func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value) bool { diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index 6ad9514557..121f394f29 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -367,6 +367,15 @@ func store_le64_idx(b []byte, idx int) { binary.LittleEndian.PutUint64(b[idx:], sink64) } +func store_le64_load(b []byte, x *[8]byte) { + _ = b[8] + // amd64:-`MOV[BWL]` + // arm64:-`MOV[BWH]` + // ppc64le:-`MOV[BWH]` + // s390x:-`MOVB`,-`MOV[WH]BR` + binary.LittleEndian.PutUint64(b, binary.LittleEndian.Uint64(x[:])) +} + func store_le32(b []byte) { // amd64:`MOVL\s` // arm64:`MOVW`,-`MOV[BH]` -- GitLab From 478277f81283b9e941c4fdadc253797e6d035971 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 23 Feb 2021 22:03:29 -0500 Subject: [PATCH 0087/1298] cmd/compile/internal-abi: use x87 mode, not MMX mode Florian Weimer pointed out that my justification for using MMX mode was nonsense and that staying in x87 mode simplifies transitions to and from C. Hence, switch the spec to say we're always in x87 mode. For #40724. Change-Id: Iad916b2c376db41f95614aa6897f6b1184576bb7 Reviewed-on: https://go-review.googlesource.com/c/go/+/295789 Trust: Austin Clements Reviewed-by: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/compile/internal-abi.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal-abi.md b/src/cmd/compile/internal-abi.md index f4ef2cc869..3a3509d8c2 100644 --- a/src/cmd/compile/internal-abi.md +++ b/src/cmd/compile/internal-abi.md @@ -455,13 +455,12 @@ The arithmetic status flags are treated like scratch registers and not preserved across calls. All other bits in RFLAGS are system flags. -The CPU is always in MMX technology state (not x87 mode). +At function calls and returns, the CPU is in x87 mode (not MMX +technology mode). -*Rationale*: Go on amd64 uses the XMM registers and never uses the x87 -registers, so it makes sense to assume the CPU is in MMX mode. -Otherwise, any function that used the XMM registers would have to -execute an EMMS instruction before calling another function or -returning (this is the case in the SysV ABI). +*Rationale*: Go on amd64 does not use either the x87 registers or MMX +registers. Hence, we follow the SysV platform conventions in order to +simplify transitions to and from the C ABI. At calls, the MXCSR control bits are always set as follows: -- GitLab From 3deb528199383b39425fc99f3741a6ade6ab5a6b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 23 Feb 2021 21:22:20 -0500 Subject: [PATCH 0088/1298] cmd/compile/internal-abi: update internal ABI spec for g register We've already implemented dedicating R14 as the G register on amd64, so remove the TODO saying we might want to hold off on this. For #40724. Change-Id: I45b24ced03cac862127b53f5e9a4b4bcf6b1f86c Reviewed-on: https://go-review.googlesource.com/c/go/+/295790 Trust: Austin Clements Reviewed-by: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/compile/internal-abi.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd/compile/internal-abi.md b/src/cmd/compile/internal-abi.md index 3a3509d8c2..0e5d8ce260 100644 --- a/src/cmd/compile/internal-abi.md +++ b/src/cmd/compile/internal-abi.md @@ -402,9 +402,6 @@ Special-purpose registers are as follows: | R15 | GOT reference temporary | Fixed if dynlink | | X15 | Zero value | Fixed | -TODO: We may start with the existing TLS-based g and move to R14 -later. - *Rationale*: These register meanings are compatible with Go’s stack-based calling convention except for R14 and X15, which will have to be restored on transitions from ABI0 code to ABIInternal code. -- GitLab From 80ddc17ae1b3ffacc42c19b999956f9ccef3ddd1 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 23 Feb 2021 20:48:22 -0500 Subject: [PATCH 0089/1298] cmd/compile/internal-abi: fix ABI0-equivalence for zero-sized values This fixes a bug in the internal ABI specification that made it not equivalent to ABI0 even with zero architectural argument registers in the case of a zero-sized argument with alignment > 1. In ABI0, even zero-sized arguments cause alignment padding in the stack frame. Currently, in the internal ABI, zero-sized arguments get register-assigned even if there are no registers because they don't consume any registers. Hence, they don't create alignment padding in the stack frame. Fix this by stack-assigning zero-sized arguments. For #40724. Change-Id: I1f5a95a94fed8b5313a360e5e76875701ba5f562 Reviewed-on: https://go-review.googlesource.com/c/go/+/295791 Trust: Austin Clements Reviewed-by: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/compile/internal-abi.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmd/compile/internal-abi.md b/src/cmd/compile/internal-abi.md index 0e5d8ce260..b457f6ee74 100644 --- a/src/cmd/compile/internal-abi.md +++ b/src/cmd/compile/internal-abi.md @@ -153,6 +153,7 @@ Assigning a receiver, argument, or result V of underlying type T works as follows: 1. Remember I and FP. +1. If T has zero size, add T to the stack sequence S and return. 1. Try to register-assign V. 1. If step 2 failed, reset I and FP to the values from step 1, add T to the stack sequence S, and assign V to this field in S. @@ -295,6 +296,15 @@ An architecture may still define register meanings that aren’t compatible with ABI0, but these differences should be easy to account for in the compiler. +The assignment algorithm assigns zero-sized values to the stack +(assignment step 2) in order to support ABI0-equivalence. +While these values take no space themselves, they do result in +alignment padding on the stack in ABI0. +Without this step, the internal ABI would register-assign zero-sized +values even on architectures that provide no argument registers +because they don't consume any registers, and hence not add alignment +padding to the stack. + The algorithm reserves spill space for arguments in the caller’s frame so that the compiler can generate a stack growth path that spills into this reserved space. -- GitLab From 3ee32439b5114c1fe5f04891b678613aa72e13c2 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Fri, 27 Nov 2020 17:10:33 +0200 Subject: [PATCH 0090/1298] cmd/compile: ARM64 optimize []float64 and []float32 access Optimize load and store to []float64 and []float32. Previously it used LSL instead of shifted register indexed load/store. Before: LSL $3, R0, R0 FMOVD F0, (R1)(R0) After: FMOVD F0, (R1)(R0<<3) Fixes #42798 Change-Id: I0c0912140c3dce5aa6abc27097c0eb93833cc589 Reviewed-on: https://go-review.googlesource.com/c/go/+/273706 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Trust: Giovanni Bajo --- src/cmd/compile/internal/arm64/ssa.go | 14 +- src/cmd/compile/internal/ssa/gen/ARM64.rules | 18 ++ src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 20 +- src/cmd/compile/internal/ssa/opGen.go | 56 ++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 294 +++++++++++++++++++ test/codegen/floats.go | 4 +- test/codegen/memops.go | 4 + 7 files changed, 396 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 73e74e1219..ca5eac72bf 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -100,9 +100,11 @@ func genIndexedOperand(v *ssa.Value) obj.Addr { // Reg: base register, Index: (shifted) index register mop := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()} switch v.Op { - case ssa.OpARM64MOVDloadidx8, ssa.OpARM64MOVDstoreidx8, ssa.OpARM64MOVDstorezeroidx8: + case ssa.OpARM64MOVDloadidx8, ssa.OpARM64MOVDstoreidx8, ssa.OpARM64MOVDstorezeroidx8, + ssa.OpARM64FMOVDloadidx8, ssa.OpARM64FMOVDstoreidx8: mop.Index = arm64.REG_LSL | 3<<5 | v.Args[1].Reg()&31 - case ssa.OpARM64MOVWloadidx4, ssa.OpARM64MOVWUloadidx4, ssa.OpARM64MOVWstoreidx4, ssa.OpARM64MOVWstorezeroidx4: + case ssa.OpARM64MOVWloadidx4, ssa.OpARM64MOVWUloadidx4, ssa.OpARM64MOVWstoreidx4, ssa.OpARM64MOVWstorezeroidx4, + ssa.OpARM64FMOVSloadidx4, ssa.OpARM64FMOVSstoreidx4: mop.Index = arm64.REG_LSL | 2<<5 | v.Args[1].Reg()&31 case ssa.OpARM64MOVHloadidx2, ssa.OpARM64MOVHUloadidx2, ssa.OpARM64MOVHstoreidx2, ssa.OpARM64MOVHstorezeroidx2: mop.Index = arm64.REG_LSL | 1<<5 | v.Args[1].Reg()&31 @@ -435,7 +437,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARM64MOVHUloadidx2, ssa.OpARM64MOVWloadidx4, ssa.OpARM64MOVWUloadidx4, - ssa.OpARM64MOVDloadidx8: + ssa.OpARM64MOVDloadidx8, + ssa.OpARM64FMOVDloadidx8, + ssa.OpARM64FMOVSloadidx4: p := s.Prog(v.Op.Asm()) p.From = genIndexedOperand(v) p.To.Type = obj.TYPE_REG @@ -472,7 +476,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARM64FMOVDstoreidx, ssa.OpARM64MOVHstoreidx2, ssa.OpARM64MOVWstoreidx4, - ssa.OpARM64MOVDstoreidx8: + ssa.OpARM64FMOVSstoreidx4, + ssa.OpARM64MOVDstoreidx8, + ssa.OpARM64FMOVDstoreidx8: p := s.Prog(v.Op.Asm()) p.To = genIndexedOperand(v) p.From.Type = obj.TYPE_REG diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 4531c38a7a..98503748db 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -792,6 +792,15 @@ (MOVHUloadidx2 ptr (MOVDconst [c]) mem) && is32Bit(c<<1) => (MOVHUload [int32(c)<<1] ptr mem) (MOVHloadidx2 ptr (MOVDconst [c]) mem) && is32Bit(c<<1) => (MOVHload [int32(c)<<1] ptr mem) +(FMOVDload [off] {sym} (ADDshiftLL [3] ptr idx) mem) && off == 0 && sym == nil => (FMOVDloadidx8 ptr idx mem) +(FMOVSload [off] {sym} (ADDshiftLL [2] ptr idx) mem) && off == 0 && sym == nil => (FMOVSloadidx4 ptr idx mem) +(FMOVDloadidx ptr (SLLconst [3] idx) mem) => (FMOVDloadidx8 ptr idx mem) +(FMOVSloadidx ptr (SLLconst [2] idx) mem) => (FMOVSloadidx4 ptr idx mem) +(FMOVDloadidx (SLLconst [3] idx) ptr mem) => (FMOVDloadidx8 ptr idx mem) +(FMOVSloadidx (SLLconst [2] idx) ptr mem) => (FMOVSloadidx4 ptr idx mem) +(FMOVDloadidx8 ptr (MOVDconst [c]) mem) && is32Bit(c<<3) => (FMOVDload ptr [int32(c)<<3] mem) +(FMOVSloadidx4 ptr (MOVDconst [c]) mem) && is32Bit(c<<2) => (FMOVSload ptr [int32(c)<<2] mem) + (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => (MOVBstore [off1+int32(off2)] {sym} ptr val mem) @@ -865,6 +874,15 @@ (MOVWstoreidx4 ptr (MOVDconst [c]) val mem) && is32Bit(c<<2) => (MOVWstore [int32(c)<<2] ptr val mem) (MOVHstoreidx2 ptr (MOVDconst [c]) val mem) && is32Bit(c<<1) => (MOVHstore [int32(c)<<1] ptr val mem) +(FMOVDstore [off] {sym} (ADDshiftLL [3] ptr idx) val mem) && off == 0 && sym == nil => (FMOVDstoreidx8 ptr idx val mem) +(FMOVSstore [off] {sym} (ADDshiftLL [2] ptr idx) val mem) && off == 0 && sym == nil => (FMOVSstoreidx4 ptr idx val mem) +(FMOVDstoreidx ptr (SLLconst [3] idx) val mem) => (FMOVDstoreidx8 ptr idx val mem) +(FMOVSstoreidx ptr (SLLconst [2] idx) val mem) => (FMOVSstoreidx4 ptr idx val mem) +(FMOVDstoreidx (SLLconst [3] idx) ptr val mem) => (FMOVDstoreidx8 ptr idx val mem) +(FMOVSstoreidx (SLLconst [2] idx) ptr val mem) => (FMOVSstoreidx4 ptr idx val mem) +(FMOVDstoreidx8 ptr (MOVDconst [c]) val mem) && is32Bit(c<<3) => (FMOVDstore [int32(c)<<3] ptr val mem) +(FMOVSstoreidx4 ptr (MOVDconst [c]) val mem) && is32Bit(c<<2) => (FMOVSstore [int32(c)<<2] ptr val mem) + (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) => diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index b0bc9c78ff..e826e75252 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -379,11 +379,13 @@ func init() { {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem. // shifted register indexed load - {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. - {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. - {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. + {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. + {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. + {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. + {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32"}, // load 32-bit float from arg0 + arg1*4, arg2 = mem. + {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1*8, arg2 = mem. {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. @@ -402,9 +404,11 @@ func init() { {name: "FMOVDstoreidx", argLength: 4, reg: fpstore2, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem. // shifted register indexed store - {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem. - {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem. - {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem. + {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem. + {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem. + {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem. + {name: "FMOVSstoreidx4", argLength: 4, reg: fpstore2, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem. + {name: "FMOVDstoreidx8", argLength: 4, reg: fpstore2, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem. {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem. {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem. diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index ba170968ae..551aa725b6 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -1481,6 +1481,8 @@ const ( OpARM64MOVWloadidx4 OpARM64MOVWUloadidx4 OpARM64MOVDloadidx8 + OpARM64FMOVSloadidx4 + OpARM64FMOVDloadidx8 OpARM64MOVBstore OpARM64MOVHstore OpARM64MOVWstore @@ -1497,6 +1499,8 @@ const ( OpARM64MOVHstoreidx2 OpARM64MOVWstoreidx4 OpARM64MOVDstoreidx8 + OpARM64FMOVSstoreidx4 + OpARM64FMOVDstoreidx8 OpARM64MOVBstorezero OpARM64MOVHstorezero OpARM64MOVWstorezero @@ -19787,6 +19791,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSloadidx4", + argLen: 3, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDloadidx8", + argLen: 3, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "MOVBstore", auxType: auxSymOff, @@ -19994,6 +20026,30 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSstoreidx4", + argLen: 4, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDstoreidx8", + argLen: 4, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "MOVBstorezero", auxType: auxSymOff, diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index ba146c7043..ece834f996 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -99,18 +99,26 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpARM64FMOVDload(v) case OpARM64FMOVDloadidx: return rewriteValueARM64_OpARM64FMOVDloadidx(v) + case OpARM64FMOVDloadidx8: + return rewriteValueARM64_OpARM64FMOVDloadidx8(v) case OpARM64FMOVDstore: return rewriteValueARM64_OpARM64FMOVDstore(v) case OpARM64FMOVDstoreidx: return rewriteValueARM64_OpARM64FMOVDstoreidx(v) + case OpARM64FMOVDstoreidx8: + return rewriteValueARM64_OpARM64FMOVDstoreidx8(v) case OpARM64FMOVSload: return rewriteValueARM64_OpARM64FMOVSload(v) case OpARM64FMOVSloadidx: return rewriteValueARM64_OpARM64FMOVSloadidx(v) + case OpARM64FMOVSloadidx4: + return rewriteValueARM64_OpARM64FMOVSloadidx4(v) case OpARM64FMOVSstore: return rewriteValueARM64_OpARM64FMOVSstore(v) case OpARM64FMOVSstoreidx: return rewriteValueARM64_OpARM64FMOVSstoreidx(v) + case OpARM64FMOVSstoreidx4: + return rewriteValueARM64_OpARM64FMOVSstoreidx4(v) case OpARM64FMULD: return rewriteValueARM64_OpARM64FMULD(v) case OpARM64FMULS: @@ -3900,6 +3908,25 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value) bool { v.AddArg3(ptr, idx, mem) return true } + // match: (FMOVDload [off] {sym} (ADDshiftLL [3] ptr idx) mem) + // cond: off == 0 && sym == nil + // result: (FMOVDloadidx8 ptr idx mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpARM64ADDshiftLL || auxIntToInt64(v_0.AuxInt) != 3 { + break + } + idx := v_0.Args[1] + ptr := v_0.Args[0] + mem := v_1 + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVDloadidx8) + v.AddArg3(ptr, idx, mem) + return true + } // match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) @@ -3964,6 +3991,56 @@ func rewriteValueARM64_OpARM64FMOVDloadidx(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (FMOVDloadidx ptr (SLLconst [3] idx) mem) + // result: (FMOVDloadidx8 ptr idx mem) + for { + ptr := v_0 + if v_1.Op != OpARM64SLLconst || auxIntToInt64(v_1.AuxInt) != 3 { + break + } + idx := v_1.Args[0] + mem := v_2 + v.reset(OpARM64FMOVDloadidx8) + v.AddArg3(ptr, idx, mem) + return true + } + // match: (FMOVDloadidx (SLLconst [3] idx) ptr mem) + // result: (FMOVDloadidx8 ptr idx mem) + for { + if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != 3 { + break + } + idx := v_0.Args[0] + ptr := v_1 + mem := v_2 + v.reset(OpARM64FMOVDloadidx8) + v.AddArg3(ptr, idx, mem) + return true + } + return false +} +func rewriteValueARM64_OpARM64FMOVDloadidx8(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (FMOVDloadidx8 ptr (MOVDconst [c]) mem) + // cond: is32Bit(c<<3) + // result: (FMOVDload ptr [int32(c)<<3] mem) + for { + ptr := v_0 + if v_1.Op != OpARM64MOVDconst { + break + } + c := auxIntToInt64(v_1.AuxInt) + mem := v_2 + if !(is32Bit(c << 3)) { + break + } + v.reset(OpARM64FMOVDload) + v.AuxInt = int32ToAuxInt(int32(c) << 3) + v.AddArg2(ptr, mem) + return true + } return false } func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { @@ -4031,6 +4108,26 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value) bool { v.AddArg4(ptr, idx, val, mem) return true } + // match: (FMOVDstore [off] {sym} (ADDshiftLL [3] ptr idx) val mem) + // cond: off == 0 && sym == nil + // result: (FMOVDstoreidx8 ptr idx val mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpARM64ADDshiftLL || auxIntToInt64(v_0.AuxInt) != 3 { + break + } + idx := v_0.Args[1] + ptr := v_0.Args[0] + val := v_1 + mem := v_2 + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVDstoreidx8) + v.AddArg4(ptr, idx, val, mem) + return true + } // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) @@ -4099,6 +4196,60 @@ func rewriteValueARM64_OpARM64FMOVDstoreidx(v *Value) bool { v.AddArg3(idx, val, mem) return true } + // match: (FMOVDstoreidx ptr (SLLconst [3] idx) val mem) + // result: (FMOVDstoreidx8 ptr idx val mem) + for { + ptr := v_0 + if v_1.Op != OpARM64SLLconst || auxIntToInt64(v_1.AuxInt) != 3 { + break + } + idx := v_1.Args[0] + val := v_2 + mem := v_3 + v.reset(OpARM64FMOVDstoreidx8) + v.AddArg4(ptr, idx, val, mem) + return true + } + // match: (FMOVDstoreidx (SLLconst [3] idx) ptr val mem) + // result: (FMOVDstoreidx8 ptr idx val mem) + for { + if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != 3 { + break + } + idx := v_0.Args[0] + ptr := v_1 + val := v_2 + mem := v_3 + v.reset(OpARM64FMOVDstoreidx8) + v.AddArg4(ptr, idx, val, mem) + return true + } + return false +} +func rewriteValueARM64_OpARM64FMOVDstoreidx8(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (FMOVDstoreidx8 ptr (MOVDconst [c]) val mem) + // cond: is32Bit(c<<3) + // result: (FMOVDstore [int32(c)<<3] ptr val mem) + for { + ptr := v_0 + if v_1.Op != OpARM64MOVDconst { + break + } + c := auxIntToInt64(v_1.AuxInt) + val := v_2 + mem := v_3 + if !(is32Bit(c << 3)) { + break + } + v.reset(OpARM64FMOVDstore) + v.AuxInt = int32ToAuxInt(int32(c) << 3) + v.AddArg3(ptr, val, mem) + return true + } return false } func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { @@ -4163,6 +4314,25 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value) bool { v.AddArg3(ptr, idx, mem) return true } + // match: (FMOVSload [off] {sym} (ADDshiftLL [2] ptr idx) mem) + // cond: off == 0 && sym == nil + // result: (FMOVSloadidx4 ptr idx mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpARM64ADDshiftLL || auxIntToInt64(v_0.AuxInt) != 2 { + break + } + idx := v_0.Args[1] + ptr := v_0.Args[0] + mem := v_1 + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVSloadidx4) + v.AddArg3(ptr, idx, mem) + return true + } // match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) @@ -4227,6 +4397,56 @@ func rewriteValueARM64_OpARM64FMOVSloadidx(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (FMOVSloadidx ptr (SLLconst [2] idx) mem) + // result: (FMOVSloadidx4 ptr idx mem) + for { + ptr := v_0 + if v_1.Op != OpARM64SLLconst || auxIntToInt64(v_1.AuxInt) != 2 { + break + } + idx := v_1.Args[0] + mem := v_2 + v.reset(OpARM64FMOVSloadidx4) + v.AddArg3(ptr, idx, mem) + return true + } + // match: (FMOVSloadidx (SLLconst [2] idx) ptr mem) + // result: (FMOVSloadidx4 ptr idx mem) + for { + if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != 2 { + break + } + idx := v_0.Args[0] + ptr := v_1 + mem := v_2 + v.reset(OpARM64FMOVSloadidx4) + v.AddArg3(ptr, idx, mem) + return true + } + return false +} +func rewriteValueARM64_OpARM64FMOVSloadidx4(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (FMOVSloadidx4 ptr (MOVDconst [c]) mem) + // cond: is32Bit(c<<2) + // result: (FMOVSload ptr [int32(c)<<2] mem) + for { + ptr := v_0 + if v_1.Op != OpARM64MOVDconst { + break + } + c := auxIntToInt64(v_1.AuxInt) + mem := v_2 + if !(is32Bit(c << 2)) { + break + } + v.reset(OpARM64FMOVSload) + v.AuxInt = int32ToAuxInt(int32(c) << 2) + v.AddArg2(ptr, mem) + return true + } return false } func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { @@ -4294,6 +4514,26 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value) bool { v.AddArg4(ptr, idx, val, mem) return true } + // match: (FMOVSstore [off] {sym} (ADDshiftLL [2] ptr idx) val mem) + // cond: off == 0 && sym == nil + // result: (FMOVSstoreidx4 ptr idx val mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpARM64ADDshiftLL || auxIntToInt64(v_0.AuxInt) != 2 { + break + } + idx := v_0.Args[1] + ptr := v_0.Args[0] + val := v_1 + mem := v_2 + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVSstoreidx4) + v.AddArg4(ptr, idx, val, mem) + return true + } // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) @@ -4362,6 +4602,60 @@ func rewriteValueARM64_OpARM64FMOVSstoreidx(v *Value) bool { v.AddArg3(idx, val, mem) return true } + // match: (FMOVSstoreidx ptr (SLLconst [2] idx) val mem) + // result: (FMOVSstoreidx4 ptr idx val mem) + for { + ptr := v_0 + if v_1.Op != OpARM64SLLconst || auxIntToInt64(v_1.AuxInt) != 2 { + break + } + idx := v_1.Args[0] + val := v_2 + mem := v_3 + v.reset(OpARM64FMOVSstoreidx4) + v.AddArg4(ptr, idx, val, mem) + return true + } + // match: (FMOVSstoreidx (SLLconst [2] idx) ptr val mem) + // result: (FMOVSstoreidx4 ptr idx val mem) + for { + if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != 2 { + break + } + idx := v_0.Args[0] + ptr := v_1 + val := v_2 + mem := v_3 + v.reset(OpARM64FMOVSstoreidx4) + v.AddArg4(ptr, idx, val, mem) + return true + } + return false +} +func rewriteValueARM64_OpARM64FMOVSstoreidx4(v *Value) bool { + v_3 := v.Args[3] + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (FMOVSstoreidx4 ptr (MOVDconst [c]) val mem) + // cond: is32Bit(c<<2) + // result: (FMOVSstore [int32(c)<<2] ptr val mem) + for { + ptr := v_0 + if v_1.Op != OpARM64MOVDconst { + break + } + c := auxIntToInt64(v_1.AuxInt) + val := v_2 + mem := v_3 + if !(is32Bit(c << 2)) { + break + } + v.reset(OpARM64FMOVSstore) + v.AuxInt = int32ToAuxInt(int32(c) << 2) + v.AddArg3(ptr, val, mem) + return true + } return false } func rewriteValueARM64_OpARM64FMULD(v *Value) bool { diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 83b4a358a5..397cbb82f7 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -53,12 +53,12 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) { } func indexLoad(b0 []float32, b1 float32, idx int) float32 { - // arm64:`FMOVS\s\(R[0-9]+\)\(R[0-9]+\),\sF[0-9]+` + // arm64:`FMOVS\s\(R[0-9]+\)\(R[0-9]+<<2\),\sF[0-9]+` return b0[idx] * b1 } func indexStore(b0 []float64, b1 float64, idx int) { - // arm64:`FMOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)` + // arm64:`FMOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<3\)` b0[idx] = b1 } diff --git a/test/codegen/memops.go b/test/codegen/memops.go index a234283146..7f06a574fe 100644 --- a/test/codegen/memops.go +++ b/test/codegen/memops.go @@ -177,9 +177,11 @@ func idxFloat32(x, y []float32, i int) { var t float32 // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` + // arm64: `FMOVS\t\(R[0-9]*\)\(R[0-9]*<<2\), F[0-9]+` t = x[i+1] // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` // 386/sse2: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // arm64: `FMOVS\tF[0-9]+, \(R[0-9]*\)\(R[0-9]*<<2\)` y[i+1] = t // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` @@ -193,9 +195,11 @@ func idxFloat64(x, y []float64, i int) { var t float64 // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` + // arm64: `FMOVD\t\(R[0-9]*\)\(R[0-9]*<<3\), F[0-9]+` t = x[i+1] // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` // 386/sse2: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + // arm64: `FMOVD\tF[0-9]+, \(R[0-9]*\)\(R[0-9]*<<3\)` y[i+1] = t // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` -- GitLab From 6c3f8a2f4730f005850be7fde3a3dac6dc5323a6 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 24 Feb 2021 11:48:09 -0800 Subject: [PATCH 0091/1298] cmd/link: use ctxt.Logf instead of package log Fixes #43601 Change-Id: I28b745cb92932d875a66f64c63355650a092f096 Reviewed-on: https://go-review.googlesource.com/c/go/+/296029 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/link/internal/ld/config.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 481dc67475..291b28e11c 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -8,7 +8,6 @@ import ( "cmd/internal/objabi" "cmd/internal/sys" "fmt" - "log" ) // A BuildMode indicates the sort of object we are building. @@ -181,7 +180,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { if ctxt.Debugvlog > 1 { defer func() { if res { - log.Printf("external linking is forced by: %s\n", reason) + ctxt.Logf("external linking is forced by: %s\n", reason) } }() } -- GitLab From 8027343b6395536aa8bef8158bad8f4c290dd650 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 24 Feb 2021 13:03:17 -0800 Subject: [PATCH 0092/1298] cmd/compile: disable inlining functions with closures for now Added a flag '-d=inlfuncswithclosures=1' to allow inlining functions with closures, and change the default to off for now, until #44370 is fixed. Updates #44370. Change-Id: Ic17723aa5c091d91f5f5004d8b63ec7125257acf Reviewed-on: https://go-review.googlesource.com/c/go/+/296049 Run-TryBot: Dan Scales Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot Trust: Dan Scales --- src/cmd/compile/internal/base/debug.go | 45 +++++++++++++------------- src/cmd/compile/internal/inline/inl.go | 12 +++---- test/closure3.go | 2 +- test/inline.go | 2 +- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go index 164941bb26..b9fa3d882e 100644 --- a/src/cmd/compile/internal/base/debug.go +++ b/src/cmd/compile/internal/base/debug.go @@ -29,28 +29,29 @@ var Debug = DebugFlags{ // The -d option takes a comma-separated list of settings. // Each setting is name=value; for ints, name is short for name=1. type DebugFlags struct { - Append int `help:"print information about append compilation"` - Checkptr int `help:"instrument unsafe pointer conversions"` - Closure int `help:"print information about closure compilation"` - DclStack int `help:"run internal dclstack check"` - Defer int `help:"print information about defer compilation"` - DisableNil int `help:"disable nil checks"` - DumpPtrs int `help:"show Node pointers values in dump output"` - DwarfInl int `help:"print information about DWARF inlined function creation"` - Export int `help:"print export data"` - Fieldtrack *int `help:"enable field tracking"` - GCProg int `help:"print dump of GC programs"` - Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"` - LocationLists int `help:"print information about DWARF location list creation"` - Nil int `help:"print information about nil checks"` - PCTab string `help:"print named pc-value table"` - Panic int `help:"show all compiler panics"` - Slice int `help:"print information about slice compilation"` - SoftFloat int `help:"force compiler to emit soft-float code"` - TypeAssert int `help:"print information about type assertion inlining"` - TypecheckInl int `help:"eager typechecking of inline function bodies"` - WB int `help:"print information about write barriers"` - ABIWrap int `help:"print information about ABI wrapper generation"` + Append int `help:"print information about append compilation"` + Checkptr int `help:"instrument unsafe pointer conversions"` + Closure int `help:"print information about closure compilation"` + DclStack int `help:"run internal dclstack check"` + Defer int `help:"print information about defer compilation"` + DisableNil int `help:"disable nil checks"` + DumpPtrs int `help:"show Node pointers values in dump output"` + DwarfInl int `help:"print information about DWARF inlined function creation"` + Export int `help:"print export data"` + Fieldtrack *int `help:"enable field tracking"` + GCProg int `help:"print dump of GC programs"` + InlFuncsWithClosures int `help:"allow functions with closures to be inlined"` + Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"` + LocationLists int `help:"print information about DWARF location list creation"` + Nil int `help:"print information about nil checks"` + PCTab string `help:"print named pc-value table"` + Panic int `help:"show all compiler panics"` + Slice int `help:"print information about slice compilation"` + SoftFloat int `help:"force compiler to emit soft-float code"` + TypeAssert int `help:"print information about type assertion inlining"` + TypecheckInl int `help:"eager typechecking of inline function bodies"` + WB int `help:"print information about write barriers"` + ABIWrap int `help:"print information about ABI wrapper generation"` any bool // set when any of the values have been set } diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 0e57c17667..fe6509e4c9 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -354,15 +354,15 @@ func (v *hairyVisitor) doNode(n ir.Node) bool { return true case ir.OCLOSURE: - // TODO(danscales,mdempsky): Get working with -G. - // Probably after #43818 is fixed. - if base.Flag.G > 0 { - v.reason = "inlining closures not yet working with -G" + if base.Debug.InlFuncsWithClosures == 0 { + // TODO(danscales): change default of InlFuncsWithClosures + // to 1 when #44370 is fixed + v.reason = "not inlining functions with closures" return true } - // TODO(danscales) - fix some bugs when budget is lowered below 15 - // Maybe make budget proportional to number of closure variables, e.g.: + // TODO(danscales): Maybe make budget proportional to number of closure + // variables, e.g.: //v.budget -= int32(len(n.(*ir.ClosureExpr).Func.ClosureVars) * 3) v.budget -= 15 // Scan body of closure (which DoChildren doesn't automatically diff --git a/test/closure3.go b/test/closure3.go index 37b548d6dc..452a52720a 100644 --- a/test/closure3.go +++ b/test/closure3.go @@ -1,4 +1,4 @@ -// errorcheckandrundir -0 -m +// errorcheckandrundir -0 -m -d=inlfuncswithclosures=1 // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/inline.go b/test/inline.go index a79f5589fb..44c746b282 100644 --- a/test/inline.go +++ b/test/inline.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m +// errorcheck -0 -m -d=inlfuncswithclosures=1 // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- GitLab From d0d21b7c4c92df8bf60059cbea4c20cfe4ae5fee Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 1 Feb 2021 13:26:47 -0500 Subject: [PATCH 0093/1298] cmd/compile: plumb abi info into expandCalls Work in progress. TODO: - insert debugging output for all the steps listed below - emit modified call instructions w/ multiple register inputs and Result-typed outputs (next CL) - initially just change output from "mem" to "Result{mem}" = most places this hits will be future work. - change OpArg to use registerized variants - (done) match abi paramresultinfo with particular arg, use Name - (this CL) push register offsets for "loads" and "stores" into recursive decomposition. - hand registerized Result to exit block For #40724. Change-Id: Ie5de9d71f8fd4e092f5ee9260b54de35abf91016 Reviewed-on: https://go-review.googlesource.com/c/go/+/293390 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/abi/abiutils.go | 68 ++-- src/cmd/compile/internal/ssa/expand_calls.go | 345 ++++++++++++++----- src/cmd/compile/internal/ssa/op.go | 16 +- 3 files changed, 312 insertions(+), 117 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 7b388ec3dc..4bd27efb59 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -30,6 +30,10 @@ type ABIParamResultInfo struct { config *ABIConfig // to enable String() method } +func (a *ABIParamResultInfo) Config() *ABIConfig { + return a.config +} + func (a *ABIParamResultInfo) InParams() []ABIParamAssignment { return a.inparams } @@ -68,10 +72,11 @@ type RegIndex uint8 // ABIParamAssignment holds information about how a specific param or // result will be passed: in registers (in which case 'Registers' is // populated) or on the stack (in which case 'Offset' is set to a -// non-negative stack offset. The values in 'Registers' are indices (as -// described above), not architected registers. +// non-negative stack offset. The values in 'Registers' are indices +// (as described above), not architected registers. type ABIParamAssignment struct { Type *types.Type + Name types.Object // should always be *ir.Name, used to match with a particular ssa.OpArg. Registers []RegIndex offset int32 } @@ -126,37 +131,36 @@ func (a *ABIConfig) Copy() *ABIConfig { // NumParamRegs returns the number of parameter registers used for a given type, // without regard for the number available. func (a *ABIConfig) NumParamRegs(t *types.Type) int { + var n int if n, ok := a.regsForTypeCache[t]; ok { return n } if t.IsScalar() || t.IsPtrShaped() { - var n int if t.IsComplex() { n = 2 } else { n = (int(t.Size()) + types.RegSize - 1) / types.RegSize } - a.regsForTypeCache[t] = n - return n - } - typ := t.Kind() - n := 0 - switch typ { - case types.TARRAY: - n = a.NumParamRegs(t.Elem()) * int(t.NumElem()) - case types.TSTRUCT: - for _, f := range t.FieldSlice() { - n += a.NumParamRegs(f.Type) + } else { + typ := t.Kind() + switch typ { + case types.TARRAY: + n = a.NumParamRegs(t.Elem()) * int(t.NumElem()) + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + n += a.NumParamRegs(f.Type) + } + case types.TSLICE: + n = a.NumParamRegs(synthSlice) + case types.TSTRING: + n = a.NumParamRegs(synthString) + case types.TINTER: + n = a.NumParamRegs(synthIface) } - case types.TSLICE: - n = a.NumParamRegs(synthSlice) - case types.TSTRING: - n = a.NumParamRegs(synthString) - case types.TINTER: - n = a.NumParamRegs(synthIface) } a.regsForTypeCache[t] = n + return n } @@ -176,14 +180,14 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { if t.NumRecvs() != 0 { rfsl := ft.Receiver.FieldSlice() result.inparams = append(result.inparams, - s.assignParamOrReturn(rfsl[0].Type, false)) + s.assignParamOrReturn(rfsl[0], false)) } // Inputs ifsl := ft.Params.FieldSlice() for _, f := range ifsl { result.inparams = append(result.inparams, - s.assignParamOrReturn(f.Type, false)) + s.assignParamOrReturn(f, false)) } s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) @@ -191,7 +195,7 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { s.rUsed = RegAmounts{} ofsl := ft.Results.FieldSlice() for _, f := range ofsl { - result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, true)) + result.outparams = append(result.outparams, s.assignParamOrReturn(f, true)) } // The spill area is at a register-aligned offset and its size is rounded up to a register alignment. // TODO in theory could align offset only to minimum required by spilled data types. @@ -299,7 +303,7 @@ func (state *assignState) allocateRegs() []RegIndex { // regAllocate creates a register ABIParamAssignment object for a param // or result with the specified type, as a final step (this assumes // that all of the safety/suitability analysis is complete). -func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssignment { +func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn bool) ABIParamAssignment { spillLoc := int64(-1) if !isReturn { // Spill for register-resident t must be aligned for storage of a t. @@ -308,6 +312,7 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi } return ABIParamAssignment{ Type: t, + Name: name, Registers: state.allocateRegs(), offset: int32(spillLoc), } @@ -316,9 +321,10 @@ func (state *assignState) regAllocate(t *types.Type, isReturn bool) ABIParamAssi // stackAllocate creates a stack memory ABIParamAssignment object for // a param or result with the specified type, as a final step (this // assumes that all of the safety/suitability analysis is complete). -func (state *assignState) stackAllocate(t *types.Type) ABIParamAssignment { +func (state *assignState) stackAllocate(t *types.Type, name types.Object) ABIParamAssignment { return ABIParamAssignment{ Type: t, + Name: name, offset: int32(state.stackSlot(t)), } } @@ -451,18 +457,20 @@ func (state *assignState) regassign(pt *types.Type) bool { } // assignParamOrReturn processes a given receiver, param, or result -// of type 'pt' to determine whether it can be register assigned. +// of field f to determine whether it can be register assigned. // The result of the analysis is recorded in the result // ABIParamResultInfo held in 'state'. -func (state *assignState) assignParamOrReturn(pt *types.Type, isReturn bool) ABIParamAssignment { +func (state *assignState) assignParamOrReturn(f *types.Field, isReturn bool) ABIParamAssignment { + // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters + pt := f.Type state.pUsed = RegAmounts{} if pt.Width == types.BADWIDTH { panic("should never happen") } else if pt.Width == 0 { - return state.stackAllocate(pt) + return state.stackAllocate(pt, f.Nname) } else if state.regassign(pt) { - return state.regAllocate(pt, isReturn) + return state.regAllocate(pt, f.Nname, isReturn) } else { - return state.stackAllocate(pt) + return state.stackAllocate(pt, f.Nname) } } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 579818e4f3..85d6fda427 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -5,6 +5,8 @@ package ssa import ( + "cmd/compile/internal/abi" + "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/src" "fmt" @@ -24,6 +26,8 @@ type offsetKey struct { pt *types.Type } +type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1. + func isBlockMultiValueExit(b *Block) bool { return (b.Kind == BlockRet || b.Kind == BlockRetJmp) && len(b.Controls) > 0 && b.Controls[0].Op == OpMakeResult } @@ -51,8 +55,107 @@ func removeTrivialWrapperTypes(t *types.Type) *types.Type { return t } +// A registerCursor tracks which register is used for an Arg or regValues, or a piece of such. +type registerCursor struct { + // TODO(register args) convert this to a generalized target cursor. + regsLen int // the number of registers available for this Arg/result (which is all in registers or not at all) + nextSlice Abi1RO // the next register/register-slice offset + config *abi.ABIConfig + regValues *[]*Value // values assigned to registers accumulate here +} + +// next effectively post-increments the register cursor; the receiver is advanced, +// the old value is returned. +func (c *registerCursor) next(t *types.Type) registerCursor { + rc := *c + if int(c.nextSlice) < c.regsLen { + w := c.config.NumParamRegs(t) + c.nextSlice += Abi1RO(w) + } + return rc +} + +// plus returns a register cursor offset from the original, without modifying the original. +func (c *registerCursor) plus(regWidth Abi1RO) registerCursor { + rc := *c + rc.nextSlice += regWidth + return rc +} + +const ( + // Register offsets for fields of built-in aggregate types; the ones not listed are zero. + RO_complex_imag = 1 + RO_string_len = 1 + RO_slice_len = 1 + RO_slice_cap = 2 + RO_iface_data = 1 +) + +func (x *expandState) regWidth(t *types.Type) Abi1RO { + return Abi1RO(x.abi1.NumParamRegs(t)) +} + +// regOffset returns the register offset of the i'th element of type t +func (x *expandState) regOffset(t *types.Type, i int) Abi1RO { + // TODO maybe cache this in a map if profiling recommends. + if i == 0 { + return 0 + } + if t.IsArray() { + return Abi1RO(i) * x.regWidth(t.Elem()) + } + if t.IsStruct() { + k := Abi1RO(0) + for j := 0; j < i; j++ { + k += x.regWidth(t.FieldType(j)) + } + return k + } + panic("Haven't implemented this case yet, do I need to?") +} + +// at returns the register cursor for component i of t, where the first +// component is numbered 0. +func (c *registerCursor) at(t *types.Type, i int) registerCursor { + rc := *c + if i == 0 || c.regsLen == 0 { + return rc + } + if t.IsArray() { + w := c.config.NumParamRegs(t.Elem()) + rc.nextSlice += Abi1RO(i * w) + return rc + } + if t.IsStruct() { + for j := 0; j < i; j++ { + rc.next(t.FieldType(j)) + } + return rc + } + panic("Haven't implemented this case yet, do I need to?") +} + +func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value) { + c.regsLen = len(regs) + c.nextSlice = 0 + if len(regs) == 0 { + return + } + c.config = info.Config() + c.regValues = result +} + +func (c *registerCursor) addArg(v *Value) { + *c.regValues = append(*c.regValues, v) +} + +func (c *registerCursor) hasRegs() bool { + return c.regsLen > 0 +} + type expandState struct { f *Func + abi1 *abi.ABIConfig debug bool canSSAType func(*types.Type) bool regSize int64 @@ -61,6 +164,8 @@ type expandState struct { ptrSize int64 hiOffset int64 lowOffset int64 + hiRo Abi1RO + loRo Abi1RO namedSelects map[*Value][]namedVal sdom SparseTree common map[selKey]*Value @@ -123,6 +228,18 @@ func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *t return locs } +// prAssignForArg returns the ABIParamAssignment for v, assumed to be an OpArg. +func (x *expandState) prAssignForArg(v *Value) abi.ABIParamAssignment { + name := v.Aux.(*ir.Name) + fPri := x.f.OwnAux.abiInfo + for _, a := range fPri.InParams() { + if a.Name == name { + return a + } + } + panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, fPri.InParams())) +} + // Calls that need lowering have some number of inputs, including a memory input, // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able. @@ -140,7 +257,7 @@ func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *t // It emits the code necessary to implement the leaf select operation that leads to the root. // // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory. -func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) []LocalSlot { +func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []LocalSlot { if x.debug { fmt.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset) } @@ -157,9 +274,13 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) } switch selector.Op { case OpArg: + paramAssignment := x.prAssignForArg(selector) + _ = paramAssignment + // TODO(register args) if !x.isAlreadyExpandedAggregateType(selector.Type) { if leafType == selector.Type { // OpIData leads us here, sometimes. leaf.copyOf(selector) + } else { x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString()) } @@ -228,6 +349,8 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) } case OpSelectN: + // TODO(register args) result case + // if applied to Op-mumble-call, the Aux tells us which result, regOffset specifies offset within result. If a register, should rewrite to OpSelectN for new call. // TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there. call := selector.Args[0] aux := call.Aux.(*AuxCall) @@ -264,9 +387,10 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) w := selector.Args[0] var ls []LocalSlot if w.Type.Kind() != types.TSTRUCT { // IData artifact - ls = x.rewriteSelect(leaf, w, offset) + ls = x.rewriteSelect(leaf, w, offset, regOffset) } else { - ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(int(selector.AuxInt))) + fldi := int(selector.AuxInt) + ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi)) if w.Op != OpIData { for _, l := range ls { locs = append(locs, x.f.fe.SplitStruct(l, int(selector.AuxInt))) @@ -276,30 +400,31 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) case OpArraySelect: w := selector.Args[0] - x.rewriteSelect(leaf, w, offset+selector.Type.Size()*selector.AuxInt) + index := selector.AuxInt + x.rewriteSelect(leaf, w, offset+selector.Type.Size()*index, regOffset+x.regOffset(w.Type, int(index))) case OpInt64Hi: w := selector.Args[0] - ls := x.rewriteSelect(leaf, w, offset+x.hiOffset) + ls := x.rewriteSelect(leaf, w, offset+x.hiOffset, regOffset+x.hiRo) locs = x.splitSlots(ls, ".hi", x.hiOffset, leafType) case OpInt64Lo: w := selector.Args[0] - ls := x.rewriteSelect(leaf, w, offset+x.lowOffset) + ls := x.rewriteSelect(leaf, w, offset+x.lowOffset, regOffset+x.loRo) locs = x.splitSlots(ls, ".lo", x.lowOffset, leafType) case OpStringPtr: - ls := x.rewriteSelect(leaf, selector.Args[0], offset) + ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset) locs = x.splitSlots(ls, ".ptr", 0, x.typs.BytePtr) case OpSlicePtr: w := selector.Args[0] - ls := x.rewriteSelect(leaf, w, offset) + ls := x.rewriteSelect(leaf, w, offset, regOffset) locs = x.splitSlots(ls, ".ptr", 0, types.NewPtr(w.Type.Elem())) case OpITab: w := selector.Args[0] - ls := x.rewriteSelect(leaf, w, offset) + ls := x.rewriteSelect(leaf, w, offset, regOffset) sfx := ".itab" if w.Type.IsEmptyInterface() { sfx = ".type" @@ -307,27 +432,27 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64) locs = x.splitSlots(ls, sfx, 0, x.typs.Uintptr) case OpComplexReal: - ls := x.rewriteSelect(leaf, selector.Args[0], offset) + ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset) locs = x.splitSlots(ls, ".real", 0, leafType) case OpComplexImag: - ls := x.rewriteSelect(leaf, selector.Args[0], offset+leafType.Width) // result is FloatNN, width of result is offset of imaginary part. + ls := x.rewriteSelect(leaf, selector.Args[0], offset+leafType.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part. locs = x.splitSlots(ls, ".imag", leafType.Width, leafType) case OpStringLen, OpSliceLen: - ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize) + ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_slice_len) locs = x.splitSlots(ls, ".len", x.ptrSize, leafType) case OpIData: - ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize) + ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_iface_data) locs = x.splitSlots(ls, ".data", x.ptrSize, leafType) case OpSliceCap: - ls := x.rewriteSelect(leaf, selector.Args[0], offset+2*x.ptrSize) + ls := x.rewriteSelect(leaf, selector.Args[0], offset+2*x.ptrSize, regOffset+RO_slice_cap) locs = x.splitSlots(ls, ".cap", 2*x.ptrSize, leafType) case OpCopy: // If it's an intermediate result, recurse - locs = x.rewriteSelect(leaf, selector.Args[0], offset) + locs = x.rewriteSelect(leaf, selector.Args[0], offset, regOffset) for _, s := range x.namedSelects[selector] { // this copy may have had its own name, preserve that, too. locs = append(locs, x.f.Names[s.locIndex]) @@ -361,23 +486,26 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, // decomposeArgOrLoad is a helper for storeArgOrLoad. // It decomposes a Load or an Arg into smaller parts, parameterized by the decomposeOne and decomposeTwo functions // passed to it, and returns the new mem. If the type does not match one of the expected aggregate types, it returns nil instead. -func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, - decomposeOne func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64) *Value, - decomposeTwo func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value) *Value { +func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor, + decomposeOne func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value, + decomposeTwo func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value { u := source.Type switch u.Kind() { case types.TARRAY: elem := u.Elem() + elemRO := x.regWidth(elem) for i := int64(0); i < u.NumElem(); i++ { elemOff := i * elem.Size() - mem = decomposeOne(x, pos, b, base, source, mem, elem, source.AuxInt+elemOff, offset+elemOff) + mem = decomposeOne(x, pos, b, base, source, mem, elem, source.AuxInt+elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) + loadRegOffset += elemRO pos = pos.WithNotStmt() } return mem case types.TSTRUCT: for i := 0; i < u.NumFields(); i++ { fld := u.Field(i) - mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, source.AuxInt+fld.Offset, offset+fld.Offset) + mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, source.AuxInt+fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } return mem @@ -386,20 +514,20 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m break } tHi, tLo := x.intPairTypes(t.Kind()) - mem = decomposeOne(x, pos, b, base, source, mem, tHi, source.AuxInt+x.hiOffset, offset+x.hiOffset) + mem = decomposeOne(x, pos, b, base, source, mem, tHi, source.AuxInt+x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() - return decomposeOne(x, pos, b, base, source, mem, tLo, source.AuxInt+x.lowOffset, offset+x.lowOffset) + return decomposeOne(x, pos, b, base, source, mem, tLo, source.AuxInt+x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) case types.TINTER: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, source.AuxInt, offset) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, source.AuxInt, offset, loadRegOffset, storeRc) case types.TSTRING: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, source.AuxInt, offset) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, source.AuxInt, offset, loadRegOffset, storeRc) case types.TCOMPLEX64: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, source.AuxInt, offset) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, source.AuxInt, offset, loadRegOffset, storeRc) case types.TCOMPLEX128: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, source.AuxInt, offset) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, source.AuxInt, offset, loadRegOffset, storeRc) case types.TSLICE: - mem = decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, source.AuxInt, offset) - return decomposeOne(x, pos, b, base, source, mem, x.typs.Int, source.AuxInt+2*x.ptrSize, offset+2*x.ptrSize) + mem = decomposeOne(x, pos, b, base, source, mem, x.typs.BytePtr, source.AuxInt, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Int, x.typs.Int, source.AuxInt+x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) } return nil } @@ -407,79 +535,85 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m // storeOneArg creates a decomposed (one step) arg that is then stored. // pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. -func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64) *Value { +func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + paramAssignment := x.prAssignForArg(source) + _ = paramAssignment + // TODO(register args) w := x.common[selKey{source, offArg, t.Width, t}] if w == nil { w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux) x.common[selKey{source, offArg, t.Width, t}] = w } - return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore) + return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc) } // storeOneLoad creates a decomposed (one step) load that is then stored. -func storeOneLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64) *Value { +func storeOneLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { from := x.offsetFrom(source.Args[0], offArg, types.NewPtr(t)) w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem) - return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore) + return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc) } -func storeTwoArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value { - mem = storeOneArg(x, pos, b, base, source, mem, t1, offArg, offStore) +func storeTwoArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + mem = storeOneArg(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) pos = pos.WithNotStmt() t1Size := t1.Size() - return storeOneArg(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size) + return storeOneArg(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) } -func storeTwoLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value { - mem = storeOneLoad(x, pos, b, base, source, mem, t1, offArg, offStore) +// storeTwoLoad creates a pair of decomposed (one step) loads that are then stored. +// the elements of the pair must not require any additional alignment. +func storeTwoLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + mem = storeOneLoad(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) pos = pos.WithNotStmt() t1Size := t1.Size() - return storeOneLoad(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size) + return storeOneLoad(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) } -// storeArgOrLoad converts stores of SSA-able aggregate arguments (passed to a call) into a series of primitive-typed +// storeArgOrLoad converts stores of SSA-able potentially aggregatable arguments (passed to a call) into a series of primitive-typed // stores of non-aggregate types. It recursively walks up a chain of selectors until it reaches a Load or an Arg. // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering. -func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64) *Value { +func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { if x.debug { fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %s; %d)\n", base.LongString(), source.LongString(), mem.String(), t.String(), offset) } switch source.Op { case OpCopy: - return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t, offset) + return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t, offset, loadRegOffset, storeRc) case OpLoad: - ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, storeOneLoad, storeTwoLoad) + ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad) if ret != nil { return ret } case OpArg: - ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, storeOneArg, storeTwoArg) + ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg) if ret != nil { return ret } case OpArrayMake0, OpStructMake0: + // TODO(register args) is this correct for registers? return mem case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4: for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) - mem = x.storeArgOrLoad(pos, b, base, source.Args[i], mem, fld.Type, offset+fld.Offset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type)) pos = pos.WithNotStmt() } return mem case OpArrayMake1: - return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t.Elem(), offset) + return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0)) case OpInt64Make: tHi, tLo := x.intPairTypes(t.Kind()) - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tHi, offset+x.hiOffset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tLo, offset+x.lowOffset) + return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc) case OpComplexMake: tPart := x.typs.Float32 @@ -487,25 +621,25 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * if wPart == 8 { tPart = x.typs.Float64 } - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tPart, offset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tPart, offset+wPart) + return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tPart, offset+wPart, 0, storeRc) case OpIMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.Uintptr, offset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize) + return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc) case OpStringMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize) + return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc) case OpSliceMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset) + mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - mem = x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize) - return x.storeArgOrLoad(pos, b, base, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize) + mem = x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int)) + return x.storeArgOrLoad(pos, b, base, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc) } // For nodes that cannot be taken apart -- OpSelectN, other structure selectors. @@ -515,11 +649,13 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == x.regSize { t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, base, source, mem, t, offset) + return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc) } + eltRO := x.regWidth(elt) for i := int64(0); i < t.NumElem(); i++ { sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, elt, offset+i*elt.Width) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0)) + loadRegOffset += eltRO pos = pos.WithNotStmt() } return mem @@ -546,13 +682,14 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * // of a *uint8, which does not succeed. t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, base, source, mem, t, offset) + return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc) } for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, fld.Type, offset+fld.Offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } return mem @@ -563,52 +700,58 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * } tHi, tLo := x.intPairTypes(t.Kind()) sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, tHi, offset+x.hiOffset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, tLo, offset+x.lowOffset) + return x.storeArgOrLoad(pos, b, base, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo)) case types.TINTER: sel := source.Block.NewValue1(pos, OpITab, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpIData, x.typs.BytePtr, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset+x.ptrSize) + return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc) case types.TSTRING: sel := source.Block.NewValue1(pos, OpStringPtr, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpStringLen, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize) + return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc) case types.TSLICE: et := types.NewPtr(t.Elem()) sel := source.Block.NewValue1(pos, OpSlicePtr, et, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, et, offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, et, offset, loadRegOffset, storeRc.next(et)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpSliceLen, x.typs.Int, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int)) sel = source.Block.NewValue1(pos, OpSliceCap, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+2*x.ptrSize) + return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc) case types.TCOMPLEX64: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float32, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float32, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset+4) + return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc) case types.TCOMPLEX128: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float64, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset) + mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float64, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset+8) + return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc) } - dst := x.offsetFrom(base, offset, types.NewPtr(t)) - s := b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) + s := mem + if storeRc.hasRegs() { + // TODO(register args) + storeRc.addArg(source) + } else { + dst := x.offsetFrom(base, offset, types.NewPtr(t)) + s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) + } if x.debug { fmt.Printf("\t\tstoreArg returns %s\n", s.LongString()) } @@ -624,6 +767,7 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { pos := v.Pos.WithNotStmt() m0 := v.MemoryArg() mem := m0 + allResults := []*Value{} for i, a := range v.Args { if i < firstArg { continue @@ -632,18 +776,31 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { break } auxI := int64(i - firstArg) + aRegs := aux.RegsOfArg(auxI) + aOffset := aux.OffsetOfArg(auxI) + aType := aux.TypeOfArg(auxI) if a.Op == OpDereference { if a.MemoryArg() != m0 { x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString()) } + if len(aRegs) > 0 { + x.f.Fatalf("Not implemented yet, not-SSA-type %v passed in registers", aType) + } // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move - // TODO this will be more complicated with registers in the picture. - mem = x.rewriteDereference(v.Block, x.sp, a, mem, aux.OffsetOfArg(auxI), aux.SizeOfArg(auxI), aux.TypeOfArg(auxI), pos) + // TODO(register args) this will be more complicated with registers in the picture. + mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos) } else { if x.debug { - fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI)) + fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) + } + var rc registerCursor + var result *[]*Value + if len(aRegs) > 0 { + result = &allResults } - mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI)) + rc.init(aRegs, aux.abiInfo, result) + mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc) + // TODO append mem to Result, update type } } v.resetArgs() @@ -667,6 +824,7 @@ func expandCalls(f *Func) { sp, _ := f.spSb() x := &expandState{ f: f, + abi1: f.ABI1, debug: f.pass.debug > 0, canSSAType: f.fe.CanSSA, regSize: f.Config.RegSize, @@ -681,9 +839,11 @@ func expandCalls(f *Func) { // For 32-bit, need to deal with decomposition of 64-bit integers, which depends on endianness. if f.Config.BigEndian { - x.lowOffset = 4 + x.lowOffset, x.hiOffset = 4, 0 + x.loRo, x.hiRo = 1, 0 } else { - x.hiOffset = 4 + x.lowOffset, x.hiOffset = 0, 4 + x.loRo, x.hiRo = 0, 1 } if x.debug { @@ -692,7 +852,7 @@ func expandCalls(f *Func) { // TODO if too slow, whole program iteration can be replaced w/ slices of appropriate values, accumulated in first loop here. - // Step 0: rewrite the calls to convert incoming args to stores. + // Step 0: rewrite the calls to convert args to calls into stores/register movement. for _, b := range f.Blocks { for _, v := range b.Values { switch v.Op { @@ -717,6 +877,7 @@ func expandCalls(f *Func) { mem := m0 aux := f.OwnAux pos := v.Pos.WithNotStmt() + allResults := []*Value{} for j, a := range v.Args { i := int64(j) if a == m0 { @@ -726,7 +887,11 @@ func expandCalls(f *Func) { auxBase := b.NewValue2A(v.Pos, OpLocalAddr, types.NewPtr(auxType), aux.results[i].Name, x.sp, mem) auxOffset := int64(0) auxSize := aux.SizeOfResult(i) + aRegs := aux.RegsOfResult(int64(j)) if a.Op == OpDereference { + if len(aRegs) > 0 { + x.f.Fatalf("Not implemented yet, not-SSA-type %v returned in register", auxType) + } // Avoid a self-move, and if one is detected try to remove the already-inserted VarDef for the assignment that won't happen. if dAddr, dMem := a.Args[0], a.Args[1]; dAddr.Op == OpLocalAddr && dAddr.Args[0].Op == OpSP && dAddr.Args[1] == dMem && dAddr.Aux == aux.results[i].Name { @@ -738,12 +903,20 @@ func expandCalls(f *Func) { mem = x.rewriteDereference(v.Block, auxBase, a, mem, auxOffset, auxSize, auxType, pos) } else { if a.Op == OpLoad && a.Args[0].Op == OpLocalAddr { - addr := a.Args[0] + addr := a.Args[0] // This is a self-move. // TODO(register args) do what here for registers? if addr.MemoryArg() == a.MemoryArg() && addr.Aux == aux.results[i].Name { continue } } - mem = x.storeArgOrLoad(v.Pos, b, auxBase, a, mem, aux.TypeOfResult(i), auxOffset) + var rc registerCursor + var result *[]*Value + if len(aRegs) > 0 { + result = &allResults + } + rc.init(aRegs, aux.abiInfo, result) + // TODO(register args) + mem = x.storeArgOrLoad(v.Pos, b, auxBase, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc) + // TODO append mem to Result, update type } } b.SetControl(mem) @@ -786,7 +959,7 @@ func expandCalls(f *Func) { fmt.Printf("Splitting store %s\n", v.LongString()) } dst, mem := v.Args[0], v.Args[2] - mem = x.storeArgOrLoad(v.Pos, b, dst, source, mem, t, 0) + mem = x.storeArgOrLoad(v.Pos, b, dst, source, mem, t, 0, 0, registerCursor{}) v.copyOf(mem) } } @@ -973,7 +1146,7 @@ func expandCalls(f *Func) { if v.Op == OpCopy { continue } - locs := x.rewriteSelect(v, v, 0) + locs := x.rewriteSelect(v, v, 0, 0) // Install new names. if v.Type.IsMemory() { continue diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 4bda7369bb..55e0602f2f 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -105,16 +105,29 @@ func (a *AuxCall) OffsetOfResult(which int64) int64 { } // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). +// If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) OffsetOfArg(which int64) int64 { return int64(a.args[which].Offset) } +// RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). +func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex { + return a.results[which].Reg +} + +// RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc). +// If the call is to a method, the receiver is the first argument (i.e., index 0) +func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex { + return a.args[which].Reg +} + // TypeOfResult returns the type of result which (indexed 0, 1, etc). func (a *AuxCall) TypeOfResult(which int64) *types.Type { return a.results[which].Type } // TypeOfArg returns the type of argument which (indexed 0, 1, etc). +// If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) TypeOfArg(which int64) *types.Type { return a.args[which].Type } @@ -125,6 +138,7 @@ func (a *AuxCall) SizeOfResult(which int64) int64 { } // SizeOfArg returns the size of argument which (indexed 0, 1, etc). +// If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) SizeOfArg(which int64) int64 { return a.TypeOfArg(which).Width } @@ -145,7 +159,7 @@ func (a *AuxCall) LateExpansionResultType() *types.Type { return types.NewResults(tys) } -// NArgs returns the number of arguments +// NArgs returns the number of arguments (including receiver, if there is one). func (a *AuxCall) NArgs() int64 { return int64(len(a.args)) } -- GitLab From dbbc5ec7e87f1976188c57ce4fb0d41e324df687 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 24 Feb 2021 22:59:59 +0100 Subject: [PATCH 0094/1298] syscall: restore broken GetQueuedCompletionStatus signature but make it not crash This reverts commit dc4698f52b5ad3f0251e0cc25bc7ffbd10e23f2c, and then fixes the memory corruption issue. It also suggests users switch to x/sys/windows for the proper function. This requires CL 295174 to be submitted first. Updates #44538. Change-Id: I0ee602f1c1d6a89cc585aff426833a4cb3f2be50 Reviewed-on: https://go-review.googlesource.com/c/go/+/296149 Trust: Jason A. Donenfeld Trust: Bryan C. Mills Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- api/except.txt | 6 ------ src/syscall/syscall_windows.go | 31 ++++++++++++++++++++++++++++--- src/syscall/zsyscall_windows.go | 6 +++--- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/api/except.txt b/api/except.txt index 1ddc397d11..6f6f839ba6 100644 --- a/api/except.txt +++ b/api/except.txt @@ -471,9 +471,6 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32 pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 -pkg syscall (windows-386), func CreateIoCompletionPort(Handle, Handle, uint32, uint32) (Handle, error) -pkg syscall (windows-386), func GetQueuedCompletionStatus(Handle, *uint32, *uint32, **Overlapped, uint32) error -pkg syscall (windows-386), func PostQueuedCompletionStatus(Handle, uint32, uint32, *Overlapped) error pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr @@ -483,9 +480,6 @@ pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintp pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr pkg syscall (windows-386), type RawSockaddrAny struct, Pad [96]int8 pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 -pkg syscall (windows-amd64), func CreateIoCompletionPort(Handle, Handle, uint32, uint32) (Handle, error) -pkg syscall (windows-amd64), func GetQueuedCompletionStatus(Handle, *uint32, *uint32, **Overlapped, uint32) error -pkg syscall (windows-amd64), func PostQueuedCompletionStatus(Handle, uint32, uint32, *Overlapped) error pkg syscall (windows-amd64), type AddrinfoW struct, Addr uintptr pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index a958f7aa84..5310f2da80 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -213,9 +213,9 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetEndOfFile(handle Handle) (err error) //sys GetSystemTimeAsFileTime(time *Filetime) //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] -//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) -//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) -//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) +//sys createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) = PostQueuedCompletionStatus //sys CancelIo(s Handle) (err error) //sys CancelIoEx(s Handle, o *Overlapped) (err error) //sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW @@ -1212,3 +1212,28 @@ func Readlink(path string, buf []byte) (n int, err error) { return n, nil } + +// Deprecated: CreateIoCompletionPort has the wrong function signature. Use x/sys/windows.CreateIoCompletionPort. +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (Handle, error) { + return createIoCompletionPort(filehandle, cphandle, uintptr(key), threadcnt) +} + +// Deprecated: GetQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.GetQueuedCompletionStatus. +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) error { + var ukey uintptr + var pukey *uintptr + if key != nil { + ukey = uintptr(*key) + pukey = &ukey + } + err := getQueuedCompletionStatus(cphandle, qty, pukey, overlapped, timeout) + if key != nil { + *key = uint32(ukey) + } + return err +} + +// Deprecated: PostQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.PostQueuedCompletionStatus. +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) error { + return postQueuedCompletionStatus(cphandle, qty, uintptr(key), overlapped) +} diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index cc44e31a85..b1480ba7df 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -515,7 +515,7 @@ func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr return } -func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { +func createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) handle = Handle(r0) if handle == 0 { @@ -822,7 +822,7 @@ func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, return } -func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { +func getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) if r1 == 0 { err = errnoErr(e1) @@ -954,7 +954,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err return } -func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { +func postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) if r1 == 0 { err = errnoErr(e1) -- GitLab From ff614b13d90961f55b1058bd798c6d4e92d3939c Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 25 Feb 2021 01:29:58 +0100 Subject: [PATCH 0095/1298] runtime: subtract one from ip when determining abort On windows/arm, the abort is given from one byte off of the function address, perhaps because Windows wants to simulate x86/amd64 modes, or because it's jumping from thumb mode. This is not the case with windows/arm64, though. This prevents a failure in the builders with the TestAbort test: crash_test.go:727: output contains BAD: panic: runtime error: invalid memory address or nil pointer dereference [recovered] panic: BAD: recovered from abort [signal 0xc0000005 code=0x0 addr=0x0 pc=0x6a5721] Change-Id: I8939c60611863cc0c325e179a772601acea9fd4a Reviewed-on: https://go-review.googlesource.com/c/go/+/296153 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/runtime/signal_windows.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index 6215d0ba2d..63158f0bc4 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -45,9 +45,10 @@ func initExceptionHandler() { //go:nosplit func isAbort(r *context) bool { pc := r.ip() - if GOARCH == "386" || GOARCH == "amd64" { + if GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm" { // In the case of an abort, the exception IP is one byte after - // the INT3 (this differs from UNIX OSes). + // the INT3 (this differs from UNIX OSes). Note that on ARM, + // this means that the exception IP is no longer aligned. pc-- } return isAbortPC(pc) -- GitLab From d822ffebc59d27190ac145a71c726dad35769225 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Wed, 24 Feb 2021 21:08:52 +0200 Subject: [PATCH 0096/1298] test: fix inline.go test for linux-amd64-noopt math.Float32bits was not being inlined across package boundaries. Create a private func that can be inlined with -l. Change-Id: Ic50bf4727dd8ade09d011eb204006b7ee88db34a Reviewed-on: https://go-review.googlesource.com/c/go/+/295989 Reviewed-by: Josh Bleecher Snyder Reviewed-by: Bryan C. Mills Reviewed-by: Keith Randall Trust: Josh Bleecher Snyder Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- test/inline.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/inline.go b/test/inline.go index 44c746b282..bc23768d01 100644 --- a/test/inline.go +++ b/test/inline.go @@ -10,7 +10,6 @@ package foo import ( - "math" "runtime" "unsafe" ) @@ -267,12 +266,18 @@ func gd3() func() { // ERROR "can inline gd3" // Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost. func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape" _ = d[:6] - d[0] = math.Float32bits(x[0]) // ERROR "inlining call to math.Float32bits" - d[1] = math.Float32bits(x[1]) // ERROR "inlining call to math.Float32bits" - d[2] = math.Float32bits(x[2]) // ERROR "inlining call to math.Float32bits" - d[3] = math.Float32bits(x[3]) // ERROR "inlining call to math.Float32bits" - d[4] = math.Float32bits(x[4]) // ERROR "inlining call to math.Float32bits" - d[5] = math.Float32bits(x[5]) // ERROR "inlining call to math.Float32bits" + d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits" + d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits" + d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits" + d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits" + d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits" + d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits" +} + +// float32bits is a copy of math.Float32bits to ensure that +// these tests pass with `-gcflags=-l`. +func float32bits(f float32) uint32 { // ERROR "can inline float32bits" + return *(*uint32)(unsafe.Pointer(&f)) } // Ensure OCONVNOP is zero cost. -- GitLab From 666ad85df450e3a54a77954f97423980b6ac064f Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Thu, 25 Feb 2021 03:03:45 +0000 Subject: [PATCH 0097/1298] cmd/compile: fix typo in rewrite_test.go insted -> instead Change-Id: Ib8a0423cf99f615976f058468873fb576dd96db6 GitHub-Last-Rev: 8e1a1d08807a35c55d65a2e3f8bb28418a43b3a8 GitHub-Pull-Request: golang/go#44598 Reviewed-on: https://go-review.googlesource.com/c/go/+/296309 Reviewed-by: Keith Randall Trust: Josh Bleecher Snyder Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/cmd/compile/internal/ssa/rewrite_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go index 6fe429e85a..272b080d88 100644 --- a/src/cmd/compile/internal/ssa/rewrite_test.go +++ b/src/cmd/compile/internal/ssa/rewrite_test.go @@ -13,7 +13,7 @@ func TestMove(t *testing.T) { copy(x[1:], x[:]) for i := 1; i < len(x); i++ { if int(x[i]) != i { - t.Errorf("Memmove got converted to OpMove in alias-unsafe way. Got %d insted of %d in position %d", int(x[i]), i, i+1) + t.Errorf("Memmove got converted to OpMove in alias-unsafe way. Got %d instead of %d in position %d", int(x[i]), i, i+1) } } } -- GitLab From 76c0003cd5645078e342c1d24c98b3ce5ae42eb4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 23 Feb 2021 14:58:32 +0100 Subject: [PATCH 0098/1298] syscall, os: use pipe2 syscall on DragonflyBSD instead of pipe Follow the implementation used by the other BSDs and account for the intricacy of having to pass the fds array even though the file descriptors are returned. Re-submit of CL 130996 with corrected pipe2 wrapper. Change-Id: Ie36d8214cba60c4fdb579f18bfc1c1ab3ead3ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/295372 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/os/pipe2_bsd.go | 4 ++-- src/os/pipe_bsd.go | 4 ++-- src/syscall/forkpipe.go | 4 ++-- src/syscall/forkpipe2.go | 4 ++-- src/syscall/syscall_dragonfly.go | 13 +++++++++++++ src/syscall/zsyscall_dragonfly_amd64.go | 12 ++++++++++++ src/syscall/zsysnum_dragonfly_amd64.go | 1 + 7 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/os/pipe2_bsd.go b/src/os/pipe2_bsd.go index 0af8019525..bf6d081db5 100644 --- a/src/os/pipe2_bsd.go +++ b/src/os/pipe2_bsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || netbsd || openbsd -// +build freebsd netbsd openbsd +//go:build dragonfly || freebsd || netbsd || openbsd +// +build dragonfly freebsd netbsd openbsd package os diff --git a/src/os/pipe_bsd.go b/src/os/pipe_bsd.go index 57959a2ea4..097b32e7eb 100644 --- a/src/os/pipe_bsd.go +++ b/src/os/pipe_bsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly || (js && wasm) || (solaris && !illumos) -// +build aix darwin dragonfly js,wasm solaris,!illumos +//go:build aix || darwin || (js && wasm) || (solaris && !illumos) +// +build aix darwin js,wasm solaris,!illumos package os diff --git a/src/syscall/forkpipe.go b/src/syscall/forkpipe.go index c7ddcf26ab..79cbdf4150 100644 --- a/src/syscall/forkpipe.go +++ b/src/syscall/forkpipe.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly || solaris -// +build aix darwin dragonfly solaris +//go:build aix || darwin || solaris +// +build aix darwin solaris package syscall diff --git a/src/syscall/forkpipe2.go b/src/syscall/forkpipe2.go index cd98779ac9..e57240c156 100644 --- a/src/syscall/forkpipe2.go +++ b/src/syscall/forkpipe2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || netbsd || openbsd -// +build freebsd netbsd openbsd +//go:build dragonfly || freebsd || netbsd || openbsd +// +build dragonfly freebsd netbsd openbsd package syscall diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go index 0988fe4608..b01a4ada67 100644 --- a/src/syscall/syscall_dragonfly.go +++ b/src/syscall/syscall_dragonfly.go @@ -100,6 +100,19 @@ func Pipe(p []int) (err error) { return } +//sysnb pipe2(p *[2]_C_int, flags int) (r int, w int, err error) + +func Pipe2(p []int, flags int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + // pipe2 on dragonfly takes an fds array as an argument, but still + // returns the file descriptors. + p[0], p[1], err = pipe2(&pp, flags) + return err +} + //sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error) func Pread(fd int, p []byte, offset int64) (n int, err error) { return extpread(fd, p, 0, offset) diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 4799d1dcb0..aa327c0010 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -274,6 +274,18 @@ func pipe() (r int, w int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func pipe2(p *[2]_C_int, flags int) (r int, w int, err error) { + r0, r1, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + r = int(r0) + w = int(r1) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go index 855188f045..ae504a5f0c 100644 --- a/src/syscall/zsysnum_dragonfly_amd64.go +++ b/src/syscall/zsysnum_dragonfly_amd64.go @@ -302,6 +302,7 @@ const ( SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); } SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); } SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); } + SYS_PIPE2 = 538 // { int pipe2(int *fildes, int flags); } SYS_UTIMENSAT = 539 // { int utimensat(int fd, const char *path, const struct timespec *ts, int flags); } SYS_ACCEPT4 = 541 // { int accept4(int s, caddr_t name, int *anamelen, int flags); } ) -- GitLab From 37ca84a9cd6a8a76dfe91263a17d2b92b17a24b3 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 25 Feb 2021 02:58:04 +0100 Subject: [PATCH 0099/1298] syscall: return error if GetQueuedCompletionStatus truncates key This function has the wrong signature, so return an error when that actually might lead to unexpected results. Users should switch to x/sys/windows for the real version of this function. Updates #44538. Change-Id: I4d1f3d1e380815733ecfea683f939b1d25dcc32a Reviewed-on: https://go-review.googlesource.com/c/go/+/296154 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Ian Lance Taylor --- src/syscall/syscall_windows.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 5310f2da80..ee5311b176 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -1229,6 +1229,9 @@ func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overla err := getQueuedCompletionStatus(cphandle, qty, pukey, overlapped, timeout) if key != nil { *key = uint32(ukey) + if uintptr(*key) != ukey && err == nil { + err = errorspkg.New("GetQueuedCompletionStatus returned key overflow") + } } return err } -- GitLab From ad17b65b340d5a40d0da1b4cbcdc239061e97c65 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 21 Feb 2021 15:28:41 -0800 Subject: [PATCH 0100/1298] testing/fstest: treat dash specially when building glob "[-]" is not a valid path.Match pattern. Fixes #44474 Change-Id: I0932bbf08ffb8ad0c5337d69d0893f53c1ba89ad Reviewed-on: https://go-review.googlesource.com/c/go/+/294869 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/testing/fstest/testfs.go | 2 +- src/testing/fstest/testfs_test.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 8fc8acaaf3..736bbf0590 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -303,7 +303,7 @@ func (t *fsTester) checkGlob(dir string, list []fs.DirEntry) { for i, e := range elem { var pattern []rune for j, r := range e { - if r == '*' || r == '?' || r == '\\' || r == '[' { + if r == '*' || r == '?' || r == '\\' || r == '[' || r == '-' { pattern = append(pattern, '\\', r) continue } diff --git a/src/testing/fstest/testfs_test.go b/src/testing/fstest/testfs_test.go index 5b8813c343..aefb4b3361 100644 --- a/src/testing/fstest/testfs_test.go +++ b/src/testing/fstest/testfs_test.go @@ -29,3 +29,12 @@ func TestSymlink(t *testing.T) { t.Fatal(err) } } + +func TestDash(t *testing.T) { + m := MapFS{ + "a-b/a": {Data: []byte("a-b/a")}, + } + if err := TestFS(m, "a-b/a"); err != nil { + t.Error(err) + } +} -- GitLab From 9fe8ebf9b49e632db54aa60809e2019a2a87e28b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 14 Feb 2021 17:59:48 -0800 Subject: [PATCH 0101/1298] test: add test case that failed with gccgo bug511.dir/b.go:10:14: error: reference to undefined field or method 'M' Change-Id: I9f96dc5c7254b310bc3e15b0bc588d62718cb4b2 Reviewed-on: https://go-review.googlesource.com/c/go/+/292009 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: Cherry Zhang --- test/fixedbugs/bug511.dir/a.go | 11 +++++++++++ test/fixedbugs/bug511.dir/b.go | 11 +++++++++++ test/fixedbugs/bug511.go | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100644 test/fixedbugs/bug511.dir/a.go create mode 100644 test/fixedbugs/bug511.dir/b.go create mode 100644 test/fixedbugs/bug511.go diff --git a/test/fixedbugs/bug511.dir/a.go b/test/fixedbugs/bug511.dir/a.go new file mode 100644 index 0000000000..33931a07a8 --- /dev/null +++ b/test/fixedbugs/bug511.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 a + +type S struct{} + +type A = S + +func (A) M() {} diff --git a/test/fixedbugs/bug511.dir/b.go b/test/fixedbugs/bug511.dir/b.go new file mode 100644 index 0000000000..f8877d6afd --- /dev/null +++ b/test/fixedbugs/bug511.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 b + +import "./a" + +func F() { + a.S{}.M() +} diff --git a/test/fixedbugs/bug511.go b/test/fixedbugs/bug511.go new file mode 100644 index 0000000000..edd3a23521 --- /dev/null +++ b/test/fixedbugs/bug511.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2021 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. + +// Gccgo mishandled type aliases as receiver types. + +package ignored -- GitLab From 2c4c189bba57a4a72c371afa7e544c16abd76ffa Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 18 Feb 2021 20:20:12 -0500 Subject: [PATCH 0102/1298] cmd/go/internal/mvs: add test cases for downgrade interaction with hidden versions For #36460 Change-Id: I889c4ece0d2caff7528cf437f89f7446dbd83955 Reviewed-on: https://go-review.googlesource.com/c/go/+/294292 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob Reviewed-by: Jay Conrod --- src/cmd/go/internal/mvs/mvs_test.go | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go index 742e396e0d..661f68be08 100644 --- a/src/cmd/go/internal/mvs/mvs_test.go +++ b/src/cmd/go/internal/mvs/mvs_test.go @@ -275,6 +275,59 @@ B1: build A: A B2 downgrade A B1: A B1 +# Both B3 and C2 require D2. +# If we downgrade D to D1, then in isolation B3 would downgrade to B1, +# because B2 is hidden — B1 is the next-highest version that is not hidden. +# However, if we downgrade D, we will also downgrade C to C1. +# And C1 requires B2.hidden, and B2.hidden also meets our requirements: +# it is compatible with D1 and a strict downgrade from B3. +# +# BUG(?): B2.hidden does not require E1, so there is no need for E1 +# to appear in the final build list. Nonetheless, there it is. +# +name: downhiddenartifact +A: B3 C2 +A1: B3 +B1: E1 +B2.hidden: +B3: D2 +C1: B2.hidden +C2: D2 +D1: +D2: +build A1: A1 B3 D2 +downgrade A1 D1: A1 B1 D1 E1 +build A: A B3 C2 D2 +downgrade A D1: A B2.hidden C1 D1 E1 + +# Both B3 and C3 require D2. +# If we downgrade D to D1, then in isolation B3 would downgrade to B1, +# and C3 would downgrade to C1. +# But C1 requires B2.hidden, and B1 requires C2.hidden, so we can't +# downgrade to either of those without pulling the other back up a little. +# +# B2.hidden and C2.hidden are both compatible with D1, so that still +# meets our requirements — but then we're in an odd state in which +# B and C have both been downgraded to hidden versions, without any +# remaining requirements to explain how those hidden versions got there. +# +# TODO(bcmills): Would it be better to force downgrades to land on non-hidden +# versions? +# In this case, that would remove the dependencies on B and C entirely. +# +name: downhiddencross +A: B3 C3 +B1: C2.hidden +B2.hidden: +B3: D2 +C1: B2.hidden +C2.hidden: +C3: D2 +D1: +D2: +build A: A B3 C3 D2 +downgrade A D1: A B2.hidden C2.hidden D1 + # golang.org/issue/25542. name: noprev1 A: B4 C2 -- GitLab From 3137da82fd74d534fff59092329c0ca820ff6589 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 19 Feb 2021 14:41:02 -0500 Subject: [PATCH 0103/1298] cmd/go: add a script test corresponding to the downhiddenartifact MVS test For #36460 Change-Id: I95abff45bb325732a19eb8b9c0d3fc34df08b4d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/294293 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob Reviewed-by: Jay Conrod --- .../script/mod_get_downup_pseudo_artifact.txt | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt diff --git a/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt new file mode 100644 index 0000000000..d773f6bd4d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt @@ -0,0 +1,132 @@ +# This test illustrates a case where an upgrade–downgrade–upgrade cycle could +# add extraneous dependencies due to another module depending on an +# otherwise-unlisted version (such as a pseudo-version). +# +# This case corresponds to the "downhiddenartifact" test in the mvs package. + +# The initial package import graph used in the test looks like: +# +# a --- b +# \ \ +# \ \ +# c --- d +# +# The module dependency graph initially looks like: +# +# a --- b.3 +# \ \ +# \ \ +# c.2 --- d.2 +# +# c.1 --- b.2 (pseudo) +# +# b.1 --- e.1 + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go get -d example.net/d@v0.1.0 + +go list -m all +stdout '^example.net/b v0.2.1-0.20210219000000-000000000000 ' +stdout '^example.net/c v0.1.0 ' +stdout '^example.net/d v0.1.0 ' + + # BUG: A dependency on e is added even though nothing requires it. +stdout '^example.net/e ' + +go mod why -m example.net/e +stdout '^\(main module does not need module example.net/e\)' + +-- go.mod -- +module example.net/a + +go 1.16 + +require ( + example.net/b v0.3.0 + example.net/c v0.2.0 +) + +replace ( + example.net/b v0.1.0 => ./b1 + example.net/b v0.2.1-0.20210219000000-000000000000 => ./b2 + example.net/b v0.3.0 => ./b3 + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c2 + example.net/d v0.1.0 => ./d + example.net/d v0.2.0 => ./d + example.net/e v0.1.0 => ./e +) +-- a.go -- +package a + +import ( + _ "example.net/b" + _ "example.net/c" +) + +-- b1/go.mod -- +module example.net/b + +go 1.16 + +require example.net/e v0.1.0 +-- b1/b.go -- +package b + +import _ "example.net/e" + +-- b2/go.mod -- +module example.net/b + +go 1.16 +-- b2/b.go -- +package b + +-- b3/go.mod -- +module example.net/b + +go 1.16 + +require example.net/d v0.2.0 +-- b3/b.go -- +package b + +import _ "example.net/d" +-- c1/go.mod -- +module example.net/c + +go 1.16 + +require example.net/b v0.2.1-0.20210219000000-000000000000 +-- c1/c.go -- +package c + +import _ "example.net/b" + +-- c2/go.mod -- +module example.net/c + +go 1.16 + +require example.net/d v0.2.0 +-- c2/c.go -- +package c + +import _ "example.net/d" + +-- d/go.mod -- +module example.net/d + +go 1.16 +-- d/d.go -- +package d + +-- e/go.mod -- +module example.net/e + +go 1.16 +-- e/e.go -- +package e -- GitLab From bcac57f89c0ec609e6fbebcbcd42bb73fdaef2f0 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 24 Feb 2021 18:24:45 -0500 Subject: [PATCH 0104/1298] cmd: upgrade golang.org/x/mod to fix go.mod parser modfile.Parse passed an empty string to the VersionFixer for the module path. This caused errors for v2+ versions. Fixes #44494 Change-Id: I13b86b6ecf6815c4bc9a96ec0668284c9228c205 Reviewed-on: https://go-review.googlesource.com/c/go/+/296131 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- .../script/mod_retract_fix_version.txt | 24 +++++ .../vendor/golang.org/x/mod/modfile/rule.go | 102 ++++++++++++++---- src/cmd/vendor/modules.txt | 2 +- 5 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_retract_fix_version.txt diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 3c90dca491..8ca3b982ee 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 + golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 498b92207f..7de27879f6 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 h1:ETedWdSKv0zHgSxvhXszxH25fCWwA6olYCPu9ehlVKs= -golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc h1:xQukuh0OD2SNSUK1CCBFATgHYx5ye75S/bAWEU/PT0E= +golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/src/cmd/go/testdata/script/mod_retract_fix_version.txt b/src/cmd/go/testdata/script/mod_retract_fix_version.txt new file mode 100644 index 0000000000..f8099ec93e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_fix_version.txt @@ -0,0 +1,24 @@ +# retract must not be used without a module directive. +! go list -m all +stderr 'go.mod:3: no module directive found, so retract cannot be used$' + +# Commands that update go.mod should fix non-canonical versions in +# retract directives. +# Verifies #44494. +go mod edit -module=rsc.io/quote/v2 +! go list -m all +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' +go mod tidy +go list -m all +cmp go.mod go.mod.want + +-- go.mod -- +go 1.16 + +retract latest +-- go.mod.want -- +go 1.16 + +retract v2.0.1 + +module rsc.io/quote/v2 diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index 8fcf96b713..f8c9384985 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -125,6 +125,12 @@ func (f *File) AddComment(text string) { type VersionFixer func(path, version string) (string, error) +// errDontFix is returned by a VersionFixer to indicate the version should be +// left alone, even if it's not canonical. +var dontFixRetract VersionFixer = func(_, vers string) (string, error) { + return vers, nil +} + // Parse parses the data, reported in errors as being from file, // into a File struct. It applies fix, if non-nil, to canonicalize all module versions found. func Parse(file string, data []byte, fix VersionFixer) (*File, error) { @@ -142,7 +148,7 @@ func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, false) } -func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) { +func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parsed *File, err error) { fs, err := parse(file, data) if err != nil { return nil, err @@ -150,8 +156,18 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File f := &File{ Syntax: fs, } - var errs ErrorList + + // fix versions in retract directives after the file is parsed. + // We need the module path to fix versions, and it might be at the end. + defer func() { + oldLen := len(errs) + f.fixRetract(fix, &errs) + if len(errs) > oldLen { + parsed, err = nil, errs + } + }() + for _, x := range fs.Stmt { switch x := x.(type) { case *Line: @@ -370,7 +386,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a case "retract": rationale := parseRetractRationale(block, line) - vi, err := parseVersionInterval(verb, &args, fix) + vi, err := parseVersionInterval(verb, "", &args, dontFixRetract) if err != nil { if strict { wrapError(err) @@ -397,6 +413,47 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a } } +// fixRetract applies fix to each retract directive in f, appending any errors +// to errs. +// +// Most versions are fixed as we parse the file, but for retract directives, +// the relevant module path is the one specified with the module directive, +// and that might appear at the end of the file (or not at all). +func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { + if fix == nil { + return + } + path := "" + if f.Module != nil { + path = f.Module.Mod.Path + } + var r *Retract + wrapError := func(err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: r.Syntax.Start, + Err: err, + }) + } + + for _, r = range f.Retract { + if path == "" { + wrapError(errors.New("no module directive found, so retract cannot be used")) + return // only print the first one of these + } + + args := r.Syntax.Token + if args[0] == "retract" { + args = args[1:] + } + vi, err := parseVersionInterval("retract", path, &args, fix) + if err != nil { + wrapError(err) + } + r.VersionInterval = vi + } +} + // isIndirect reports whether line has a "// indirect" comment, // meaning it is in go.mod only for its effect on indirect dependencies, // so that it can be dropped entirely once the effective version of the @@ -491,13 +548,13 @@ func AutoQuote(s string) string { return s } -func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (VersionInterval, error) { +func parseVersionInterval(verb string, path string, args *[]string, fix VersionFixer) (VersionInterval, error) { toks := *args if len(toks) == 0 || toks[0] == "(" { return VersionInterval{}, fmt.Errorf("expected '[' or version") } if toks[0] != "[" { - v, err := parseVersion(verb, "", &toks[0], fix) + v, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -509,7 +566,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio if len(toks) == 0 { return VersionInterval{}, fmt.Errorf("expected version after '['") } - low, err := parseVersion(verb, "", &toks[0], fix) + low, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -523,7 +580,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio if len(toks) == 0 { return VersionInterval{}, fmt.Errorf("expected version after ','") } - high, err := parseVersion(verb, "", &toks[0], fix) + high, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -631,8 +688,7 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } } if fix != nil { - var err error - t, err = fix(path, t) + fixed, err := fix(path, t) if err != nil { if err, ok := err.(*module.ModuleError); ok { return "", &Error{ @@ -643,19 +699,23 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } return "", err } + t = fixed + } else { + cv := module.CanonicalVersion(t) + if cv == "" { + return "", &Error{ + Verb: verb, + ModPath: path, + Err: &module.InvalidVersionError{ + Version: t, + Err: errors.New("must be of the form v1.2.3"), + }, + } + } + t = cv } - if v := module.CanonicalVersion(t); v != "" { - *s = v - return *s, nil - } - return "", &Error{ - Verb: verb, - ModPath: path, - Err: &module.InvalidVersionError{ - Version: t, - Err: errors.New("must be of the form v1.2.3"), - }, - } + *s = t + return *s, nil } func modulePathMajor(path string) (string, error) { diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 254cff70dd..03853007e0 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.2-0.20210223202949-66f6d92cabd5 +# golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile -- GitLab From 1f7a01459b1172fdc571a81ffd369dbf32b6c8b2 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Mon, 23 Nov 2020 15:42:48 +0800 Subject: [PATCH 0105/1298] runtime: batch moving gFree list between local p and global schedt Change-Id: I0ca1fcee6d3f08bdfcfa51f0dc774118d7355636 Reviewed-on: https://go-review.googlesource.com/c/go/+/271914 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/runtime/proc.go | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index dbb430fd25..19049d21f3 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4170,17 +4170,25 @@ func gfput(_p_ *p, gp *g) { _p_.gFree.push(gp) _p_.gFree.n++ if _p_.gFree.n >= 64 { - lock(&sched.gFree.lock) + var ( + inc int32 + stackQ gQueue + noStackQ gQueue + ) for _p_.gFree.n >= 32 { - _p_.gFree.n-- gp = _p_.gFree.pop() + _p_.gFree.n-- if gp.stack.lo == 0 { - sched.gFree.noStack.push(gp) + noStackQ.push(gp) } else { - sched.gFree.stack.push(gp) + stackQ.push(gp) } - sched.gFree.n++ + inc++ } + lock(&sched.gFree.lock) + sched.gFree.noStack.pushAll(noStackQ) + sched.gFree.stack.pushAll(stackQ) + sched.gFree.n += inc unlock(&sched.gFree.lock) } } @@ -4232,17 +4240,25 @@ retry: // Purge all cached G's from gfree list to the global list. func gfpurge(_p_ *p) { - lock(&sched.gFree.lock) + var ( + inc int32 + stackQ gQueue + noStackQ gQueue + ) for !_p_.gFree.empty() { gp := _p_.gFree.pop() _p_.gFree.n-- if gp.stack.lo == 0 { - sched.gFree.noStack.push(gp) + noStackQ.push(gp) } else { - sched.gFree.stack.push(gp) + stackQ.push(gp) } - sched.gFree.n++ + inc++ } + lock(&sched.gFree.lock) + sched.gFree.noStack.pushAll(noStackQ) + sched.gFree.stack.pushAll(stackQ) + sched.gFree.n += inc unlock(&sched.gFree.lock) } -- GitLab From ee2a45e5fbee473b81c8ab81da8d83699d64e01f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 24 Feb 2021 09:43:59 +0100 Subject: [PATCH 0106/1298] runtime: use pipe2 for nonblockingPipe on dragonfly The pipe2 syscall is available since DragonflyBSD 4.2, see https://www.dragonflybsd.org/release42/ Change-Id: Ifc67c4935cc59bae29be459167e2fa765843ac03 Reviewed-on: https://go-review.googlesource.com/c/go/+/295471 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/runtime/defs_dragonfly.go | 4 ++++ src/runtime/defs_dragonfly_amd64.go | 4 ++++ src/runtime/export_pipe2_test.go | 4 ++-- src/runtime/export_pipe_test.go | 4 ++-- src/runtime/nbpipe_pipe.go | 4 ++-- src/runtime/nbpipe_pipe2.go | 4 ++-- src/runtime/os_dragonfly.go | 5 +++-- src/runtime/sys_dragonfly_amd64.s | 18 ++++++++++++++++++ 8 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/runtime/defs_dragonfly.go b/src/runtime/defs_dragonfly.go index 225258901f..aca2bf9001 100644 --- a/src/runtime/defs_dragonfly.go +++ b/src/runtime/defs_dragonfly.go @@ -32,6 +32,10 @@ const ( EFAULT = C.EFAULT EBUSY = C.EBUSY EAGAIN = C.EAGAIN + ENOSYS = C.ENOSYS + + O_NONBLOCK = C.O_NONBLOCK + O_CLOEXEC = C.O_CLOEXEC PROT_NONE = C.PROT_NONE PROT_READ = C.PROT_READ diff --git a/src/runtime/defs_dragonfly_amd64.go b/src/runtime/defs_dragonfly_amd64.go index 30f1b33845..f3c6ecd04b 100644 --- a/src/runtime/defs_dragonfly_amd64.go +++ b/src/runtime/defs_dragonfly_amd64.go @@ -10,6 +10,10 @@ const ( _EFAULT = 0xe _EBUSY = 0x10 _EAGAIN = 0x23 + _ENOSYS = 0x4e + + _O_NONBLOCK = 0x4 + _O_CLOEXEC = 0x20000 _PROT_NONE = 0x0 _PROT_READ = 0x1 diff --git a/src/runtime/export_pipe2_test.go b/src/runtime/export_pipe2_test.go index 31c8e43b3f..26d8b7d185 100644 --- a/src/runtime/export_pipe2_test.go +++ b/src/runtime/export_pipe2_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || linux || netbsd || openbsd || solaris -// +build freebsd linux netbsd openbsd solaris +//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris +// +build dragonfly freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/export_pipe_test.go b/src/runtime/export_pipe_test.go index 82032e6bfb..a0c6c0440d 100644 --- a/src/runtime/export_pipe_test.go +++ b/src/runtime/export_pipe_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly -// +build aix darwin dragonfly +//go:build aix || darwin +// +build aix darwin package runtime diff --git a/src/runtime/nbpipe_pipe.go b/src/runtime/nbpipe_pipe.go index d92cf97217..b17257e9ec 100644 --- a/src/runtime/nbpipe_pipe.go +++ b/src/runtime/nbpipe_pipe.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly -// +build aix darwin dragonfly +//go:build aix || darwin +// +build aix darwin package runtime diff --git a/src/runtime/nbpipe_pipe2.go b/src/runtime/nbpipe_pipe2.go index f138d1f956..f22b2b591f 100644 --- a/src/runtime/nbpipe_pipe2.go +++ b/src/runtime/nbpipe_pipe2.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || linux || netbsd || openbsd || solaris -// +build freebsd linux netbsd openbsd solaris +//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris +// +build dragonfly freebsd linux netbsd openbsd solaris package runtime diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 2e930b6e94..5c688a3109 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -60,10 +60,11 @@ func kqueue() int32 //go:noescape func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 -func closeonexec(fd int32) -func setNonblock(fd int32) func pipe() (r, w int32, errno int32) +func pipe2(flags int32) (r, w int32, errno int32) +func closeonexec(fd int32) +func setNonblock(fd int32) // From DragonFly's const ( diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s index 580633af55..9cb268d740 100644 --- a/src/runtime/sys_dragonfly_amd64.s +++ b/src/runtime/sys_dragonfly_amd64.s @@ -123,6 +123,24 @@ pipeok: MOVL $0, errno+8(FP) RET +// func pipe2(flags int32) (r, w int32, errno int32) +TEXT runtime·pipe2(SB),NOSPLIT,$0-20 + MOVL $0, DI + // dragonfly expects flags as the 2nd argument + MOVL flags+0(FP), SI + MOVL $538, AX + SYSCALL + JCC pipe2ok + MOVL $-1,r+8(FP) + MOVL $-1,w+12(FP) + MOVL AX, errno+16(FP) + RET +pipe2ok: + MOVL AX, r+8(FP) + MOVL DX, w+12(FP) + MOVL $0, errno+16(FP) + RET + TEXT runtime·write1(SB),NOSPLIT,$-8 MOVQ fd+0(FP), DI // arg 1 fd MOVQ p+8(FP), SI // arg 2 buf -- GitLab From 1a3e968b1fcb2082b1d99be563a7c9f8c61c66ba Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 21 Feb 2021 22:09:03 +0700 Subject: [PATCH 0107/1298] cmd/compile: fix mishandling of unsafe-uintptr arguments with call method in go/defer In CL 253457, we did the same fix for direct function calls. But for method calls, the receiver argument also need to be passed through the wrapper function, which we are not doing so the compiler crashes with the code in #44415. As we already rewrite t.M(...) into T.M(t, ...) during walkCall1, to fix this, we can do the same trick in wrapCall, so the receiver argument will be treated as others. Fixes #44415 Change-Id: I396182983c85d9c5e4494657da79d25636e8a079 Reviewed-on: https://go-review.googlesource.com/c/go/+/294849 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/walk/expr.go | 32 +++++++++++++++------------ src/cmd/compile/internal/walk/stmt.go | 3 +++ test/fixedbugs/issue24491a.go | 30 +++++++++++++++++++++++++ test/fixedbugs/issue44415.go | 21 ++++++++++++++++++ 4 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 test/fixedbugs/issue44415.go diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index 7b65db5100..ce95fbc2b4 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -503,21 +503,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) { } n.SetWalked(true) - // If this is a method call t.M(...), - // rewrite into a function call T.M(t, ...). // TODO(mdempsky): Do this right after type checking. - if n.Op() == ir.OCALLMETH { - withRecv := make([]ir.Node, len(n.Args)+1) - dot := n.X.(*ir.SelectorExpr) - withRecv[0] = dot.X - copy(withRecv[1:], n.Args) - n.Args = withRecv - - dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym) - - n.SetOp(ir.OCALLFUNC) - n.X = typecheck.Expr(dot) - } + rewriteMethodCall(n) args := n.Args params := n.X.Type().Params() @@ -547,6 +534,23 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) { n.Args = args } +// rewriteMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...). +func rewriteMethodCall(n *ir.CallExpr) { + if n.Op() != ir.OCALLMETH { + return + } + withRecv := make([]ir.Node, len(n.Args)+1) + dot := n.X.(*ir.SelectorExpr) + withRecv[0] = dot.X + copy(withRecv[1:], n.Args) + n.Args = withRecv + + dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym) + + n.SetOp(ir.OCALLFUNC) + n.X = typecheck.Expr(dot) +} + // walkDivMod walks an ODIV or OMOD node. func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { n.X = walkExpr(n.X, init) diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go index 46a621c2ba..86f8819ec3 100644 --- a/src/cmd/compile/internal/walk/stmt.go +++ b/src/cmd/compile/internal/walk/stmt.go @@ -241,6 +241,9 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { init.Append(ir.TakeInit(n)...) } + // TODO(mdempsky): Do this right after type checking. + rewriteMethodCall(n) + isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e). diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go index 8accf8c0a3..da734531a5 100644 --- a/test/fixedbugs/issue24491a.go +++ b/test/fixedbugs/issue24491a.go @@ -48,6 +48,30 @@ func f() int { return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) } +type S struct{} + +//go:noinline +//go:uintptrescapes +func (S) test(s string, p, q uintptr, rest ...uintptr) int { + runtime.GC() + runtime.GC() + + if *(*string)(unsafe.Pointer(p)) != "ok" { + panic(s + ": p failed") + } + if *(*string)(unsafe.Pointer(q)) != "ok" { + panic(s + ": q failed") + } + for _, r := range rest { + if *(*string)(unsafe.Pointer(r)) != "ok" { + panic(s + ": r[i] failed") + } + } + + done <- true + return 0 +} + func main() { test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) <-done @@ -60,6 +84,12 @@ func main() { }() <-done + func() { + s := &S{} + defer s.test("method call", uintptr(setup()), uintptr(setup())) + }() + <-done + f() <-done } diff --git a/test/fixedbugs/issue44415.go b/test/fixedbugs/issue44415.go new file mode 100644 index 0000000000..26820a9f09 --- /dev/null +++ b/test/fixedbugs/issue44415.go @@ -0,0 +1,21 @@ +// compile + +// Copyright 2021 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 windows + +package p + +import ( + "syscall" + "unsafe" +) + +var dllKernel = syscall.NewLazyDLL("Kernel32.dll") + +func Call() { + procLocalFree := dllKernel.NewProc("LocalFree") + defer procLocalFree.Call(uintptr(unsafe.Pointer(nil))) +} -- GitLab From 4ebb6f5110af3e60455d8751b996b958afb25a36 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 7 Jan 2021 19:08:37 -0800 Subject: [PATCH 0108/1298] cmd/compile: automate resultInArg0 register checks No functional changes; passes toolstash-check. No measureable performance changes. Change-Id: I2629f73d4a3cc56d80f512f33cf57cf41d8f15d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/296010 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/amd64/ssa.go | 76 ++++-------------------- src/cmd/compile/internal/arm/ssa.go | 3 - src/cmd/compile/internal/arm64/ssa.go | 9 +-- src/cmd/compile/internal/mips/ssa.go | 9 --- src/cmd/compile/internal/mips64/ssa.go | 3 - src/cmd/compile/internal/riscv64/ssa.go | 3 - src/cmd/compile/internal/s390x/ssa.go | 48 +++------------ src/cmd/compile/internal/ssa/gen/main.go | 1 + src/cmd/compile/internal/ssa/opGen.go | 1 + src/cmd/compile/internal/ssa/value.go | 17 ++++++ src/cmd/compile/internal/ssagen/ssa.go | 4 ++ src/cmd/compile/internal/x86/ssa.go | 44 +++----------- 12 files changed, 52 insertions(+), 166 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 6944ba7ce7..230219a383 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -202,9 +202,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[2].Reg()} p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()}) - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL: r := v.Reg() r1 := v.Args[0].Reg() @@ -254,11 +251,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64BTSL, ssa.OpAMD64BTSQ, ssa.OpAMD64BTCL, ssa.OpAMD64BTCQ, ssa.OpAMD64BTRL, ssa.OpAMD64BTRQ: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } - opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) + opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg()) case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU: // Arg[0] (the dividend) is in AX. @@ -401,20 +394,16 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // compute (x+y)/2 unsigned. // Do a 64-bit add, the overflow goes into the carry. // Shift right once and pull the carry back into the 63rd bit. - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(x86.AADDQ) p.From.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() p.From.Reg = v.Args[1].Reg() p = s.Prog(x86.ARCRQ) p.From.Type = obj.TYPE_CONST p.From.Offset = 1 p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpAMD64ADDQcarry, ssa.OpAMD64ADCQ: r := v.Reg0() @@ -530,21 +519,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64CMOVQCS, ssa.OpAMD64CMOVLCS, ssa.OpAMD64CMOVWCS, ssa.OpAMD64CMOVQGTF, ssa.OpAMD64CMOVLGTF, ssa.OpAMD64CMOVWGTF, ssa.OpAMD64CMOVQGEF, ssa.OpAMD64CMOVLGEF, ssa.OpAMD64CMOVWGEF: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpAMD64CMOVQNEF, ssa.OpAMD64CMOVLNEF, ssa.OpAMD64CMOVWNEF: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // Flag condition: ^ZERO || PARITY // Generate: // CMOV*NE SRC,DST @@ -553,7 +534,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() var q *obj.Prog if v.Op == ssa.OpAMD64CMOVQNEF { q = s.Prog(x86.ACMOVQPS) @@ -565,14 +546,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { q.From.Type = obj.TYPE_REG q.From.Reg = v.Args[1].Reg() q.To.Type = obj.TYPE_REG - q.To.Reg = r + q.To.Reg = v.Reg() case ssa.OpAMD64CMOVQEQF, ssa.OpAMD64CMOVLEQF, ssa.OpAMD64CMOVWEQF: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } - // Flag condition: ZERO && !PARITY // Generate: // MOV SRC,AX @@ -589,7 +565,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG - p.From.Reg = r + p.From.Reg = v.Reg() p.To.Type = obj.TYPE_REG p.To.Reg = x86.REG_AX var q *obj.Prog @@ -603,7 +579,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { q.From.Type = obj.TYPE_REG q.From.Reg = x86.REG_AX q.To.Type = obj.TYPE_REG - q.To.Reg = r + q.To.Reg = v.Reg() case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst: r := v.Reg() @@ -622,15 +598,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask: r := v.Reg() p := s.Prog(v.Op.Asm()) @@ -913,9 +885,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.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.OpAMD64ADDLloadidx1, ssa.OpAMD64ADDLloadidx4, ssa.OpAMD64ADDLloadidx8, ssa.OpAMD64ADDQloadidx1, ssa.OpAMD64ADDQloadidx8, ssa.OpAMD64SUBLloadidx1, ssa.OpAMD64SUBLloadidx4, ssa.OpAMD64SUBLloadidx8, ssa.OpAMD64SUBQloadidx1, ssa.OpAMD64SUBQloadidx8, ssa.OpAMD64ANDLloadidx1, ssa.OpAMD64ANDLloadidx4, ssa.OpAMD64ANDLloadidx8, ssa.OpAMD64ANDQloadidx1, ssa.OpAMD64ANDQloadidx8, @@ -939,9 +908,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.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.OpAMD64DUFFZERO: if s.ABI != obj.ABIInternal { v.Fatalf("MOVOconst can be only used in ABIInternal functions") @@ -1078,22 +1044,14 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL, ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpAMD64NEGLflags: - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg0() case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD: p := s.Prog(v.Op.Asm()) @@ -1214,25 +1172,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg0() case ssa.OpAMD64XCHGB, ssa.OpAMD64XCHGL, ssa.OpAMD64XCHGQ: - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output[0] not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG - p.From.Reg = r + p.From.Reg = v.Reg0() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[1].Reg() ssagen.AddAux(&p.To, v) case ssa.OpAMD64XADDLlock, ssa.OpAMD64XADDQlock: - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output[0] not in same register %s", v.LongString()) - } s.Prog(x86.ALOCK) p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG - p.From.Reg = r + p.From.Reg = v.Reg0() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[1].Reg() ssagen.AddAux(&p.To, v) diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go index 729d2dab2d..6cbdf4377d 100644 --- a/src/cmd/compile/internal/arm/ssa.go +++ b/src/cmd/compile/internal/arm/ssa.go @@ -173,9 +173,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = y case ssa.OpARMMOVWnop: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // nothing to do case ssa.OpLoadReg: if v.Type.IsFlags() { diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index ca5eac72bf..2576aeb600 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -142,9 +142,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = y case ssa.OpARM64MOVDnop: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // nothing to do case ssa.OpLoadReg: if v.Type.IsFlags() { @@ -522,17 +519,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.To, v) case ssa.OpARM64BFI, ssa.OpARM64BFXIL: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt >> 8 p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt & 0xff}) p.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpARM64SBFIZ, ssa.OpARM64SBFX, ssa.OpARM64UBFIZ, diff --git a/src/cmd/compile/internal/mips/ssa.go b/src/cmd/compile/internal/mips/ssa.go index f1cdbd3241..115e3cb8e2 100644 --- a/src/cmd/compile/internal/mips/ssa.go +++ b/src/cmd/compile/internal/mips/ssa.go @@ -112,9 +112,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = y } case ssa.OpMIPSMOVWnop: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // nothing to do case ssa.OpLoadReg: if v.Type.IsFlags() { @@ -244,9 +241,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() case ssa.OpMIPSCMOVZ: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[2].Reg() @@ -254,9 +248,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() case ssa.OpMIPSCMOVZzero: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[1].Reg() diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go index 14cf7af143..d9c47751e1 100644 --- a/src/cmd/compile/internal/mips64/ssa.go +++ b/src/cmd/compile/internal/mips64/ssa.go @@ -115,9 +115,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = y } case ssa.OpMIPS64MOVVnop: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // nothing to do case ssa.OpLoadReg: if v.Type.IsFlags() { diff --git a/src/cmd/compile/internal/riscv64/ssa.go b/src/cmd/compile/internal/riscv64/ssa.go index 70c29a4b7b..0a3064323a 100644 --- a/src/cmd/compile/internal/riscv64/ssa.go +++ b/src/cmd/compile/internal/riscv64/ssa.go @@ -211,9 +211,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = rd case ssa.OpRISCV64MOVDnop: - if v.Reg() != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } // nothing to do case ssa.OpLoadReg: if v.Type.IsFlags() { diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index d4c7a286e2..0c65f7a238 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -175,10 +175,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.Reg = r1 } case ssa.OpS390XRXSBG: - r1 := v.Reg() - if r1 != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } r2 := v.Args[1].Reg() i := v.Aux.(s390x.RotateParams) p := s.Prog(v.Op.Asm()) @@ -188,7 +184,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { {Type: obj.TYPE_CONST, Offset: int64(i.Amount)}, {Type: obj.TYPE_REG, Reg: r2}, }) - p.To = obj.Addr{Type: obj.TYPE_REG, Reg: r1} + p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} case ssa.OpS390XRISBGZ: r1 := v.Reg() r2 := v.Args[0].Reg() @@ -233,12 +229,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.Reg = r2 } case ssa.OpS390XADDE, ssa.OpS390XSUBE: - r1 := v.Reg0() - if r1 != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } r2 := v.Args[1].Reg() - opregreg(s, v.Op.Asm(), r1, r2) + opregreg(s, v.Op.Asm(), v.Reg0(), r2) case ssa.OpS390XADDCconst: r1 := v.Reg0() r3 := v.Args[0].Reg() @@ -248,18 +240,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpS390XMULLD, ssa.OpS390XMULLW, ssa.OpS390XMULHD, ssa.OpS390XMULHDU, ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } - opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) + opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg()) case ssa.OpS390XFSUBS, ssa.OpS390XFSUB, ssa.OpS390XFADDS, ssa.OpS390XFADD: - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } - opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) + opregreg(s, v.Op.Asm(), v.Reg0(), v.Args[1].Reg()) case ssa.OpS390XMLGR: // MLGR Rx R3 -> R2:R3 r0 := v.Args[0].Reg() @@ -274,10 +258,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG case ssa.OpS390XFMADD, ssa.OpS390XFMADDS, ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } r1 := v.Args[1].Reg() r2 := v.Args[2].Reg() p := s.Prog(v.Op.Asm()) @@ -285,7 +265,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = r1 p.Reg = r2 p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpS390XFIDBR: switch v.AuxInt { case 0, 1, 3, 4, 5, 6, 7: @@ -361,15 +341,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpS390XANDconst, ssa.OpS390XANDWconst, ssa.OpS390XORconst, ssa.OpS390XORWconst, ssa.OpS390XXORconst, ssa.OpS390XXORWconst: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst, ssa.OpS390XSRDconst, ssa.OpS390XSRWconst, ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst, @@ -441,16 +417,12 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpS390XANDWload, ssa.OpS390XANDload, ssa.OpS390XORWload, ssa.OpS390XORload, ssa.OpS390XXORWload, ssa.OpS390XXORload: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[1].Reg() ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpS390XMOVDload, ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload, ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload, @@ -608,16 +580,12 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8: v.Fatalf("SumBytes generated %s", v.LongString()) case ssa.OpS390XLOCGR: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = int64(v.Aux.(s390x.CCMask)) p.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.OpS390XFSQRT: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go index f5385389c3..8e5997b25a 100644 --- a/src/cmd/compile/internal/ssa/gen/main.go +++ b/src/cmd/compile/internal/ssa/gen/main.go @@ -407,6 +407,7 @@ func genOp() { fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }") fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }") fmt.Fprintln(w, "func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint }") + fmt.Fprintln(w, "func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 }") // generate registers for _, a := range archs { diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 551aa725b6..10ea57b36b 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -36193,6 +36193,7 @@ func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect } func (o Op) IsCall() bool { return opcodeTable[o].call } func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects } func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint } +func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 } var registers386 = [...]Register{ {0, x86.REG_AX, 0, "AX"}, diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 6539631b9c..55e4b684c1 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -411,6 +411,23 @@ func (v *Value) isGenericIntConst() bool { return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) } +// ResultReg returns the result register assigned to v, in cmd/internal/obj/$ARCH numbering. +// It is similar to Reg and Reg0, except that it is usable interchangeably for all Value Ops. +// If you know v.Op, using Reg or Reg0 (as appropriate) will be more efficient. +func (v *Value) ResultReg() int16 { + reg := v.Block.Func.RegAlloc[v.ID] + if reg == nil { + v.Fatalf("nil reg for value: %s\n%s\n", v.LongString(), v.Block.Func) + } + if pair, ok := reg.(LocPair); ok { + reg = pair[0] + } + if reg == nil { + v.Fatalf("nil reg0 for value: %s\n%s\n", v.LongString(), v.Block.Func) + } + return reg.(*Register).objNum +} + // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering. func (v *Value) Reg() int16 { reg := v.Block.Func.RegAlloc[v.ID] diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index d69eb17ca9..20acdbdc66 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6509,6 +6509,10 @@ func genssa(f *ssa.Func, pp *objw.Progs) { x := s.pp.Next s.DebugFriendlySetPosFrom(v) + if v.Op.ResultInArg0() && v.ResultReg() != v.Args[0].Reg() { + v.Fatalf("input[0] and output not in same register %s", v.LongString()) + } + switch v.Op { case ssa.OpInitMem: // memory arg needs no code diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index 00dfa07bf7..c5fe3ae2e2 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -161,31 +161,19 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.Op386PXOR, ssa.Op386ADCL, ssa.Op386SBBL: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } - opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) + opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg()) case ssa.Op386ADDLcarry, ssa.Op386SUBLcarry: // output 0 is carry/borrow, output 1 is the low 32 bits. - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output[0] not in same register %s", v.LongString()) - } - opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) + opregreg(s, v.Op.Asm(), v.Reg0(), v.Args[1].Reg()) case ssa.Op386ADDLconstcarry, ssa.Op386SUBLconstcarry: // output 0 is carry/borrow, output 1 is the low 32 bits. - r := v.Reg0() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output[0] not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg0() case ssa.Op386DIVL, ssa.Op386DIVW, ssa.Op386DIVLU, ssa.Op386DIVWU, @@ -306,20 +294,16 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // compute (x+y)/2 unsigned. // Do a 32-bit add, the overflow goes into the carry. // Shift right once and pull the carry back into the 31st bit. - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(x86.AADDL) p.From.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() p.From.Reg = v.Args[1].Reg() p = s.Prog(x86.ARCRL) p.From.Type = obj.TYPE_CONST p.From.Offset = 1 p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.Op386ADDLconst: r := v.Reg() @@ -370,15 +354,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.Op386SHRLconst, ssa.Op386SHRWconst, ssa.Op386SHRBconst, ssa.Op386SARLconst, ssa.Op386SARWconst, ssa.Op386SARBconst, ssa.Op386ROLLconst, ssa.Op386ROLWconst, ssa.Op386ROLBconst: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.Op386SBBLcarrymask: r := v.Reg() p := s.Prog(v.Op.Asm()) @@ -536,9 +516,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.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, @@ -549,9 +526,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.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.Op386MOVSSstore, ssa.Op386MOVSDstore, ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore, ssa.Op386ADDLmodify, ssa.Op386SUBLmodify, ssa.Op386ANDLmodify, ssa.Op386ORLmodify, ssa.Op386XORLmodify: p := s.Prog(v.Op.Asm()) @@ -781,13 +755,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.Op386NEGL, ssa.Op386BSWAPL, ssa.Op386NOTL: - r := v.Reg() - if r != v.Args[0].Reg() { - v.Fatalf("input[0] and output not in same register %s", v.LongString()) - } p := s.Prog(v.Op.Asm()) p.To.Type = obj.TYPE_REG - p.To.Reg = r + p.To.Reg = v.Reg() case ssa.Op386BSFL, ssa.Op386BSFW, ssa.Op386BSRL, ssa.Op386BSRW, ssa.Op386SQRTSD: -- GitLab From 194b636f8f1ff7d6b709b5b9010d1d14b3919e66 Mon Sep 17 00:00:00 2001 From: Ivan Trubach Date: Thu, 25 Feb 2021 19:15:04 +0000 Subject: [PATCH 0109/1298] database/sql: close driver.Connector if it implements io.Closer This change allows driver implementations to manage resources in driver.Connector, e.g. to share the same underlying database handle between multiple connections. That is, it allows embedded databases with in-memory backends like SQLite and Genji to safely release the resources once the sql.DB is closed. This makes it possible to address oddities with in-memory stores in SQLite and Genji drivers without introducing too much complexity in the driver implementations. See also: - https://github.com/mattn/go-sqlite3/issues/204 - https://github.com/mattn/go-sqlite3/issues/511 - https://github.com/genjidb/genji/issues/210 Fixes #41790 Change-Id: Idbd19763134438ed38288b9d44f16608e4e97fd7 GitHub-Last-Rev: 962c785dfb3bb6ad98b2216bcedd84ba383fe872 GitHub-Pull-Request: golang/go#41710 Reviewed-on: https://go-review.googlesource.com/c/go/+/258360 Reviewed-by: Emmanuel Odeke Reviewed-by: Daniel Theophanes Trust: Emmanuel Odeke Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot --- src/database/sql/driver/driver.go | 3 +++ src/database/sql/fakedb_test.go | 9 +++++++++ src/database/sql/sql.go | 6 ++++++ src/database/sql/sql_test.go | 11 ++++++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index 5bbcf20db2..f09396175a 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -115,6 +115,9 @@ type DriverContext interface { // DriverContext's OpenConnector method, to allow drivers // access to context and to avoid repeated parsing of driver // configuration. +// +// If a Connector implements io.Closer, the sql package's DB.Close +// method will call Close and return error (if any). type Connector interface { // Connect returns a connection to the database. // Connect may return a cached connection (one previously diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go index 7605a2a6d2..1bfd1118aa 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -56,6 +56,7 @@ type fakeConnector struct { name string waiter func(context.Context) + closed bool } func (c *fakeConnector) Connect(context.Context) (driver.Conn, error) { @@ -68,6 +69,14 @@ func (c *fakeConnector) Driver() driver.Driver { return fdriver } +func (c *fakeConnector) Close() error { + if c.closed { + return errors.New("fakedb: connector is closed") + } + c.closed = true + return nil +} + type fakeDriverCtx struct { fakeDriver } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 726aadb899..37bcb0d091 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -850,6 +850,12 @@ func (db *DB) Close() error { } } db.stop() + if c, ok := db.connector.(io.Closer); ok { + err1 := c.Close() + if err1 != nil { + err = err1 + } + } return err } diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 99bfd62491..c06e565ea9 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -4059,9 +4059,18 @@ func TestOpenConnector(t *testing.T) { } defer db.Close() - if _, is := db.connector.(*fakeConnector); !is { + c, ok := db.connector.(*fakeConnector) + if !ok { t.Fatal("not using *fakeConnector") } + + if err := db.Close(); err != nil { + t.Fatal(err) + } + + if !c.closed { + t.Fatal("connector is not closed") + } } type ctxOnlyDriver struct { -- GitLab From 526ee96f4992ff3a1e1c219fe8dc9870098bacba Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 6 Nov 2020 17:37:03 -0800 Subject: [PATCH 0110/1298] os: avoid allocation in File.WriteString Instead of alloc+copy to convert the string to a byte slice, do an unsafe conversion. Rely on the kernel not to scribble on the buffer during the write. Fixes #42406 Change-Id: I66f4838b43a11bcc3d67bbfa1706726318d55343 Reviewed-on: https://go-review.googlesource.com/c/go/+/268020 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Emmanuel Odeke --- src/os/file.go | 9 ++++++++- src/os/os_test.go | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/os/file.go b/src/os/file.go index 52dd94339b..ebeb0d0ac9 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -44,11 +44,13 @@ import ( "errors" "internal/poll" "internal/testlog" + "internal/unsafeheader" "io" "io/fs" "runtime" "syscall" "time" + "unsafe" ) // Name returns the name of the file as presented to Open. @@ -246,7 +248,12 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) { // WriteString is like Write, but writes the contents of string s rather than // a slice of bytes. func (f *File) WriteString(s string) (n int, err error) { - return f.Write([]byte(s)) + var b []byte + hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b)) + hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data + hdr.Cap = len(s) + hdr.Len = len(s) + return f.Write(b) } // Mkdir creates a new directory with the specified name and permission diff --git a/src/os/os_test.go b/src/os/os_test.go index a32e5fc11e..f27c796c05 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -2773,3 +2773,21 @@ func TestReadFileProc(t *testing.T) { t.Fatalf("read %s: not newline-terminated: %q", name, data) } } + +func TestWriteStringAlloc(t *testing.T) { + if runtime.GOOS == "js" { + t.Skip("js allocates a lot during File.WriteString") + } + d := t.TempDir() + f, err := Create(filepath.Join(d, "whiteboard.txt")) + if err != nil { + t.Fatal(err) + } + defer f.Close() + allocs := testing.AllocsPerRun(100, func() { + f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n") + }) + if allocs != 0 { + t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs) + } +} -- GitLab From 6c3bcda866582b51842d71576a11c0fe1b647a22 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 17 Feb 2021 17:49:40 -0800 Subject: [PATCH 0111/1298] cmd/compile: declare inlined result params early for empty returns The code for delayed declaration of inlined result parameters only handles non-empty return statements. This is generally okay, because we already early declare if there are any (non-blank) named result parameters. But if a user writes a function with only blank result parameters and with exactly one return statement, which is empty, then they could end up hitting the dreaded "Value live at entry" ICE. This CL fixes the issue by ensuring we always early declare inlined result parameters if there are any empty return statements. Fixes #44355. Change-Id: I315f3853be436452883b1ce31da1bdffdf24d506 Reviewed-on: https://go-review.googlesource.com/c/go/+/293293 TryBot-Result: Go Bot Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le Reviewed-by: David Chase --- src/cmd/compile/internal/inline/inl.go | 20 ++++++++++++++------ test/fixedbugs/issue44355.dir/a.go | 7 +++++++ test/fixedbugs/issue44355.dir/b.go | 9 +++++++++ test/fixedbugs/issue44355.go | 7 +++++++ 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 test/fixedbugs/issue44355.dir/a.go create mode 100644 test/fixedbugs/issue44355.dir/b.go create mode 100644 test/fixedbugs/issue44355.go diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index fe6509e4c9..1703be74e9 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -852,17 +852,25 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b } } + // We can delay declaring+initializing result parameters if: + // (1) there's exactly one "return" statement in the inlined function; + // (2) it's not an empty return statement (#44355); and + // (3) the result parameters aren't named. + delayretvars := true + nreturns := 0 ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) { - if n != nil && n.Op() == ir.ORETURN { + if n, ok := n.(*ir.ReturnStmt); ok { nreturns++ + if len(n.Results) == 0 { + delayretvars = false // empty return statement (case 2) + } } }) - // We can delay declaring+initializing result parameters if: - // (1) there's only one "return" statement in the inlined - // function, and (2) the result parameters aren't named. - delayretvars := nreturns == 1 + if nreturns != 1 { + delayretvars = false // not exactly one return statement (case 1) + } // temporaries for return values. var retvars []ir.Node @@ -873,7 +881,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b m = inlvar(n) m = typecheck.Expr(m).(*ir.Name) inlvars[n] = m - delayretvars = false // found a named result parameter + delayretvars = false // found a named result parameter (case 3) } else { // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i) diff --git a/test/fixedbugs/issue44355.dir/a.go b/test/fixedbugs/issue44355.dir/a.go new file mode 100644 index 0000000000..0f63c6fd98 --- /dev/null +++ b/test/fixedbugs/issue44355.dir/a.go @@ -0,0 +1,7 @@ +// Copyright 2021 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 a + +func F() (_ *int) { return nil } diff --git a/test/fixedbugs/issue44355.dir/b.go b/test/fixedbugs/issue44355.dir/b.go new file mode 100644 index 0000000000..09d5bde887 --- /dev/null +++ b/test/fixedbugs/issue44355.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +import "./a" + +var _ = a.F() diff --git a/test/fixedbugs/issue44355.go b/test/fixedbugs/issue44355.go new file mode 100644 index 0000000000..d406838588 --- /dev/null +++ b/test/fixedbugs/issue44355.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 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 ignored -- GitLab From 7fcf9893f71c75f6b2fd53bea326d5061f705208 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 25 Feb 2021 09:58:05 -0800 Subject: [PATCH 0112/1298] cmd/internal/obj: fix typo in docs Change-Id: I5a3d26a4cc59b327d46ca24bcb01ef594758c230 Reviewed-on: https://go-review.googlesource.com/c/go/+/296531 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Ian Lance Taylor --- src/cmd/internal/obj/link.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index a48db3bdc8..a24461cef2 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -360,7 +360,7 @@ func (p *Prog) SetFrom3(a Addr) { p.RestArgs = []AddrPos{{a, Source}} } -// SetTo2 assings []Args{{a, 1}} to p.RestArgs when the second destination +// SetTo2 assigns []Args{{a, 1}} to p.RestArgs when the second destination // operand does not fit into prog.RegTo2. func (p *Prog) SetTo2(a Addr) { p.RestArgs = []AddrPos{{a, Destination}} -- GitLab From b83d073e9eb4cbd0cd5ca530f576668c49f6d0f1 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 14 Oct 2020 18:41:16 -0700 Subject: [PATCH 0113/1298] reflect: add Method.IsExported and StructField.IsExported methods The IsExported method is a more intuitive helper for checking whether the method or field is exported than checking whether PkgPath is empty. In the same CL, modify the standard library to make use of this helper. Fixes #41563 Change-Id: Iaacfb3b74449501f98e2707aa32095a32bd3c3c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/266197 Trust: Joe Tsai Run-TryBot: Joe Tsai TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/encoding/asn1/asn1.go | 2 +- src/encoding/asn1/marshal.go | 2 +- src/encoding/json/encode.go | 5 ++-- src/encoding/xml/typeinfo.go | 2 +- src/net/rpc/server.go | 2 +- src/reflect/all_test.go | 55 ++++++++++++++++++++++++++++++------ src/reflect/type.go | 19 ++++++++++--- src/text/template/exec.go | 2 +- 8 files changed, 68 insertions(+), 21 deletions(-) diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index f9b9cb4930..cffc06dc9c 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -914,7 +914,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam structType := fieldType for i := 0; i < structType.NumField(); i++ { - if structType.Field(i).PkgPath != "" { + if !structType.Field(i).IsExported() { err = StructuralError{"struct contains unexported fields"} return } diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go index 0d34d5aa1e..5b4d786d49 100644 --- a/src/encoding/asn1/marshal.go +++ b/src/encoding/asn1/marshal.go @@ -488,7 +488,7 @@ func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error t := v.Type() for i := 0; i < t.NumField(); i++ { - if t.Field(i).PkgPath != "" { + if !t.Field(i).IsExported() { return nil, StructuralError{"struct contains unexported fields"} } } diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 483b9d8f2d..751f03d33d 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -1239,19 +1239,18 @@ func typeFields(t reflect.Type) structFields { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) - isUnexported := sf.PkgPath != "" if sf.Anonymous { t := sf.Type if t.Kind() == reflect.Ptr { t = t.Elem() } - if isUnexported && t.Kind() != reflect.Struct { + if !sf.IsExported() && t.Kind() != reflect.Struct { // Ignore embedded fields of unexported non-struct types. continue } // Do not ignore embedded fields of unexported struct types // since they may have exported fields. - } else if isUnexported { + } else if !sf.IsExported() { // Ignore unexported non-embedded fields. continue } diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go index f30fe58590..162724ef1a 100644 --- a/src/encoding/xml/typeinfo.go +++ b/src/encoding/xml/typeinfo.go @@ -60,7 +60,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) { n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) - if (f.PkgPath != "" && !f.Anonymous) || f.Tag.Get("xml") == "-" { + if (!f.IsExported() && !f.Anonymous) || f.Tag.Get("xml") == "-" { continue // Private field } diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go index 9cb928240f..074c5b9b0d 100644 --- a/src/net/rpc/server.go +++ b/src/net/rpc/server.go @@ -283,7 +283,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType { mtype := method.Type mname := method.Name // Method must be exported. - if method.PkgPath != "" { + if !method.IsExported() { continue } // Method needs three ins: receiver, *args, *reply. diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 1225d6177d..35cc469d74 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -2900,6 +2900,7 @@ func TestFieldPkgPath(t *testing.T) { index []int pkgPath string embedded bool + exported bool } checkPkgPath := func(name string, s []pkgpathTest) { @@ -2911,27 +2912,63 @@ func TestFieldPkgPath(t *testing.T) { if got, want := f.Anonymous, test.embedded; got != want { t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want) } + if got, want := f.IsExported(), test.exported; got != want { + t.Errorf("%s: Field(%d).IsExported = %v, want %v", name, test.index, got, want) + } } } checkPkgPath("testStruct", []pkgpathTest{ - {[]int{0}, "", false}, // Exported - {[]int{1}, "reflect_test", false}, // unexported - {[]int{2}, "", true}, // OtherPkgFields - {[]int{2, 0}, "", false}, // OtherExported - {[]int{2, 1}, "reflect", false}, // otherUnexported - {[]int{3}, "reflect_test", true}, // int - {[]int{4}, "reflect_test", true}, // *x + {[]int{0}, "", false, true}, // Exported + {[]int{1}, "reflect_test", false, false}, // unexported + {[]int{2}, "", true, true}, // OtherPkgFields + {[]int{2, 0}, "", false, true}, // OtherExported + {[]int{2, 1}, "reflect", false, false}, // otherUnexported + {[]int{3}, "reflect_test", true, false}, // int + {[]int{4}, "reflect_test", true, false}, // *x }) type localOtherPkgFields OtherPkgFields typ = TypeOf(localOtherPkgFields{}) checkPkgPath("localOtherPkgFields", []pkgpathTest{ - {[]int{0}, "", false}, // OtherExported - {[]int{1}, "reflect", false}, // otherUnexported + {[]int{0}, "", false, true}, // OtherExported + {[]int{1}, "reflect", false, false}, // otherUnexported }) } +func TestMethodPkgPath(t *testing.T) { + type I interface { + x() + X() + } + typ := TypeOf((*interface { + I + y() + Y() + })(nil)).Elem() + + tests := []struct { + name string + pkgPath string + exported bool + }{ + {"X", "", true}, + {"Y", "", true}, + {"x", "reflect_test", false}, + {"y", "reflect_test", false}, + } + + for _, test := range tests { + m, _ := typ.MethodByName(test.name) + if got, want := m.PkgPath, test.pkgPath; got != want { + t.Errorf("MethodByName(%q).PkgPath = %q, want %q", test.name, got, want) + } + if got, want := m.IsExported(), test.exported; got != want { + t.Errorf("MethodByName(%q).IsExported = %v, want %v", test.name, got, want) + } + } +} + func TestVariadicType(t *testing.T) { // Test example from Type documentation. var f func(x int, y ...float64) diff --git a/src/reflect/type.go b/src/reflect/type.go index eb2030063a..dc235ea8f7 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -568,12 +568,13 @@ func newName(n, tag string, exported bool) name { // Method represents a single method. type Method struct { // Name is the method name. + Name string + // PkgPath is the package path that qualifies a lower case (unexported) // method name. It is empty for upper case (exported) method names. // The combination of PkgPath and Name uniquely identifies a method // in a method set. // See https://golang.org/ref/spec#Uniqueness_of_identifiers - Name string PkgPath string Type Type // method type @@ -581,6 +582,11 @@ type Method struct { Index int // index for Type.Method } +// IsExported reports whether the method is exported. +func (m Method) IsExported() bool { + return m.PkgPath == "" +} + const ( kindDirectIface = 1 << 5 kindGCProg = 1 << 6 // Type.gc points to GC program @@ -1090,6 +1096,7 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) { type StructField struct { // Name is the field name. Name string + // PkgPath is the package path that qualifies a lower case (unexported) // field name. It is empty for upper case (exported) field names. // See https://golang.org/ref/spec#Uniqueness_of_identifiers @@ -1102,6 +1109,11 @@ type StructField struct { Anonymous bool // is an embedded field } +// IsExported reports whether the field is exported. +func (f StructField) IsExported() bool { + return f.PkgPath == "" +} + // A StructTag is the tag string in a struct field. // // By convention, tag strings are a concatenation of @@ -2771,8 +2783,7 @@ func runtimeStructField(field StructField) (structField, string) { panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set") } - exported := field.PkgPath == "" - if exported { + if field.IsExported() { // Best-effort check for misuse. // Since this field will be treated as exported, not much harm done if Unicode lowercase slips through. c := field.Name[0] @@ -2788,7 +2799,7 @@ func runtimeStructField(field StructField) (structField, string) { resolveReflectType(field.Type.common()) // install in runtime f := structField{ - name: newName(field.Name, string(field.Tag), exported), + name: newName(field.Name, string(field.Tag), field.IsExported()), typ: field.Type.common(), offsetEmbed: offsetEmbed, } diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 19154fc640..4637b2035f 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -615,7 +615,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, tField, ok := receiver.Type().FieldByName(fieldName) if ok { field := receiver.FieldByIndex(tField.Index) - if tField.PkgPath != "" { // field is unexported + if !tField.IsExported() { s.errorf("%s is an unexported field of struct type %s", fieldName, typ) } // If it's a function, we must call it. -- GitLab From 9a7fe196e468c687ad7239b9447c584826331771 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 25 Feb 2021 21:32:29 +0000 Subject: [PATCH 0114/1298] Revert "cmd/compile: fix mishandling of unsafe-uintptr arguments with call method in go/defer" This reverts commit CL 294849. Reason for revert: this doesn't actually fix the issue, as revealed by the noopt builder's failures. Change-Id: Ib4ea9ceb4d75e46b3b91ec348b365fd8c83316ad Reviewed-on: https://go-review.googlesource.com/c/go/+/296629 Trust: Matthew Dempsky Reviewed-by: Bryan C. Mills --- src/cmd/compile/internal/walk/expr.go | 32 ++++++++++++--------------- src/cmd/compile/internal/walk/stmt.go | 3 --- test/fixedbugs/issue24491a.go | 30 ------------------------- test/fixedbugs/issue44415.go | 21 ------------------ 4 files changed, 14 insertions(+), 72 deletions(-) delete mode 100644 test/fixedbugs/issue44415.go diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index ce95fbc2b4..7b65db5100 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -503,8 +503,21 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) { } n.SetWalked(true) + // If this is a method call t.M(...), + // rewrite into a function call T.M(t, ...). // TODO(mdempsky): Do this right after type checking. - rewriteMethodCall(n) + if n.Op() == ir.OCALLMETH { + withRecv := make([]ir.Node, len(n.Args)+1) + dot := n.X.(*ir.SelectorExpr) + withRecv[0] = dot.X + copy(withRecv[1:], n.Args) + n.Args = withRecv + + dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym) + + n.SetOp(ir.OCALLFUNC) + n.X = typecheck.Expr(dot) + } args := n.Args params := n.X.Type().Params() @@ -534,23 +547,6 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) { n.Args = args } -// rewriteMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...). -func rewriteMethodCall(n *ir.CallExpr) { - if n.Op() != ir.OCALLMETH { - return - } - withRecv := make([]ir.Node, len(n.Args)+1) - dot := n.X.(*ir.SelectorExpr) - withRecv[0] = dot.X - copy(withRecv[1:], n.Args) - n.Args = withRecv - - dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym) - - n.SetOp(ir.OCALLFUNC) - n.X = typecheck.Expr(dot) -} - // walkDivMod walks an ODIV or OMOD node. func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { n.X = walkExpr(n.X, init) diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go index 86f8819ec3..46a621c2ba 100644 --- a/src/cmd/compile/internal/walk/stmt.go +++ b/src/cmd/compile/internal/walk/stmt.go @@ -241,9 +241,6 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { init.Append(ir.TakeInit(n)...) } - // TODO(mdempsky): Do this right after type checking. - rewriteMethodCall(n) - isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e). diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go index da734531a5..8accf8c0a3 100644 --- a/test/fixedbugs/issue24491a.go +++ b/test/fixedbugs/issue24491a.go @@ -48,30 +48,6 @@ func f() int { return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) } -type S struct{} - -//go:noinline -//go:uintptrescapes -func (S) test(s string, p, q uintptr, rest ...uintptr) int { - runtime.GC() - runtime.GC() - - if *(*string)(unsafe.Pointer(p)) != "ok" { - panic(s + ": p failed") - } - if *(*string)(unsafe.Pointer(q)) != "ok" { - panic(s + ": q failed") - } - for _, r := range rest { - if *(*string)(unsafe.Pointer(r)) != "ok" { - panic(s + ": r[i] failed") - } - } - - done <- true - return 0 -} - func main() { test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) <-done @@ -84,12 +60,6 @@ func main() { }() <-done - func() { - s := &S{} - defer s.test("method call", uintptr(setup()), uintptr(setup())) - }() - <-done - f() <-done } diff --git a/test/fixedbugs/issue44415.go b/test/fixedbugs/issue44415.go deleted file mode 100644 index 26820a9f09..0000000000 --- a/test/fixedbugs/issue44415.go +++ /dev/null @@ -1,21 +0,0 @@ -// compile - -// Copyright 2021 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 windows - -package p - -import ( - "syscall" - "unsafe" -) - -var dllKernel = syscall.NewLazyDLL("Kernel32.dll") - -func Call() { - procLocalFree := dllKernel.NewProc("LocalFree") - defer procLocalFree.Call(uintptr(unsafe.Pointer(nil))) -} -- GitLab From 5f15af111cb40c3ac154be88288abd381e6f61e2 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 15 Jan 2021 09:48:39 -0500 Subject: [PATCH 0115/1298] syscall: comment on fields omitted from the win32finddata1 struct Updates #42637 Change-Id: I4c7d38034b60c2c04efdeb530a97d96deddfd6fe Reviewed-on: https://go-review.googlesource.com/c/go/+/284152 Trust: Bryan C. Mills Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jason A. Donenfeld Reviewed-by: Alex Brainman --- src/syscall/types_windows.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index 0349f3b180..5fef5c9477 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -398,6 +398,14 @@ type win32finddata1 struct { Reserved1 uint32 FileName [MAX_PATH]uint16 AlternateFileName [14]uint16 + + // The Microsoft documentation for this struct¹ describes three additional + // fields: dwFileType, dwCreatorType, and wFinderFlags. However, those fields + // are empirically only present in the macOS port of the Win32 API,² and thus + // not needed for binaries built for Windows. + // + // ¹ https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw + // ² https://golang.org/issue/42637#issuecomment-760715755 } func copyFindData(dst *Win32finddata, src *win32finddata1) { -- GitLab From a61524d1033632f733f69bf6635e767d70d95cdd Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 7 Jan 2021 14:01:29 -0800 Subject: [PATCH 0116/1298] cmd/internal/obj: add Prog.SetFrom3{Reg,Const} These are the the most common uses, and they reduce line noise. I don't love adding new deprecated APIs, but since they're trivial wrappers, it'll be very easy to update them along with the rest. No functional changes; passes toolstash-check. Change-Id: I691a8175cfef9081180e463c63f326376af3f3a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/296009 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/asm/internal/asm/asm.go | 5 +---- src/cmd/compile/internal/amd64/ssa.go | 6 +++--- src/cmd/compile/internal/arm/ssa.go | 4 ++-- src/cmd/compile/internal/arm64/ssa.go | 10 +++++----- src/cmd/compile/internal/ppc64/ssa.go | 22 +++++++++++----------- src/cmd/compile/internal/s390x/ssa.go | 8 ++++---- src/cmd/compile/internal/x86/ssa.go | 2 +- src/cmd/internal/obj/link.go | 14 ++++++++++++++ 8 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index c4032759bb..06867cd507 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -811,10 +811,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { } else { mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1))) } - prog.SetFrom3(obj.Addr{ - Type: obj.TYPE_CONST, - Offset: int64(mask), - }) + prog.SetFrom3Const(int64(mask)) prog.To = a[4] break } diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 230219a383..32cb0a9368 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -201,7 +201,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[2].Reg()} p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()}) + p.SetFrom3Reg(v.Args[1].Reg()) case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL: r := v.Reg() r1 := v.Args[0].Reg() @@ -588,7 +588,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[0].Reg()}) + p.SetFrom3Reg(v.Args[0].Reg()) case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, @@ -1073,7 +1073,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } p.From.Offset = val p.From.Type = obj.TYPE_CONST - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[0].Reg()}) + p.SetFrom3Reg(v.Args[0].Reg()) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() case ssa.OpAMD64POPCNTQ, ssa.OpAMD64POPCNTL: diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go index 6cbdf4377d..c4d8cbf149 100644 --- a/src/cmd/compile/internal/arm/ssa.go +++ b/src/cmd/compile/internal/arm/ssa.go @@ -279,7 +279,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt >> 8 - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt & 0xff}) + p.SetFrom3Const(v.AuxInt & 0xff) p.Reg = v.Args[0].Reg() p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() @@ -299,7 +299,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(arm.ABFC) p.From.Type = obj.TYPE_CONST p.From.Offset = int64(width) - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(lsb)}) + p.SetFrom3Const(int64(lsb)) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() break diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 2576aeb600..5067d92dfe 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -229,7 +229,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.Reg = ra p.From.Type = obj.TYPE_REG p.From.Reg = rm - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: rn}) + p.SetFrom3Reg(rn) p.To.Type = obj.TYPE_REG p.To.Reg = rt case ssa.OpARM64ADDconst, @@ -292,7 +292,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[0].Reg()}) + p.SetFrom3Reg(v.Args[0].Reg()) p.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() @@ -522,7 +522,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt >> 8 - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt & 0xff}) + p.SetFrom3Const(v.AuxInt & 0xff) p.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() @@ -533,7 +533,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt >> 8 - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt & 0xff}) + p.SetFrom3Const(v.AuxInt & 0xff) p.Reg = v.Args[0].Reg() p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() @@ -952,7 +952,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Reg = condBits[ssa.Op(v.AuxInt)] p.Reg = v.Args[0].Reg() - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r1}) + p.SetFrom3Reg(r1) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() case ssa.OpARM64DUFFZERO: diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index c85e110ed3..f984079c4b 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -419,7 +419,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // If it is a Compare-and-Swap-Release operation, set the EH field with // the release hint. if v.AuxInt == 0 { - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 0}) + p.SetFrom3Const(0) } // CMP reg1,reg2 p1 := s.Prog(cmp) @@ -586,7 +586,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) // clrlslwi ra,rs,mb,sh will become rlwinm ra,rs,sh,mb-sh,31-sh as described in ISA p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)} - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}) + p.SetFrom3Const(ssa.GetPPC64Shiftsh(shifts)) p.Reg = r1 p.To.Type = obj.TYPE_REG p.To.Reg = r @@ -598,7 +598,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) // clrlsldi ra,rs,mb,sh will become rldic ra,rs,sh,mb-sh p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)} - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}) + p.SetFrom3Const(ssa.GetPPC64Shiftsh(shifts)) p.Reg = r1 p.To.Type = obj.TYPE_REG p.To.Reg = r @@ -610,7 +610,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { shifts := v.AuxInt p := s.Prog(v.Op.Asm()) p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)} - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}) + p.SetFrom3Const(ssa.GetPPC64Shiftmb(shifts)) p.Reg = r1 p.To.Type = obj.TYPE_REG p.To.Reg = r @@ -658,7 +658,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} p.Reg = v.Args[0].Reg() p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(rot)} - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)}) + p.SetFrom3Const(int64(mask)) // Auxint holds mask case ssa.OpPPC64RLWNM: @@ -667,7 +667,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} p.Reg = v.Args[0].Reg() p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()} - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)}) + p.SetFrom3Const(int64(mask)) case ssa.OpPPC64MADDLD: r := v.Reg() @@ -679,7 +679,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = r1 p.Reg = r2 - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r3}) + p.SetFrom3Reg(r3) p.To.Type = obj.TYPE_REG p.To.Reg = r @@ -693,7 +693,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = r1 p.Reg = r3 - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r2}) + p.SetFrom3Reg(r2) p.To.Type = obj.TYPE_REG p.To.Reg = r @@ -720,7 +720,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpPPC64SUBFCconst: p := s.Prog(v.Op.Asm()) - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt}) + p.SetFrom3Const(v.AuxInt) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() p.To.Type = obj.TYPE_REG @@ -910,7 +910,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // AuxInt values 4,5,6 implemented with reverse operand order from 0,1,2 if v.AuxInt > 3 { p.Reg = r.Reg - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[0].Reg()}) + p.SetFrom3Reg(v.Args[0].Reg()) } else { p.Reg = v.Args[0].Reg() p.SetFrom3(r) @@ -1784,7 +1784,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { pp.To.Reg = ppc64.REG_LR // Insert a hint this is not a subroutine return. - pp.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 1}) + pp.SetFrom3Const(1) if base.Ctxt.Flag_shared { // When compiling Go into PIC, the function we just diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index 0c65f7a238..4830d902c2 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -894,7 +894,7 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { p.From.Type = obj.TYPE_CONST p.From.Offset = int64(s390x.NotEqual & s390x.NotUnordered) // unordered is not possible p.Reg = s390x.REG_R3 - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 0}) + p.SetFrom3Const(0) if b.Succs[0].Block() != next { s.Br(s390x.ABR, b.Succs[0].Block()) } @@ -937,17 +937,17 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { p.From.Type = obj.TYPE_CONST p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible p.Reg = b.Controls[0].Reg() - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()}) + p.SetFrom3Reg(b.Controls[1].Reg()) case ssa.BlockS390XCGIJ, ssa.BlockS390XCIJ: p.From.Type = obj.TYPE_CONST p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible p.Reg = b.Controls[0].Reg() - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))}) + p.SetFrom3Const(int64(int8(b.AuxInt))) case ssa.BlockS390XCLGIJ, ssa.BlockS390XCLIJ: p.From.Type = obj.TYPE_CONST p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible p.Reg = b.Controls[0].Reg() - p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))}) + p.SetFrom3Const(int64(uint8(b.AuxInt))) default: b.Fatalf("branch not implemented: %s", b.LongString()) } diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index c5fe3ae2e2..4d134c6926 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -342,7 +342,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r - p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[0].Reg()}) + p.SetFrom3Reg(v.Args[0].Reg()) case ssa.Op386SUBLconst, ssa.Op386ADCLconst, diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index a24461cef2..c74de779d2 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -360,6 +360,20 @@ func (p *Prog) SetFrom3(a Addr) { p.RestArgs = []AddrPos{{a, Source}} } +// SetFrom3Reg calls p.SetFrom3 with a register Addr containing reg. +// +// Deprecated: for the same reasons as Prog.GetFrom3. +func (p *Prog) SetFrom3Reg(reg int16) { + p.SetFrom3(Addr{Type: TYPE_REG, Reg: reg}) +} + +// SetFrom3Const calls p.SetFrom3 with a const Addr containing x. +// +// Deprecated: for the same reasons as Prog.GetFrom3. +func (p *Prog) SetFrom3Const(off int64) { + p.SetFrom3(Addr{Type: TYPE_CONST, Offset: off}) +} + // SetTo2 assigns []Args{{a, 1}} to p.RestArgs when the second destination // operand does not fit into prog.RegTo2. func (p *Prog) SetTo2(a Addr) { -- GitLab From 9a555fc24c318bf1b07bdc07d5c02e372681e401 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 25 Feb 2021 12:13:23 -0800 Subject: [PATCH 0117/1298] cmd/compile: fix missing descend in Addrtaken for closures. ComputeAddrtaken needs to descend into closures, now that imported bodies can include closures. The bug was that we weren't properly setting Addrtaken for a variable inside a closure inside a function that we were importing. For now, still disable inlining of functions with closures for -G mode. I'll enable it in a later change -- there are just a few fixes related to the fact that we don't need to set Ntype for closure functions. Added a test derived from the cilium repro in the issue. Fixes #44370 Change-Id: Ida2a403636bf8740b471b3ad68b5474951811e19 Reviewed-on: https://go-review.googlesource.com/c/go/+/296649 Run-TryBot: Dan Scales Trust: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/base/flag.go | 1 + src/cmd/compile/internal/inline/inl.go | 4 +--- src/cmd/compile/internal/typecheck/subr.go | 9 +++++++-- test/fixedbugs/issue44370.dir/a.go | 20 ++++++++++++++++++++ test/fixedbugs/issue44370.dir/b.go | 11 +++++++++++ test/fixedbugs/issue44370.go | 7 +++++++ 6 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 test/fixedbugs/issue44370.dir/a.go create mode 100644 test/fixedbugs/issue44370.dir/b.go create mode 100644 test/fixedbugs/issue44370.go diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index d8ca9885cb..ade17fc0cd 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -159,6 +159,7 @@ func ParseFlags() { Flag.LinkShared = &Ctxt.Flag_linkshared Flag.Shared = &Ctxt.Flag_shared Flag.WB = true + Debug.InlFuncsWithClosures = 1 Flag.Cfg.ImportMap = make(map[string]string) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 1703be74e9..e961b10844 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -354,9 +354,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool { return true case ir.OCLOSURE: - if base.Debug.InlFuncsWithClosures == 0 { - // TODO(danscales): change default of InlFuncsWithClosures - // to 1 when #44370 is fixed + if base.Debug.InlFuncsWithClosures == 0 || base.Flag.G > 0 { v.reason = "not inlining functions with closures" return true } diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index b88a9f2283..c40cfa2288 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -106,7 +106,8 @@ var DirtyAddrtaken = false func ComputeAddrtaken(top []ir.Node) { for _, n := range top { - ir.Visit(n, func(n ir.Node) { + var doVisit func(n ir.Node) + doVisit = func(n ir.Node) { if n.Op() == ir.OADDR { if x := ir.OuterValue(n.(*ir.AddrExpr).X); x.Op() == ir.ONAME { x.Name().SetAddrtaken(true) @@ -117,7 +118,11 @@ func ComputeAddrtaken(top []ir.Node) { } } } - }) + if n.Op() == ir.OCLOSURE { + ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doVisit) + } + } + ir.Visit(n, doVisit) } } diff --git a/test/fixedbugs/issue44370.dir/a.go b/test/fixedbugs/issue44370.dir/a.go new file mode 100644 index 0000000000..c5bf1bcbc7 --- /dev/null +++ b/test/fixedbugs/issue44370.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2021 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 a + +// A StoppableWaitGroup waits for a collection of goroutines to finish. +type StoppableWaitGroup struct { + // i is the internal counter which can store tolerate negative values + // as opposed the golang's library WaitGroup. + i *int64 +} + +// NewStoppableWaitGroup returns a new StoppableWaitGroup. When the 'Stop' is +// executed, following 'Add()' calls won't have any effect. +func NewStoppableWaitGroup() *StoppableWaitGroup { + return &StoppableWaitGroup{ + i: func() *int64 { i := int64(0); return &i }(), + } +} diff --git a/test/fixedbugs/issue44370.dir/b.go b/test/fixedbugs/issue44370.dir/b.go new file mode 100644 index 0000000000..f0e0b4e55f --- /dev/null +++ b/test/fixedbugs/issue44370.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 b + +import "./a" + +func JoinClusterServices() { + _ = a.NewStoppableWaitGroup() +} diff --git a/test/fixedbugs/issue44370.go b/test/fixedbugs/issue44370.go new file mode 100644 index 0000000000..d406838588 --- /dev/null +++ b/test/fixedbugs/issue44370.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2021 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 ignored -- GitLab From e25040d16288563c89cead5e8da8d3b9c74ab655 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 4 Feb 2021 16:42:35 -0500 Subject: [PATCH 0118/1298] cmd/compile: change StaticCall to return a "Results" StaticLECall (multiple value in +mem, multiple value result +mem) -> StaticCall (multiple ergister value in +mem, multiple register-sized-value result +mem) -> ARCH CallStatic (multiple ergister value in +mem, multiple register-sized-value result +mem) But the architecture-dependent stuff is indifferent to whether it is mem->mem or (mem)->(mem) until Prog generation. Deal with OpSelectN -> Prog in ssagen/ssa.go, others, as they appear. For #40724. Change-Id: I1d0436f6371054f1881862641d8e7e418e4a6a16 Reviewed-on: https://go-review.googlesource.com/c/go/+/293391 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 83 +++- src/cmd/compile/internal/ssa/cse.go | 2 +- src/cmd/compile/internal/ssa/expand_calls.go | 38 +- .../compile/internal/ssa/gen/generic.rules | 54 +-- .../compile/internal/ssa/gen/genericOps.go | 2 +- src/cmd/compile/internal/ssa/location.go | 14 + src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/op.go | 10 + src/cmd/compile/internal/ssa/opGen.go | 2 +- src/cmd/compile/internal/ssa/regalloc.go | 20 +- src/cmd/compile/internal/ssa/rewrite.go | 14 +- .../compile/internal/ssa/rewritegeneric.go | 411 ++++++------------ src/cmd/compile/internal/ssa/schedule.go | 16 +- src/cmd/compile/internal/ssa/tighten.go | 3 +- src/cmd/compile/internal/ssa/tuple.go | 40 +- src/cmd/compile/internal/ssa/writebarrier.go | 17 +- src/cmd/compile/internal/ssagen/ssa.go | 18 +- src/cmd/compile/internal/types/type.go | 23 +- 18 files changed, 387 insertions(+), 382 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 4bd27efb59..b43d95e976 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -27,6 +27,8 @@ type ABIParamResultInfo struct { outparams []ABIParamAssignment offsetToSpillArea int64 spillAreaSize int64 + inRegistersUsed int + outRegistersUsed int config *ABIConfig // to enable String() method } @@ -42,6 +44,14 @@ func (a *ABIParamResultInfo) OutParams() []ABIParamAssignment { return a.outparams } +func (a *ABIParamResultInfo) InRegistersUsed() int { + return a.inRegistersUsed +} + +func (a *ABIParamResultInfo) OutRegistersUsed() int { + return a.outRegistersUsed +} + func (a *ABIParamResultInfo) InParam(i int) ABIParamAssignment { return a.inparams[i] } @@ -164,6 +174,55 @@ func (a *ABIConfig) NumParamRegs(t *types.Type) int { return n } +// preAllocateParams gets the slice sizes right for inputs and outputs. +func (a *ABIParamResultInfo) preAllocateParams(hasRcvr bool, nIns, nOuts int) { + if hasRcvr { + nIns++ + } + a.inparams = make([]ABIParamAssignment, 0, nIns) + a.outparams = make([]ABIParamAssignment, 0, nOuts) +} + +// ABIAnalyzeTypes takes an optional receiver type, arrays of ins and outs, and returns an ABIParamResultInfo, +// based on the given configuration. This is the same result computed by config.ABIAnalyze applied to the +// corresponding method/function type, except that all the embedded parameter names are nil. +// This is intended for use by ssagen/ssa.go:(*state).rtcall, for runtime functions that lack a parsed function type. +func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Type) *ABIParamResultInfo { + setup() + s := assignState{ + rTotal: config.regAmounts, + } + result := &ABIParamResultInfo{config: config} + result.preAllocateParams(rcvr != nil, len(ins), len(outs)) + + // Receiver + if rcvr != nil { + result.inparams = append(result.inparams, + s.assignParamOrReturn(rcvr, nil, false)) + } + + // Inputs + for _, t := range ins { + result.inparams = append(result.inparams, + s.assignParamOrReturn(t, nil, false)) + } + s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) + result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + + // Outputs + s.rUsed = RegAmounts{} + for _, t := range outs { + result.outparams = append(result.outparams, s.assignParamOrReturn(t, nil, true)) + } + // The spill area is at a register-aligned offset and its size is rounded up to a register alignment. + // TODO in theory could align offset only to minimum required by spilled data types. + result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize) + result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) + result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + + return result +} + // ABIAnalyze takes a function type 't' and an ABI rules description // 'config' and analyzes the function to determine how its parameters // and results will be passed (in registers or on the stack), returning @@ -174,33 +233,37 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { rTotal: config.regAmounts, } result := &ABIParamResultInfo{config: config} + ft := t.FuncType() + result.preAllocateParams(t.NumRecvs() != 0, ft.Params.NumFields(), ft.Results.NumFields()) // Receiver - ft := t.FuncType() + // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters if t.NumRecvs() != 0 { - rfsl := ft.Receiver.FieldSlice() + r := ft.Receiver.FieldSlice()[0] result.inparams = append(result.inparams, - s.assignParamOrReturn(rfsl[0], false)) + s.assignParamOrReturn(r.Type, r.Nname, false)) } // Inputs ifsl := ft.Params.FieldSlice() for _, f := range ifsl { result.inparams = append(result.inparams, - s.assignParamOrReturn(f, false)) + s.assignParamOrReturn(f.Type, f.Nname, false)) } s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize)) + result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs // Outputs s.rUsed = RegAmounts{} ofsl := ft.Results.FieldSlice() for _, f := range ofsl { - result.outparams = append(result.outparams, s.assignParamOrReturn(f, true)) + result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, f.Nname, true)) } // The spill area is at a register-aligned offset and its size is rounded up to a register alignment. // TODO in theory could align offset only to minimum required by spilled data types. result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize) result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) + result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs return result } @@ -460,17 +523,15 @@ func (state *assignState) regassign(pt *types.Type) bool { // of field f to determine whether it can be register assigned. // The result of the analysis is recorded in the result // ABIParamResultInfo held in 'state'. -func (state *assignState) assignParamOrReturn(f *types.Field, isReturn bool) ABIParamAssignment { - // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters - pt := f.Type +func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, isReturn bool) ABIParamAssignment { state.pUsed = RegAmounts{} if pt.Width == types.BADWIDTH { panic("should never happen") } else if pt.Width == 0 { - return state.stackAllocate(pt, f.Nname) + return state.stackAllocate(pt, n) } else if state.regassign(pt) { - return state.regAllocate(pt, f.Nname, isReturn) + return state.regAllocate(pt, n, isReturn) } else { - return state.stackAllocate(pt, f.Nname) + return state.stackAllocate(pt, n) } } diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index f78527410c..ade5e0648e 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -299,7 +299,7 @@ func cmpVal(v, w *Value, auxIDs auxmap) types.Cmp { // OpSelect is a pseudo-op. We need to be more aggressive // regarding CSE to keep multiple OpSelect's of the same // argument from existing. - if v.Op != OpSelect0 && v.Op != OpSelect1 { + if v.Op != OpSelect0 && v.Op != OpSelect1 && v.Op != OpSelectN { if tc := v.Type.Compare(w.Type); tc != types.CMPeq { return tc } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 85d6fda427..292b0b41ce 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -170,6 +170,7 @@ type expandState struct { sdom SparseTree common map[selKey]*Value offsets map[offsetKey]*Value + memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. } // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target @@ -280,7 +281,6 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, if !x.isAlreadyExpandedAggregateType(selector.Type) { if leafType == selector.Type { // OpIData leads us here, sometimes. leaf.copyOf(selector) - } else { x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString()) } @@ -357,13 +357,43 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, which := selector.AuxInt if which == aux.NResults() { // mem is after the results. // rewrite v as a Copy of call -- the replacement call will produce a mem. - leaf.copyOf(call) + if call.Op == OpStaticLECall { + if leaf != selector { + panic("Unexpected selector of memory") + } + // StaticCall selector will address last element of Result. + // TODO do this for all the other call types eventually. + if aux.abiInfo == nil { + panic(fmt.Errorf("aux.abiInfo nil for call %s", call.LongString())) + } + if existing := x.memForCall[call.ID]; existing == nil { + selector.AuxInt = int64(aux.abiInfo.OutRegistersUsed()) + x.memForCall[call.ID] = selector + } else { + selector.copyOf(existing) + } + } else { + leaf.copyOf(call) + } } else { leafType := removeTrivialWrapperTypes(leaf.Type) if x.canSSAType(leafType) { pt := types.NewPtr(leafType) off := x.offsetFrom(x.sp, offset+aux.OffsetOfResult(which), pt) // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input. + if call.Op == OpStaticLECall { // TODO this is temporary until all calls are register-able + // Create a "mem" for any loads that need to occur. + if mem := x.memForCall[call.ID]; mem != nil { + if mem.Block != call.Block { + panic(fmt.Errorf("selector and call need to be in same block, selector=%s; call=%s", selector.LongString(), call.LongString())) + } + call = mem + } else { + mem = call.Block.NewValue1I(call.Pos.WithNotStmt(), OpSelectN, types.TypeMem, int64(aux.abiInfo.OutRegistersUsed()), call) + x.memForCall[call.ID] = mem + call = mem + } + } if leaf.Block == call.Block { leaf.reset(OpLoad) leaf.SetArgs2(off, call) @@ -835,6 +865,7 @@ func expandCalls(f *Func) { sdom: f.Sdom(), common: make(map[selKey]*Value), offsets: make(map[offsetKey]*Value), + memForCall: make(map[ID]*Value), } // For 32-bit, need to deal with decomposition of 64-bit integers, which depends on endianness. @@ -1173,7 +1204,8 @@ func expandCalls(f *Func) { switch v.Op { case OpStaticLECall: v.Op = OpStaticCall - v.Type = types.TypeMem + // TODO need to insert all the register types. + v.Type = types.NewResults([]*types.Type{types.TypeMem}) case OpClosureLECall: v.Op = OpClosureCall v.Type = types.TypeMem diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 1784923224..fab45243ed 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -1970,37 +1970,6 @@ (Sqrt (Const64F [c])) && !math.IsNaN(math.Sqrt(c)) => (Const64F [math.Sqrt(c)]) -// recognize runtime.newobject and don't Zero/Nilcheck it -(Zero (Load (OffPtr [c] (SP)) mem) mem) - && mem.Op == OpStaticCall - && isSameCall(mem.Aux, "runtime.newobject") - && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value - => mem -(Store (Load (OffPtr [c] (SP)) mem) x mem) - && isConstZero(x) - && mem.Op == OpStaticCall - && isSameCall(mem.Aux, "runtime.newobject") - && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value - => mem -(Store (OffPtr (Load (OffPtr [c] (SP)) mem)) x mem) - && isConstZero(x) - && mem.Op == OpStaticCall - && isSameCall(mem.Aux, "runtime.newobject") - && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value - => mem -// nil checks just need to rewrite to something useless. -// they will be deadcode eliminated soon afterwards. -(NilCheck (Load (OffPtr [c] (SP)) (StaticCall {sym} _)) _) - && isSameCall(sym, "runtime.newobject") - && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value - && warnRule(fe.Debug_checknil(), v, "removed nil check") - => (Invalid) -(NilCheck (OffPtr (Load (OffPtr [c] (SP)) (StaticCall {sym} _))) _) - && isSameCall(sym, "runtime.newobject") - && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value - && warnRule(fe.Debug_checknil(), v, "removed nil check") - => (Invalid) - // for rewriting results of some late-expanded rewrites (below) (SelectN [0] (MakeResult a ___)) => a (SelectN [1] (MakeResult a b ___)) => b @@ -2021,12 +1990,12 @@ && isSameCall(call.Aux, "runtime.newobject") => mem -(NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call)) +(NilCheck (SelectN [0] call:(StaticLECall _ _)) _) && isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") => (Invalid) -(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call)) +(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _) && isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") => (Invalid) @@ -2083,15 +2052,19 @@ (IsNonNil (Addr _)) => (ConstBool [true]) (IsNonNil (LocalAddr _ _)) => (ConstBool [true]) +// TODO REGISTER ARGS this will need revision. +// Because expand calls runs after prove, constants useful to this pattern may not appear +// In the future both versions need to exist; the memory and register variants. + // Inline small or disjoint runtime.memmove calls with constant length. // See the comment in op Move in genericOps.go for discussion of the type. -(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) +(SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) && sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() // avoids TUINTPTR, see issue 30061 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) - && clobber(s1, s2, s3) + && clobber(s1, s2, s3, call) => (Move {t.Elem()} [int64(sz)] dst src mem) // Inline small or disjoint runtime.memmove calls with constant length. @@ -2105,13 +2078,6 @@ && clobber(call) => (Move {dst.Type.Elem()} [int64(sz)] dst src mem) -// De-virtualize interface calls into static calls. -// Note that (ITab (IMake)) doesn't get -// rewritten until after the first opt pass, -// so this rule should trigger reliably. -(InterCall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) mem) && devirt(v, auxCall, itab, off) != nil => - (StaticCall [int32(argsize)] {devirt(v, auxCall, itab, off)} mem) - // De-virtualize late-expanded interface calls into late-expanded static calls. // Note that (ITab (IMake)) doesn't get rewritten until after the first opt pass, // so this rule should trigger reliably. @@ -2499,8 +2465,8 @@ (Store {t5} (OffPtr [o5] dst) d4 (Zero {t1} [n] dst mem))))) -// TODO this does not fire before call expansion; is that acceptable? -(StaticCall {sym} x) && needRaceCleanup(sym, v) => x +(SelectN [0] call:(StaticLECall {sym} a x)) && needRaceCleanup(sym, call) && clobber(call) => x +(SelectN [0] call:(StaticLECall {sym} x)) && needRaceCleanup(sym, call) && clobber(call) => x // Collapse moving A -> B -> C into just A -> C. // Later passes (deadstore, elim unread auto) will remove the A -> B move, if possible. diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 23a2d74b14..043f445c16 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -396,7 +396,7 @@ var genericOps = []opData{ // to match StaticCall's 32 bit arg size limit. // TODO(drchase,josharian): could the arg size limit be bundled into the rules for CallOff? {name: "ClosureCall", argLength: 3, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory. - {name: "StaticCall", argLength: 1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0=memory. auxint=arg size. Returns memory. + {name: "StaticCall", argLength: -1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0..argN-1 are register inputs, argN=memory. auxint=arg size. Returns Result of register results, plus memory. {name: "InterCall", argLength: 2, aux: "CallOff", call: true}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory. {name: "ClosureLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded closure call. arg0=code pointer, arg1=context ptr, arg2..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 4cd0ac8d77..af0a913d17 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -88,6 +88,20 @@ func (t LocPair) String() string { return fmt.Sprintf("<%s,%s>", n0, n1) } +type LocResults []Location + +func (t LocResults) String() string { + s := "<" + a := "" + for _, r := range t { + a += s + s = "," + a += r.String() + } + a += ">" + return a +} + type ArgPair struct { reg *Register mem LocalSlot diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index f332b2e028..f6b2bf86a9 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,7 +21,7 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpConvert, OpInlMark: + case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark: continue // ok not to lower case OpGetG: if f.Config.hasGReg { diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 55e0602f2f..6949bdca31 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -203,9 +203,19 @@ func (a *AuxCall) String() string { return fn + "}" } +func ACParamsToTypes(ps []Param) (ts []*types.Type) { + for _, p := range ps { + ts = append(ts, p.Type) + } + return +} + // StaticAuxCall returns an AuxCall for a static call. func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { // TODO Create regInfo for AuxCall + if paramResultInfo == nil { + panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) + } return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo} } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 10ea57b36b..2d37ae4357 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -35435,7 +35435,7 @@ var opcodeTable = [...]opInfo{ { name: "StaticCall", auxType: auxCallOff, - argLen: 1, + argLen: -1, call: true, generic: true, }, diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 8c25b1c81d..99e101281b 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -761,6 +761,9 @@ func (s *regAllocState) advanceUses(v *Value) { // current instruction. func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool { u := s.values[v.ID].uses + if u == nil { + panic(fmt.Errorf("u is nil, v = %s, s.values[v.ID] = %v", v.LongString(), s.values[v.ID])) + } d := u.dist for u != nil && u.dist == d { u = u.next @@ -1208,13 +1211,17 @@ func (s *regAllocState) regalloc(f *Func) { s.sb = v.ID continue } - if v.Op == OpSelect0 || v.Op == OpSelect1 { + if v.Op == OpSelect0 || v.Op == OpSelect1 || v.Op == OpSelectN { if s.values[v.ID].needReg { - var i = 0 - if v.Op == OpSelect1 { - i = 1 + if v.Op == OpSelectN { + s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocResults)[int(v.AuxInt)].(*Register).num), v, v) + } else { + var i = 0 + if v.Op == OpSelect1 { + i = 1 + } + s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocPair)[i].(*Register).num), v, v) } - s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocPair)[i].(*Register).num), v, v) } b.Values = append(b.Values, v) s.advanceUses(v) @@ -1767,6 +1774,9 @@ func (s *regAllocState) placeSpills() { // put the spill of v. At the start "best" is the best place // we have found so far. // TODO: find a way to make this O(1) without arbitrary cutoffs. + if v == nil { + panic(fmt.Errorf("nil v, s.orig[%d], vi = %v, spill = %s", i, vi, spill.LongString())) + } best := v.Block bestArg := v var bestDepth int16 diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index ac6278ab9d..19b97a3ed1 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -793,7 +793,10 @@ func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym { func devirtLECall(v *Value, sym *obj.LSym) *Value { v.Op = OpStaticLECall - v.Aux.(*AuxCall).Fn = sym + auxcall := v.Aux.(*AuxCall) + auxcall.Fn = sym + // TODO(register args) this should not be necessary when fully transition to the new register ABI. + auxcall.abiInfo = v.Block.Func.ABIDefault.ABIAnalyzeTypes(nil, ACParamsToTypes(auxcall.args), ACParamsToTypes(auxcall.results)) v.RemoveArg(0) return v } @@ -1617,7 +1620,7 @@ func needRaceCleanup(sym *AuxCall, v *Value) bool { for _, b := range f.Blocks { for _, v := range b.Values { switch v.Op { - case OpStaticCall: + case OpStaticCall, OpStaticLECall: // Check for racefuncenter/racefuncenterfp will encounter racefuncexit and vice versa. // Allow calls to panic* s := v.Aux.(*AuxCall).Fn.String() @@ -1632,15 +1635,20 @@ func needRaceCleanup(sym *AuxCall, v *Value) bool { return false case OpPanicBounds, OpPanicExtend: // Note: these are panic generators that are ok (like the static calls above). - case OpClosureCall, OpInterCall: + case OpClosureCall, OpInterCall, OpClosureLECall, OpInterLECall: // We must keep the race functions if there are any other call types. return false } } } if isSameCall(sym, "runtime.racefuncenter") { + // TODO REGISTER ABI this needs to be cleaned up. // If we're removing racefuncenter, remove its argument as well. if v.Args[0].Op != OpStore { + if v.Op == OpStaticLECall { + // there is no store, yet. + return true + } return false } mem := v.Args[0].Args[2] diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 958e24d29f..e5a27199a7 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -122,8 +122,6 @@ func rewriteValuegeneric(v *Value) bool { return rewriteValuegeneric_OpEqSlice(v) case OpIMake: return rewriteValuegeneric_OpIMake(v) - case OpInterCall: - return rewriteValuegeneric_OpInterCall(v) case OpInterLECall: return rewriteValuegeneric_OpInterLECall(v) case OpIsInBounds: @@ -392,8 +390,6 @@ func rewriteValuegeneric(v *Value) bool { return rewriteValuegeneric_OpSlicemask(v) case OpSqrt: return rewriteValuegeneric_OpSqrt(v) - case OpStaticCall: - return rewriteValuegeneric_OpStaticCall(v) case OpStaticLECall: return rewriteValuegeneric_OpStaticLECall(v) case OpStore: @@ -8542,52 +8538,6 @@ func rewriteValuegeneric_OpIMake(v *Value) bool { } return false } -func rewriteValuegeneric_OpInterCall(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - // match: (InterCall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) mem) - // cond: devirt(v, auxCall, itab, off) != nil - // result: (StaticCall [int32(argsize)] {devirt(v, auxCall, itab, off)} mem) - for { - argsize := auxIntToInt32(v.AuxInt) - auxCall := auxToCall(v.Aux) - if v_0.Op != OpLoad { - break - } - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpOffPtr { - break - } - off := auxIntToInt64(v_0_0.AuxInt) - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpITab { - break - } - v_0_0_0_0 := v_0_0_0.Args[0] - if v_0_0_0_0.Op != OpIMake { - break - } - v_0_0_0_0_0 := v_0_0_0_0.Args[0] - if v_0_0_0_0_0.Op != OpAddr { - break - } - itab := auxToSym(v_0_0_0_0_0.Aux) - v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0] - if v_0_0_0_0_0_0.Op != OpSB { - break - } - mem := v_1 - if !(devirt(v, auxCall, itab, off) != nil) { - break - } - v.reset(OpStaticCall) - v.AuxInt = int32ToAuxInt(int32(argsize)) - v.Aux = callToAux(devirt(v, auxCall, itab, off)) - v.AddArg(mem) - return true - } - return false -} func rewriteValuegeneric_OpInterLECall(v *Value) bool { // match: (InterLECall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) ___) // cond: devirtLESym(v, auxCall, itab, off) != nil @@ -16113,7 +16063,6 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block - config := b.Func.Config fe := b.Func.fe // match: (NilCheck (GetG mem) mem) // result: mem @@ -16128,67 +16077,7 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { v.copyOf(mem) return true } - // match: (NilCheck (Load (OffPtr [c] (SP)) (StaticCall {sym} _)) _) - // cond: isSameCall(sym, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.RegSize && warnRule(fe.Debug_checknil(), v, "removed nil check") - // result: (Invalid) - for { - if v_0.Op != OpLoad { - break - } - _ = v_0.Args[1] - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpOffPtr { - break - } - c := auxIntToInt64(v_0_0.AuxInt) - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpSP { - break - } - v_0_1 := v_0.Args[1] - if v_0_1.Op != OpStaticCall { - break - } - sym := auxToCall(v_0_1.Aux) - if !(isSameCall(sym, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(fe.Debug_checknil(), v, "removed nil check")) { - break - } - v.reset(OpInvalid) - return true - } - // match: (NilCheck (OffPtr (Load (OffPtr [c] (SP)) (StaticCall {sym} _))) _) - // cond: isSameCall(sym, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.RegSize && warnRule(fe.Debug_checknil(), v, "removed nil check") - // result: (Invalid) - for { - if v_0.Op != OpOffPtr { - break - } - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpLoad { - break - } - _ = v_0_0.Args[1] - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpOffPtr { - break - } - c := auxIntToInt64(v_0_0_0.AuxInt) - v_0_0_0_0 := v_0_0_0.Args[0] - if v_0_0_0_0.Op != OpSP { - break - } - v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpStaticCall { - break - } - sym := auxToCall(v_0_0_1.Aux) - if !(isSameCall(sym, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize && warnRule(fe.Debug_checknil(), v, "removed nil check")) { - break - } - v.reset(OpInvalid) - return true - } - // match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call)) + // match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) _) // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") // result: (Invalid) for { @@ -16196,13 +16085,13 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { break } call := v_0.Args[0] - if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { + if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { break } v.reset(OpInvalid) return true } - // match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call)) + // match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _) // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") // result: (Invalid) for { @@ -16214,7 +16103,7 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { break } call := v_0_0.Args[0] - if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { + if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { break } v.reset(OpInvalid) @@ -20799,6 +20688,94 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { v.copyOf(c) return true } + // match: (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) + // result: (Move {t.Elem()} [int64(sz)] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpStaticCall || len(call.Args) != 1 { + break + } + sym := auxToCall(call.Aux) + s1 := call.Args[0] + if s1.Op != OpStore { + break + } + _ = s1.Args[2] + s1_1 := s1.Args[1] + if s1_1.Op != OpConst64 { + break + } + sz := auxIntToInt64(s1_1.AuxInt) + s2 := s1.Args[2] + if s2.Op != OpStore { + break + } + _ = s2.Args[2] + src := s2.Args[1] + s3 := s2.Args[2] + if s3.Op != OpStore { + break + } + t := auxToType(s3.Aux) + mem := s3.Args[2] + dst := s3.Args[1] + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(int64(sz)) + v.Aux = typeToAux(t.Elem()) + v.AddArg3(dst, src, mem) + return true + } + // match: (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const32 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) + // result: (Move {t.Elem()} [int64(sz)] dst src mem) + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpStaticCall || len(call.Args) != 1 { + break + } + sym := auxToCall(call.Aux) + s1 := call.Args[0] + if s1.Op != OpStore { + break + } + _ = s1.Args[2] + s1_1 := s1.Args[1] + if s1_1.Op != OpConst32 { + break + } + sz := auxIntToInt32(s1_1.AuxInt) + s2 := s1.Args[2] + if s2.Op != OpStore { + break + } + _ = s2.Args[2] + src := s2.Args[1] + s3 := s2.Args[2] + if s3.Op != OpStore { + break + } + t := auxToType(s3.Aux) + mem := s3.Args[2] + dst := s3.Args[1] + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { + break + } + v.reset(OpMove) + v.AuxInt = int64ToAuxInt(int64(sz)) + v.Aux = typeToAux(t.Elem()) + v.AddArg3(dst, src, mem) + return true + } // match: (SelectN [0] call:(StaticLECall {sym} dst src (Const64 [sz]) mem)) // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem) @@ -20857,6 +20834,44 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { v.AddArg3(dst, src, mem) return true } + // match: (SelectN [0] call:(StaticLECall {sym} a x)) + // cond: needRaceCleanup(sym, call) && clobber(call) + // result: x + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpStaticLECall || len(call.Args) != 2 { + break + } + sym := auxToCall(call.Aux) + x := call.Args[1] + if !(needRaceCleanup(sym, call) && clobber(call)) { + break + } + v.copyOf(x) + return true + } + // match: (SelectN [0] call:(StaticLECall {sym} x)) + // cond: needRaceCleanup(sym, call) && clobber(call) + // result: x + for { + if auxIntToInt64(v.AuxInt) != 0 { + break + } + call := v_0 + if call.Op != OpStaticLECall || len(call.Args) != 1 { + break + } + sym := auxToCall(call.Aux) + x := call.Args[0] + if !(needRaceCleanup(sym, call) && clobber(call)) { + break + } + v.copyOf(x) + return true + } return false } func rewriteValuegeneric_OpSignExt16to32(v *Value) bool { @@ -21307,98 +21322,6 @@ func rewriteValuegeneric_OpSqrt(v *Value) bool { } return false } -func rewriteValuegeneric_OpStaticCall(v *Value) bool { - v_0 := v.Args[0] - b := v.Block - config := b.Func.Config - // match: (StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) - // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3) - // result: (Move {t.Elem()} [int64(sz)] dst src mem) - for { - sym := auxToCall(v.Aux) - s1 := v_0 - if s1.Op != OpStore { - break - } - _ = s1.Args[2] - s1_1 := s1.Args[1] - if s1_1.Op != OpConst64 { - break - } - sz := auxIntToInt64(s1_1.AuxInt) - s2 := s1.Args[2] - if s2.Op != OpStore { - break - } - _ = s2.Args[2] - src := s2.Args[1] - s3 := s2.Args[2] - if s3.Op != OpStore { - break - } - t := auxToType(s3.Aux) - mem := s3.Args[2] - dst := s3.Args[1] - if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3)) { - break - } - v.reset(OpMove) - v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(t.Elem()) - v.AddArg3(dst, src, mem) - return true - } - // match: (StaticCall {sym} s1:(Store _ (Const32 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) - // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3) - // result: (Move {t.Elem()} [int64(sz)] dst src mem) - for { - sym := auxToCall(v.Aux) - s1 := v_0 - if s1.Op != OpStore { - break - } - _ = s1.Args[2] - s1_1 := s1.Args[1] - if s1_1.Op != OpConst32 { - break - } - sz := auxIntToInt32(s1_1.AuxInt) - s2 := s1.Args[2] - if s2.Op != OpStore { - break - } - _ = s2.Args[2] - src := s2.Args[1] - s3 := s2.Args[2] - if s3.Op != OpStore { - break - } - t := auxToType(s3.Aux) - mem := s3.Args[2] - dst := s3.Args[1] - if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3)) { - break - } - v.reset(OpMove) - v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(t.Elem()) - v.AddArg3(dst, src, mem) - return true - } - // match: (StaticCall {sym} x) - // cond: needRaceCleanup(sym, v) - // result: x - for { - sym := auxToCall(v.Aux) - x := v_0 - if !(needRaceCleanup(sym, v)) { - break - } - v.copyOf(x) - return true - } - return false -} func rewriteValuegeneric_OpStaticLECall(v *Value) bool { b := v.Block typ := &b.Func.Config.Types @@ -21442,7 +21365,6 @@ func rewriteValuegeneric_OpStore(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block - config := b.Func.Config fe := b.Func.fe // match: (Store {t1} p1 (Load p2 mem) mem) // cond: isSamePtr(p1, p2) && t2.Size() == t1.Size() @@ -21890,58 +21812,6 @@ func rewriteValuegeneric_OpStore(v *Value) bool { v.AddArg3(dst, e, mem) return true } - // match: (Store (Load (OffPtr [c] (SP)) mem) x mem) - // cond: isConstZero(x) && mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.RegSize - // result: mem - for { - if v_0.Op != OpLoad { - break - } - mem := v_0.Args[1] - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpOffPtr { - break - } - c := auxIntToInt64(v_0_0.AuxInt) - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpSP { - break - } - x := v_1 - if mem != v_2 || !(isConstZero(x) && mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) { - break - } - v.copyOf(mem) - return true - } - // match: (Store (OffPtr (Load (OffPtr [c] (SP)) mem)) x mem) - // cond: isConstZero(x) && mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.RegSize - // result: mem - for { - if v_0.Op != OpOffPtr { - break - } - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpLoad { - break - } - mem := v_0_0.Args[1] - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpOffPtr { - break - } - c := auxIntToInt64(v_0_0_0.AuxInt) - v_0_0_0_0 := v_0_0_0.Args[0] - if v_0_0_0_0.Op != OpSP { - break - } - x := v_1 - if mem != v_2 || !(isConstZero(x) && mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) { - break - } - v.copyOf(mem) - return true - } // match: (Store (SelectN [0] call:(StaticLECall _ _)) x mem:(SelectN [1] call)) // cond: isConstZero(x) && isSameCall(call.Aux, "runtime.newobject") // result: mem @@ -24660,27 +24530,6 @@ func rewriteValuegeneric_OpZero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] b := v.Block - config := b.Func.Config - // match: (Zero (Load (OffPtr [c] (SP)) mem) mem) - // cond: mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.RegSize - // result: mem - for { - if v_0.Op != OpLoad { - break - } - mem := v_0.Args[1] - v_0_0 := v_0.Args[0] - if v_0_0.Op != OpOffPtr { - break - } - c := auxIntToInt64(v_0_0.AuxInt) - v_0_0_0 := v_0_0.Args[0] - if v_0_0_0.Op != OpSP || mem != v_1 || !(mem.Op == OpStaticCall && isSameCall(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize()+config.RegSize) { - break - } - v.copyOf(mem) - return true - } // match: (Zero (SelectN [0] call:(StaticLECall _ _)) mem:(SelectN [1] call)) // cond: isSameCall(call.Aux, "runtime.newobject") // result: mem diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index 8facb91100..6b34310db7 100644 --- a/src/cmd/compile/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go @@ -145,7 +145,7 @@ func schedule(f *Func) { // reduce register pressure. It also helps make sure // VARDEF ops are scheduled before the corresponding LEA. score[v.ID] = ScoreMemory - case v.Op == OpSelect0 || v.Op == OpSelect1: + case v.Op == OpSelect0 || v.Op == OpSelect1 || v.Op == OpSelectN: // Schedule the pseudo-op of reading part of a tuple // immediately after the tuple-generating op, since // this value is already live. This also removes its @@ -270,6 +270,20 @@ func schedule(f *Func) { tuples[v.Args[0].ID] = make([]*Value, 2) } tuples[v.Args[0].ID][1] = v + case v.Op == OpSelectN: + if tuples[v.Args[0].ID] == nil { + tuples[v.Args[0].ID] = make([]*Value, v.Args[0].Type.NumFields()) + } + tuples[v.Args[0].ID][v.AuxInt] = v + case v.Type.IsResults() && tuples[v.ID] != nil: + tup := tuples[v.ID] + for i := len(tup) - 1; i >= 0; i-- { + if tup[i] != nil { + order = append(order, tup[i]) + } + } + delete(tuples, v.ID) + order = append(order, v) case v.Type.IsTuple() && tuples[v.ID] != nil: if tuples[v.ID][1] != nil { order = append(order, tuples[v.ID][1]) diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index 5dfc453649..bd08334a5f 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -18,10 +18,11 @@ func tighten(f *Func) { continue } switch v.Op { - case OpPhi, OpArg, OpSelect0, OpSelect1: + case OpPhi, OpArg, OpSelect0, OpSelect1, OpSelectN: // Phis need to stay in their block. // Arg must stay in the entry block. // Tuple selectors must stay with the tuple generator. + // SelectN is typically, ultimately, a register. continue } if v.MemoryArg() != nil { diff --git a/src/cmd/compile/internal/ssa/tuple.go b/src/cmd/compile/internal/ssa/tuple.go index 38deabf83d..289df40431 100644 --- a/src/cmd/compile/internal/ssa/tuple.go +++ b/src/cmd/compile/internal/ssa/tuple.go @@ -4,8 +4,8 @@ package ssa -// tightenTupleSelectors ensures that tuple selectors (Select0 and -// Select1 ops) are in the same block as their tuple generator. The +// tightenTupleSelectors ensures that tuple selectors (Select0, Select1, +// and SelectN ops) are in the same block as their tuple generator. The // function also ensures that there are no duplicate tuple selectors. // These properties are expected by the scheduler but may not have // been maintained by the optimization pipeline up to this point. @@ -13,28 +13,40 @@ package ssa // See issues 16741 and 39472. func tightenTupleSelectors(f *Func) { selectors := make(map[struct { - id ID - op Op + id ID + which int }]*Value) for _, b := range f.Blocks { for _, selector := range b.Values { - if selector.Op != OpSelect0 && selector.Op != OpSelect1 { + // Key fields for de-duplication + var tuple *Value + idx := 0 + switch selector.Op { + default: continue - } - - // Get the tuple generator to use as a key for de-duplication. - tuple := selector.Args[0] - if !tuple.Type.IsTuple() { - f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString()) + case OpSelect1: + idx = 1 + fallthrough + case OpSelect0: + tuple = selector.Args[0] + if !tuple.Type.IsTuple() { + f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString()) + } + case OpSelectN: + tuple = selector.Args[0] + idx = int(selector.AuxInt) + if !tuple.Type.IsResults() { + f.Fatalf("arg of result selector %s is not a results: %s", selector.String(), tuple.LongString()) + } } // If there is a pre-existing selector in the target block then // use that. Do this even if the selector is already in the // target block to avoid duplicate tuple selectors. key := struct { - id ID - op Op - }{tuple.ID, selector.Op} + id ID + which int + }{tuple.ID, idx} if t := selectors[key]; t != nil { if selector != t { selector.copyOf(t) diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 7d375da128..0af039577f 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -487,12 +487,14 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va off := config.ctxt.FixedFrameSize() var ACArgs []Param + var argTypes []*types.Type if typ != nil { // for typedmemmove taddr := b.NewValue1A(pos, OpAddr, b.Func.Config.Types.Uintptr, typ, sb) off = round(off, taddr.Type.Alignment()) arg := b.NewValue1I(pos, OpOffPtr, taddr.Type.PtrTo(), off, sp) mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, taddr, mem) ACArgs = append(ACArgs, Param{Type: b.Func.Config.Types.Uintptr, Offset: int32(off)}) + argTypes = append(argTypes, b.Func.Config.Types.Uintptr) off += taddr.Type.Size() } @@ -500,6 +502,7 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va arg := b.NewValue1I(pos, OpOffPtr, ptr.Type.PtrTo(), off, sp) mem = b.NewValue3A(pos, OpStore, types.TypeMem, ptr.Type, arg, ptr, mem) ACArgs = append(ACArgs, Param{Type: ptr.Type, Offset: int32(off)}) + argTypes = append(argTypes, ptr.Type) off += ptr.Type.Size() if val != nil { @@ -507,15 +510,15 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va arg = b.NewValue1I(pos, OpOffPtr, val.Type.PtrTo(), off, sp) mem = b.NewValue3A(pos, OpStore, types.TypeMem, val.Type, arg, val, mem) ACArgs = append(ACArgs, Param{Type: val.Type, Offset: int32(off)}) + argTypes = append(argTypes, val.Type) off += val.Type.Size() } off = round(off, config.PtrSize) // issue call - // TODO(register args) -- will need more details - mem = b.NewValue1A(pos, OpStaticCall, types.TypeMem, StaticAuxCall(fn, ACArgs, nil, nil), mem) + mem = b.NewValue1A(pos, OpStaticCall, types.TypeResultMem, StaticAuxCall(fn, ACArgs, nil, b.Func.ABIDefault.ABIAnalyzeTypes(nil, argTypes, nil)), mem) mem.AuxInt = off - config.ctxt.FixedFrameSize() - return mem + return b.NewValue1I(pos, OpSelectN, types.TypeMem, 0, mem) } // round to a multiple of r, r is a power of 2 @@ -563,12 +566,20 @@ func IsReadOnlyGlobalAddr(v *Value) bool { // IsNewObject reports whether v is a pointer to a freshly allocated & zeroed object at memory state mem. func IsNewObject(v *Value, mem *Value) bool { + // TODO this will need updating for register args; the OpLoad is wrong. if v.Op != OpLoad { return false } if v.MemoryArg() != mem { return false } + if mem.Op != OpSelectN { + return false + } + if mem.Type != types.TypeMem { + return false + } // assume it is the right selection if true + mem = mem.Args[0] if mem.Op != OpStaticCall { return false } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 20acdbdc66..ba00b9c7f6 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4734,7 +4734,8 @@ func (s *state) openDeferExit() { aux := ssa.ClosureAuxCall(ACArgs, ACResults) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v) } else { - aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, nil) // TODO will need types for this. + aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, + s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) } callArgs = append(callArgs, s.mem()) @@ -4896,7 +4897,8 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // Call runtime.deferprocStack with pointer to _defer record. ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(base.Ctxt.FixedFrameSize())}) - aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, ACArgs, ACResults, nil) + aux := ssa.StaticAuxCall(ir.Syms.DeferprocStack, ACArgs, ACResults, + s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) callArgs = append(callArgs, addr, s.mem()) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) call.AddArgs(callArgs...) @@ -4956,10 +4958,12 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // call target switch { case k == callDefer: - aux := ssa.StaticAuxCall(ir.Syms.Deferproc, ACArgs, ACResults, nil) // TODO paramResultInfo for DeferProc + aux := ssa.StaticAuxCall(ir.Syms.Deferproc, ACArgs, ACResults, + s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) // TODO paramResultInfo for DeferProc call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) case k == callGo: - aux := ssa.StaticAuxCall(ir.Syms.Newproc, ACArgs, ACResults, nil) + aux := ssa.StaticAuxCall(ir.Syms.Newproc, ACArgs, ACResults, + s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) // TODO paramResultInfo for NewProc case closure != nil: // rawLoad because loading the code pointer from a @@ -5434,6 +5438,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args . var ACArgs []ssa.Param var ACResults []ssa.Param var callArgs []*ssa.Value + var callArgTypes []*types.Type for _, arg := range args { t := arg.Type @@ -5441,6 +5446,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args . size := t.Size() ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)}) callArgs = append(callArgs, arg) + callArgTypes = append(callArgTypes, t) off += size } off = types.Rnd(off, int64(types.RegSize)) @@ -5455,7 +5461,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args . // Issue call var call *ssa.Value - aux := ssa.StaticAuxCall(fn, ACArgs, ACResults, nil) // WILL NEED A TYPE FOR THIS.) + aux := ssa.StaticAuxCall(fn, ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, callArgTypes, results)) callArgs = append(callArgs, s.mem()) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) call.AddArgs(callArgs...) @@ -6520,7 +6526,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) { // input args need no code case ssa.OpSP, ssa.OpSB: // nothing to do - case ssa.OpSelect0, ssa.OpSelect1: + case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN: // nothing to do case ssa.OpGetG: // nothing to do when there's a g register, diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index b6374e49a5..9fb6d68994 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -581,12 +581,19 @@ func NewTuple(t1, t2 *Type) *Type { return t } -func NewResults(types []*Type) *Type { +func newResults(types []*Type) *Type { t := New(TRESULTS) t.Extra.(*Results).Types = types return t } +func NewResults(types []*Type) *Type { + if len(types) == 1 && types[0] == TypeMem { + return TypeResultMem + } + return newResults(types) +} + func newSSA(name string) *Type { t := New(TSSA) t.Extra = name @@ -1407,6 +1414,9 @@ func (t *Type) PtrTo() *Type { } func (t *Type) NumFields() int { + if t.kind == TRESULTS { + return len(t.Extra.(*Results).Types) + } return t.Fields().Len() } func (t *Type) FieldType(i int) *Type { @@ -1597,11 +1607,12 @@ func FakeRecvType() *Type { var ( // TSSA types. HasPointers assumes these are pointer-free. - TypeInvalid = newSSA("invalid") - TypeMem = newSSA("mem") - TypeFlags = newSSA("flags") - TypeVoid = newSSA("void") - TypeInt128 = newSSA("int128") + TypeInvalid = newSSA("invalid") + TypeMem = newSSA("mem") + TypeFlags = newSSA("flags") + TypeVoid = newSSA("void") + TypeInt128 = newSSA("int128") + TypeResultMem = newResults([]*Type{TypeMem}) ) // NewNamed returns a new named type for the given type name. -- GitLab From 23943a67378040340d835734a55dee7cb639e586 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 26 Feb 2021 10:17:09 +0700 Subject: [PATCH 0119/1298] cmd/compile: fix mishandling of unsafe-uintptr arguments with call method in go/defer In CL 253457, we did the same fix for direct function calls. But for method calls, the receiver argument also need to be passed through the wrapper function, which we are not doing so the compiler crashes with the code in #44415. It will be nicer if we can rewrite OCALLMETHOD to normal OCALLFUNC, but that will be for future CL. The passing receiver argument to wrapper function is easier for backporting to go1.16 branch. Fixes #44415 Change-Id: I03607a64429042c6066ce673931db9769deb3124 Reviewed-on: https://go-review.googlesource.com/c/go/+/296490 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/walk/stmt.go | 21 ++++++++++++++---- test/fixedbugs/issue24491a.go | 31 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go index 46a621c2ba..0c851506cb 100644 --- a/src/cmd/compile/internal/walk/stmt.go +++ b/src/cmd/compile/internal/walk/stmt.go @@ -253,15 +253,22 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { } } + wrapArgs := n.Args + // If there's a receiver argument, it needs to be passed through the wrapper too. + if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER { + recv := n.X.(*ir.SelectorExpr).X + wrapArgs = append([]ir.Node{recv}, wrapArgs...) + } + // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion. - origArgs := make([]ir.Node, len(n.Args)) + origArgs := make([]ir.Node, len(wrapArgs)) var funcArgs []*ir.Field - for i, arg := range n.Args { + for i, arg := range wrapArgs { s := typecheck.LookupNum("a", i) if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() { origArgs[i] = arg arg = arg.(*ir.ConvExpr).X - n.Args[i] = arg + wrapArgs[i] = arg } funcArgs = append(funcArgs, ir.NewField(base.Pos, s, nil, arg.Type())) } @@ -278,6 +285,12 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { } args[i] = ir.NewConvExpr(base.Pos, origArg.Op(), origArg.Type(), args[i]) } + if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER { + // Move wrapped receiver argument back to its appropriate place. + recv := typecheck.Expr(args[0]) + n.X.(*ir.SelectorExpr).X = recv + args = args[1:] + } call := ir.NewCallExpr(base.Pos, n.Op(), n.X, args) if !isBuiltinCall { call.SetOp(ir.OCALL) @@ -291,6 +304,6 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { typecheck.Stmts(fn.Body) typecheck.Target.Decls = append(typecheck.Target.Decls, fn) - call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args) + call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, wrapArgs) return walkExpr(typecheck.Stmt(call), init) } diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go index 8accf8c0a3..d30b65b233 100644 --- a/test/fixedbugs/issue24491a.go +++ b/test/fixedbugs/issue24491a.go @@ -48,6 +48,14 @@ func f() int { return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) } +type S struct{} + +//go:noinline +//go:uintptrescapes +func (S) test(s string, p, q uintptr, rest ...uintptr) int { + return test(s, p, q, rest...) +} + func main() { test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) <-done @@ -60,6 +68,29 @@ func main() { }() <-done + func() { + for { + defer test("defer in for loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) + break + } + }() + + <-done + func() { + s := &S{} + defer s.test("method call", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) + }() + <-done + + func() { + s := &S{} + for { + defer s.test("defer method loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) + break + } + }() + <-done + f() <-done } -- GitLab From a655208c9ecd2fee4de6deff35a863b1c28a091c Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 25 Feb 2021 20:01:53 -0500 Subject: [PATCH 0120/1298] cmd/link: handle types as converted to interface when dynlink When using plugins, a type (whose value) may be pass to a plugin and get converted to interface there, or vice versa. We need to treat the type as potentially converted to interface, and retain its methods. Should fix #44586. Change-Id: I80dd35e68baedaa852a317543ccd78d94628d13b Reviewed-on: https://go-review.googlesource.com/c/go/+/296709 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- misc/cgo/testplugin/plugin_test.go | 13 ++++---- misc/cgo/testplugin/testdata/method2/main.go | 32 +++++++++++++++++++ misc/cgo/testplugin/testdata/method2/p/p.go | 9 ++++++ .../cgo/testplugin/testdata/method2/plugin.go | 11 +++++++ src/cmd/link/internal/ld/deadcode.go | 7 ++++ 5 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 misc/cgo/testplugin/testdata/method2/main.go create mode 100644 misc/cgo/testplugin/testdata/method2/p/p.go create mode 100644 misc/cgo/testplugin/testdata/method2/plugin.go diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go index 9055dbda04..2d991012c8 100644 --- a/misc/cgo/testplugin/plugin_test.go +++ b/misc/cgo/testplugin/plugin_test.go @@ -201,12 +201,11 @@ func TestMethod(t *testing.T) { // Exported symbol's method must be live. goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go") goCmd(t, "build", "-o", "method.exe", "./method/main.go") + run(t, "./method.exe") +} - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - cmd := exec.CommandContext(ctx, "./method.exe") - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) - } +func TestMethod2(t *testing.T) { + goCmd(t, "build", "-buildmode=plugin", "-o", "method2.so", "./method2/plugin.go") + goCmd(t, "build", "-o", "method2.exe", "./method2/main.go") + run(t, "./method2.exe") } diff --git a/misc/cgo/testplugin/testdata/method2/main.go b/misc/cgo/testplugin/testdata/method2/main.go new file mode 100644 index 0000000000..6a87e7b6a0 --- /dev/null +++ b/misc/cgo/testplugin/testdata/method2/main.go @@ -0,0 +1,32 @@ +// Copyright 2021 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. + +// A type can be passed to a plugin and converted to interface +// there. So its methods need to be live. + +package main + +import ( + "plugin" + + "testplugin/method2/p" +) + +var t p.T + +type I interface { M() } + +func main() { + pl, err := plugin.Open("method2.so") + if err != nil { + panic(err) + } + + f, err := pl.Lookup("F") + if err != nil { + panic(err) + } + + f.(func(p.T) interface{})(t).(I).M() +} diff --git a/misc/cgo/testplugin/testdata/method2/p/p.go b/misc/cgo/testplugin/testdata/method2/p/p.go new file mode 100644 index 0000000000..acb526acec --- /dev/null +++ b/misc/cgo/testplugin/testdata/method2/p/p.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 p + +type T int + +func (T) M() { println("M") } diff --git a/misc/cgo/testplugin/testdata/method2/plugin.go b/misc/cgo/testplugin/testdata/method2/plugin.go new file mode 100644 index 0000000000..6198e7648e --- /dev/null +++ b/misc/cgo/testplugin/testdata/method2/plugin.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 "testplugin/method2/p" + +func main() {} + +func F(t p.T) interface{} { return t } diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 1874103b93..ebde41499e 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -24,6 +24,7 @@ type deadcodePass struct { ifaceMethod map[methodsig]bool // methods declared in reached interfaces markableMethods []methodref // methods of reached types reflectSeen bool // whether we have seen a reflect method call + dynlink bool methodsigstmp []methodsig // scratch buffer for decoding method signatures } @@ -34,6 +35,7 @@ func (d *deadcodePass) init() { if objabi.Fieldtrack_enabled != 0 { d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym()) } + d.dynlink = d.ctxt.DynlinkingGo() if d.ctxt.BuildMode == BuildModeShared { // Mark all symbols defined in this library as reachable when @@ -115,6 +117,11 @@ func (d *deadcodePass) flood() { var usedInIface bool if isgotype { + if d.dynlink { + // When dynaamic linking, a type may be passed across DSO + // boundary and get converted to interface at the other side. + d.ldr.SetAttrUsedInIface(symIdx, true) + } usedInIface = d.ldr.AttrUsedInIface(symIdx) } -- GitLab From f41460145ef6b75303e5f766a676274f456387d3 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 4 Feb 2021 00:11:12 +0100 Subject: [PATCH 0121/1298] cmd/link: recognize ARM64 PE files and relocations For now, this only add a single relocation type, which is sufficient for Windows resources. Later we'll see if we need more for cgo. In order to ensure these code paths are actually tested, this expands the rsrc tests to include all the architectures of PE objects that we need to be recognizing, and splits things more clearly between binutils and llvm objects, which have a slightly different layout, so that we test both. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. Change-Id: Ia1ee840265e9d12c0b12dd1c5d0810f8b300e557 Reviewed-on: https://go-review.googlesource.com/c/go/+/289429 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/lib.go | 6 ++- src/cmd/link/internal/loadpe/ldpe.go | 29 +++++++++++++ src/cmd/link/link_test.go | 38 +++++++++++++----- .../{testPErsrc => pe-binutils}/main.go | 7 ++-- .../link/testdata/pe-binutils/rsrc_386.syso | Bin 0 -> 228 bytes .../rsrc.syso => pe-binutils/rsrc_amd64.syso} | Bin .../{testPErsrc-complex => pe-llvm}/main.go | 4 +- src/cmd/link/testdata/pe-llvm/rsrc_386.syso | Bin 0 -> 352 bytes .../rsrc.syso => pe-llvm/rsrc_amd64.syso} | Bin 352 -> 352 bytes src/cmd/link/testdata/pe-llvm/rsrc_arm.syso | Bin 0 -> 352 bytes src/cmd/link/testdata/pe-llvm/rsrc_arm64.syso | Bin 0 -> 352 bytes 11 files changed, 67 insertions(+), 17 deletions(-) rename src/cmd/link/testdata/{testPErsrc => pe-binutils}/main.go (65%) create mode 100644 src/cmd/link/testdata/pe-binutils/rsrc_386.syso rename src/cmd/link/testdata/{testPErsrc/rsrc.syso => pe-binutils/rsrc_amd64.syso} (100%) rename src/cmd/link/testdata/{testPErsrc-complex => pe-llvm}/main.go (92%) create mode 100644 src/cmd/link/testdata/pe-llvm/rsrc_386.syso rename src/cmd/link/testdata/{testPErsrc-complex/rsrc.syso => pe-llvm/rsrc_amd64.syso} (81%) create mode 100644 src/cmd/link/testdata/pe-llvm/rsrc_arm.syso create mode 100644 src/cmd/link/testdata/pe-llvm/rsrc_arm64.syso diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 28713456c4..517b0f6930 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1827,7 +1827,11 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file) } - if /* x86 */ c1 == 0x4c && c2 == 0x01 || /* x86_64 */ c1 == 0x64 && c2 == 0x86 || /* armv7 */ c1 == 0xc4 && c2 == 0x01 { + switch c1<<8 | c2 { + case 0x4c01, // 386 + 0x6486, // amd64 + 0xc401, // arm + 0x64aa: // arm64 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn) if err != nil { diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go index a5c025de8f..f474dfb276 100644 --- a/src/cmd/link/internal/loadpe/ldpe.go +++ b/src/cmd/link/internal/loadpe/ldpe.go @@ -115,6 +115,24 @@ const ( IMAGE_REL_THUMB_BRANCH24 = 0x0014 IMAGE_REL_THUMB_BLX23 = 0x0015 IMAGE_REL_ARM_PAIR = 0x0016 + IMAGE_REL_ARM64_ABSOLUTE = 0x0000 + IMAGE_REL_ARM64_ADDR32 = 0x0001 + IMAGE_REL_ARM64_ADDR32NB = 0x0002 + IMAGE_REL_ARM64_BRANCH26 = 0x0003 + IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004 + IMAGE_REL_ARM64_REL21 = 0x0005 + IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006 + IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007 + IMAGE_REL_ARM64_SECREL = 0x0008 + IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009 + IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A + IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B + IMAGE_REL_ARM64_TOKEN = 0x000C + IMAGE_REL_ARM64_SECTION = 0x000D + IMAGE_REL_ARM64_ADDR64 = 0x000E + IMAGE_REL_ARM64_BRANCH19 = 0x000F + IMAGE_REL_ARM64_BRANCH14 = 0x0010 + IMAGE_REL_ARM64_REL32 = 0x0011 ) // TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe. @@ -319,6 +337,17 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read case IMAGE_REL_ARM_BRANCH24: rType = objabi.R_CALLARM + rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:]))) + } + + case sys.ARM64: + switch r.Type { + default: + return nil, nil, fmt.Errorf("%s: %v: unknown ARM64 relocation type %v", pn, sectsyms[rsect], r.Type) + + case IMAGE_REL_ARM64_ADDR32, IMAGE_REL_ARM64_ADDR32NB: + rType = objabi.R_ADDR + rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:]))) } } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 08ddd00a0c..9c69ccca43 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -753,23 +753,24 @@ func TestIndexMismatch(t *testing.T) { } } -func TestPErsrc(t *testing.T) { +func TestPErsrcBinutils(t *testing.T) { // Test that PE rsrc section is handled correctly (issue 39658). testenv.MustHaveGoBuild(t) - if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" { - t.Skipf("this is a windows/amd64-only test") + if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" { + // This test is limited to amd64 and 386, because binutils is limited as such + t.Skipf("this is only for windows/amd64 and windows/386") } t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestPErsrc") + tmpdir, err := ioutil.TempDir("", "TestPErsrcBinutils") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) - pkgdir := filepath.Join("testdata", "testPErsrc") + pkgdir := filepath.Join("testdata", "pe-binutils") exe := filepath.Join(tmpdir, "a.exe") cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe) cmd.Dir = pkgdir @@ -787,19 +788,36 @@ func TestPErsrc(t *testing.T) { if !bytes.Contains(b, []byte("Hello Gophers!")) { t.Fatalf("binary does not contain expected content") } +} + +func TestPErsrcLLVM(t *testing.T) { + // Test that PE rsrc section is handled correctly (issue 39658). + testenv.MustHaveGoBuild(t) + + if runtime.GOOS != "windows" { + t.Skipf("this is a windows-only test") + } + + t.Parallel() + + tmpdir, err := ioutil.TempDir("", "TestPErsrcLLVM") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) - pkgdir = filepath.Join("testdata", "testPErsrc-complex") - exe = filepath.Join(tmpdir, "a.exe") - cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe) + pkgdir := filepath.Join("testdata", "pe-llvm") + exe := filepath.Join(tmpdir, "a.exe") + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe) cmd.Dir = pkgdir // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment - out, err = cmd.CombinedOutput() + out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("building failed: %v, output:\n%s", err, out) } // Check that the binary contains the rsrc data - b, err = ioutil.ReadFile(exe) + b, err := ioutil.ReadFile(exe) if err != nil { t.Fatalf("reading output failed: %v", err) } diff --git a/src/cmd/link/testdata/testPErsrc/main.go b/src/cmd/link/testdata/pe-binutils/main.go similarity index 65% rename from src/cmd/link/testdata/testPErsrc/main.go rename to src/cmd/link/testdata/pe-binutils/main.go index 5eb66fb9cc..14ea6f9e0f 100644 --- a/src/cmd/link/testdata/testPErsrc/main.go +++ b/src/cmd/link/testdata/pe-binutils/main.go @@ -4,10 +4,9 @@ // Test that a PE rsrc section is handled correctly (issue 39658). // -// rsrc.syso is created with: -// windres -i a.rc -o rsrc.syso -O coff -// on windows-amd64-2016 builder, where a.rc is a text file with -// the following content: +// rsrc.syso is created using binutils with: +// {x86_64,i686}-w64-mingw32-windres -i a.rc -o rsrc_$GOARCH.syso -O coff +// where a.rc is a text file with the following content: // // resname RCDATA { // "Hello Gophers!\0", diff --git a/src/cmd/link/testdata/pe-binutils/rsrc_386.syso b/src/cmd/link/testdata/pe-binutils/rsrc_386.syso new file mode 100644 index 0000000000000000000000000000000000000000..b4abc58abee609976b890aa7dafe197431d7e011 GIT binary patch literal 228 zcmeZaWMlw=a|{d&5EcugUQuyTGDr}LI~W)kY#10AjzIY!bq)*$2cTRi#mKU&D782*F*j8q$l1j)#8DwpuP7O0 zErUZ^YGR3=fq@_c1H=FS3=GT+P+x$33vvZBBgnrX7RU|=hN=Pkl!<|XfteBHSBM;p QR0%Qw0}vmq2E58x&QzG diff --git a/src/cmd/link/testdata/pe-llvm/rsrc_arm.syso b/src/cmd/link/testdata/pe-llvm/rsrc_arm.syso new file mode 100644 index 0000000000000000000000000000000000000000..c93a1e9ba0ffa390e122f211ca55ace3355ce27b GIT binary patch literal 352 zcmX@Y$iy&xqFTZS1_lN;1~6dMD=IEZRxvOH^B5QyG8h;bQWzK*&Oiki85kHG7#JL& z>WrYm3=#|s3^!mLC=F5vWkM-N1}+8$klF^Q0GI-q8NtBNV8FnDBF@0T$iT_Mz~BK^ z#lRo}r9l)sLlA>2LokCMgCm14gDY4KD+2=q69WT7QEG8sVs5HJkh6WrYm3=#|s3^!mLC=F5vWkM-N1}+8$klF^Q0GI-q8NtBNV8FnDBF@0T$iT_Mz~BK^ z#lRo}r9l)sLlA>2LokCMgCm14gDY4KD+2=q69WT7QEG8sVs5HJkh6 Date: Sun, 31 Jan 2021 17:37:20 +0100 Subject: [PATCH 0122/1298] syscall: add support for proc thread attribute lists This will allow us to pass additional attributes when starting processes. Updates #44011. Change-Id: I4af365c5544a6d421830f247593ec970200e5e03 Reviewed-on: https://go-review.googlesource.com/c/go/+/288296 Trust: Jason A. Donenfeld Trust: Alex Brainman Reviewed-by: Alex Brainman --- src/syscall/syscall_windows.go | 23 +++++++++++++++++++++++ src/syscall/types_windows.go | 16 ++++++++++++++++ src/syscall/zsyscall_windows.go | 24 ++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index ee5311b176..cc8dc487d3 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -284,6 +284,9 @@ func NewCallbackCDecl(fn interface{}) uintptr { // This function returns 1 byte BOOLEAN rather than the 4 byte BOOL. //sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW //sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW +//sys initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList +//sys deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) = DeleteProcThreadAttributeList +//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value uintptr, size uintptr, prevvalue uintptr, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute // syscall interface implementation for other packages @@ -1240,3 +1243,23 @@ func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overla func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) error { return postQueuedCompletionStatus(cphandle, qty, uintptr(key), overlapped) } + +// newProcThreadAttributeList allocates new PROC_THREAD_ATTRIBUTE_LIST, with +// the requested maximum number of attributes, which must be cleaned up by +// deleteProcThreadAttributeList. +func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LIST, error) { + var size uintptr + err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) + if err != ERROR_INSUFFICIENT_BUFFER { + if err == nil { + return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList") + } + return nil, err + } + al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]byte, size)[0])) + err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size) + if err != nil { + return nil, err + } + return al, nil +} diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index 5fef5c9477..384b5b4f2c 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -490,6 +490,22 @@ type StartupInfo struct { StdErr Handle } +type _PROC_THREAD_ATTRIBUTE_LIST struct { + _ [1]byte +} + +const ( + _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000 + _PROC_THREAD_ATTRIBUTE_HANDLE_LIST = 0x00020002 +) + +type _STARTUPINFOEXW struct { + StartupInfo + ProcThreadAttributeList *_PROC_THREAD_ATTRIBUTE_LIST +} + +const _EXTENDED_STARTUPINFO_PRESENT = 0x00080000 + type ProcessInformation struct { Process Handle Thread Handle diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index b1480ba7df..b08e6ac5c2 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -93,6 +93,7 @@ var ( procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") procDeleteFileW = modkernel32.NewProc("DeleteFileW") + procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") procExitProcess = modkernel32.NewProc("ExitProcess") @@ -131,6 +132,7 @@ var ( procGetTempPathW = modkernel32.NewProc("GetTempPathW") procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") procGetVersion = modkernel32.NewProc("GetVersion") + procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList") procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") procLocalFree = modkernel32.NewProc("LocalFree") procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") @@ -153,6 +155,7 @@ var ( procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") procTerminateProcess = modkernel32.NewProc("TerminateProcess") procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile") + procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute") procVirtualLock = modkernel32.NewProc("VirtualLock") procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") @@ -569,6 +572,11 @@ func DeleteFile(path *uint16) (err error) { return } +func deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) { + Syscall(procDeleteProcThreadAttributeList.Addr(), 1, uintptr(unsafe.Pointer(attrlist)), 0, 0) + return +} + func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) { r1, _, e1 := Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0) if r1 == 0 { @@ -897,6 +905,14 @@ func GetVersion() (ver uint32, err error) { return } +func initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) { + r1, _, e1 := Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(attrlist)), uintptr(attrcount), uintptr(flags), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func LoadLibrary(libname string) (handle Handle, err error) { var _p0 *uint16 _p0, err = UTF16PtrFromString(libname) @@ -1099,6 +1115,14 @@ func UnmapViewOfFile(addr uintptr) (err error) { return } +func updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value uintptr, size uintptr, prevvalue uintptr, returnedsize *uintptr) (err error) { + r1, _, e1 := Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func VirtualLock(addr uintptr, length uintptr) (err error) { r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0) if r1 == 0 { -- GitLab From 2d760816ff30bea82f54682f3049cfb6c6027da7 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 31 Jan 2021 17:54:27 +0100 Subject: [PATCH 0123/1298] syscall: restrict inherited handles on Windows Windows does not have CLOEXEC, but rather handles are marked explicitly for being inherited by new processes. This can cause problems when different Windows functions create new processes from different threads. syscall.StartProcess has traditionally used a mutex to prevent races with itself, but this doesn't handle races with other win32 functions. Fortunately there's a solution: PROC_THREAD_ATTRIBUTE_HANDLE_LIST allows us to pass the entire list of handles that we want to be inherited. This lets us get rid of the mutex and also makes process creation safe across the Go runtime, no matter the context. Updates #44011. Change-Id: Ia3424cd2ec64868849cbd6cbb5b0d765224bf4ab Reviewed-on: https://go-review.googlesource.com/c/go/+/288297 Trust: Jason A. Donenfeld Trust: Alex Brainman Reviewed-by: Alex Brainman --- src/syscall/exec_windows.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 46cbd7567d..ff9f7a3913 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -310,12 +310,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle } } - // Acquire the fork lock so that no other threads - // create new fds that are not yet close-on-exec - // before we fork. - ForkLock.Lock() - defer ForkLock.Unlock() - p, _ := GetCurrentProcess() fd := make([]Handle, len(attr.Files)) for i := range attr.Files { @@ -327,7 +321,12 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle defer CloseHandle(Handle(fd[i])) } } - si := new(StartupInfo) + si := new(_STARTUPINFOEXW) + si.ProcThreadAttributeList, err = newProcThreadAttributeList(1) + if err != nil { + return 0, 0, err + } + defer deleteProcThreadAttributeList(si.ProcThreadAttributeList) si.Cb = uint32(unsafe.Sizeof(*si)) si.Flags = STARTF_USESTDHANDLES if sys.HideWindow { @@ -338,13 +337,19 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle si.StdOutput = fd[1] si.StdErr = fd[2] + // Do not accidentally inherit more than these handles. + err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, uintptr(unsafe.Pointer(&fd[0])), uintptr(len(fd))*unsafe.Sizeof(fd[0]), 0, nil) + if err != nil { + return 0, 0, err + } + pi := new(ProcessInformation) - flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT + flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT if sys.Token != 0 { - err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi) + err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } else { - err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi) + err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } if err != nil { return 0, 0, err -- GitLab From 3146166baa8c420dfe20619e4aa9978b87927268 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 31 Jan 2021 18:07:43 +0100 Subject: [PATCH 0124/1298] syscall: introduce SysProcAttr.AdditionalInheritedHandles on Windows This allows users to specify handles that they explicitly want to be inherited by the new process. These handles must already be marked as inheritable. Updates #44011. Updates #21085. Change-Id: Ib18322e7dc2909e68c4209e80385492804fa15d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/288298 Trust: Jason A. Donenfeld Reviewed-by: Alex Brainman --- src/syscall/exec_windows.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index ff9f7a3913..0ddc240a56 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -235,13 +235,14 @@ type ProcAttr struct { } type SysProcAttr struct { - HideWindow bool - CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess - CreationFlags uint32 - Token Token // if set, runs new process in the security context represented by the token - ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process - ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process - NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process + HideWindow bool + CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess + CreationFlags uint32 + Token Token // if set, runs new process in the security context represented by the token + ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process + ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process + NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process + AdditionalInheritedHandles []Handle // a list of additional handles, already marked as inheritable, that will be inherited by the new process } var zeroProcAttr ProcAttr @@ -337,6 +338,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle si.StdOutput = fd[1] si.StdErr = fd[2] + fd = append(fd, sys.AdditionalInheritedHandles...) // Do not accidentally inherit more than these handles. err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, uintptr(unsafe.Pointer(&fd[0])), uintptr(len(fd))*unsafe.Sizeof(fd[0]), 0, nil) if err != nil { -- GitLab From 19f96e73bf655764b57424cc9e00657f364ffb89 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 31 Jan 2021 18:14:56 +0100 Subject: [PATCH 0125/1298] syscall: introduce SysProcAttr.ParentProcess on Windows This allows users to specify which process should be used as the parent process when creating a new process. Note that this doesn't just trivially pass the handle onward to PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, because inherited handles must be valid in the parent process, so if we're changing the destination process, then we must also change the origin of the parent handles. And, the StartProcess function must clean up these handles successfully when exiting, regardless of where the duplication happened. So, we take care in this commit to use DuplicateHandle for both duplicating and for closing the inherited handles. The test was taken originally from CL 288272 and adjusted for use here. Fixes #44011. Change-Id: Ib3b132028dcab1aded3dc0e65126c8abebfa35eb Reviewed-on: https://go-review.googlesource.com/c/go/+/288300 Trust: Jason A. Donenfeld Trust: Alex Brainman Reviewed-by: Alex Brainman --- src/syscall/exec_windows.go | 17 ++++++-- src/syscall/exec_windows_test.go | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 0ddc240a56..7b73cf1f6f 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -243,6 +243,7 @@ type SysProcAttr struct { ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process AdditionalInheritedHandles []Handle // a list of additional handles, already marked as inheritable, that will be inherited by the new process + ParentProcess Handle // if non-zero, the new process regards the process given by this handle as its parent process, and AdditionalInheritedHandles, if set, should exist in this parent process } var zeroProcAttr ProcAttr @@ -312,18 +313,22 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle } p, _ := GetCurrentProcess() + parentProcess := p + if sys.ParentProcess != 0 { + parentProcess = sys.ParentProcess + } fd := make([]Handle, len(attr.Files)) for i := range attr.Files { if attr.Files[i] > 0 { - err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) + err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) if err != nil { return 0, 0, err } - defer CloseHandle(Handle(fd[i])) + defer DuplicateHandle(parentProcess, fd[i], 0, nil, 0, false, DUPLICATE_CLOSE_SOURCE) } } si := new(_STARTUPINFOEXW) - si.ProcThreadAttributeList, err = newProcThreadAttributeList(1) + si.ProcThreadAttributeList, err = newProcThreadAttributeList(2) if err != nil { return 0, 0, err } @@ -334,6 +339,12 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle si.Flags |= STARTF_USESHOWWINDOW si.ShowWindow = SW_HIDE } + if sys.ParentProcess != 0 { + err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, uintptr(unsafe.Pointer(&sys.ParentProcess)), unsafe.Sizeof(sys.ParentProcess), 0, nil) + if err != nil { + return 0, 0, err + } + } si.StdInput = fd[0] si.StdOutput = fd[1] si.StdErr = fd[2] diff --git a/src/syscall/exec_windows_test.go b/src/syscall/exec_windows_test.go index eda1d36877..8a1c2ceaae 100644 --- a/src/syscall/exec_windows_test.go +++ b/src/syscall/exec_windows_test.go @@ -5,8 +5,14 @@ package syscall_test import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "syscall" "testing" + "time" ) func TestEscapeArg(t *testing.T) { @@ -41,3 +47,70 @@ func TestEscapeArg(t *testing.T) { } } } + +func TestChangingProcessParent(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") == "parent" { + // in parent process + + // Parent does nothign. It is just used as a parent of a child process. + time.Sleep(time.Minute) + os.Exit(0) + } + + if os.Getenv("GO_WANT_HELPER_PROCESS") == "child" { + // in child process + dumpPath := os.Getenv("GO_WANT_HELPER_PROCESS_FILE") + if dumpPath == "" { + fmt.Fprintf(os.Stderr, "Dump file path cannot be blank.") + os.Exit(1) + } + err := os.WriteFile(dumpPath, []byte(fmt.Sprintf("%d", os.Getppid())), 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "Error writing dump file: %v", err) + os.Exit(2) + } + os.Exit(0) + } + + // run parent process + + parent := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent") + parent.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=parent") + err := parent.Start() + if err != nil { + t.Fatal(err) + } + defer func() { + parent.Process.Kill() + parent.Wait() + }() + + // run child process + + const _PROCESS_CREATE_PROCESS = 0x0080 + const _PROCESS_DUP_HANDLE = 0x0040 + childDumpPath := filepath.Join(t.TempDir(), "ppid.txt") + ph, err := syscall.OpenProcess(_PROCESS_CREATE_PROCESS|_PROCESS_DUP_HANDLE|syscall.PROCESS_QUERY_INFORMATION, + false, uint32(parent.Process.Pid)) + if err != nil { + t.Fatal(err) + } + defer syscall.CloseHandle(ph) + + child := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent") + child.Env = append(os.Environ(), + "GO_WANT_HELPER_PROCESS=child", + "GO_WANT_HELPER_PROCESS_FILE="+childDumpPath) + child.SysProcAttr = &syscall.SysProcAttr{ParentProcess: ph} + childOutput, err := child.CombinedOutput() + if err != nil { + t.Errorf("child failed: %v: %v", err, string(childOutput)) + } + childOutput, err = ioutil.ReadFile(childDumpPath) + if err != nil { + t.Fatalf("reading child ouput failed: %v", err) + } + if got, want := string(childOutput), fmt.Sprintf("%d", parent.Process.Pid); got != want { + t.Fatalf("child output: want %q, got %q", want, got) + } +} -- GitLab From d8e33d558e2c5fcd7f9092790780e68adbac0f1b Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Sun, 21 Feb 2021 10:54:38 -0800 Subject: [PATCH 0126/1298] cmd/compile: deal with closures in generic functions and instantiated function values - Deal with closures in generic functions by fixing the stenciling code - Deal with instantiated function values (instantiated generic functions that are not immediately called) during stenciling. This requires changing the OFUNCINST node to an ONAME node for the appropriately instantiated function. We do this in a second pass, since this is uncommon, but requires editing the tree at multiple levels. - Check global assignments (as well as functions) for generic function instantiations. - Fix a bug in (*subst).typ where a generic type in a generic function may definitely not use all the type args of the function, so we need to translate the rparams of the type based on the tparams/targs of the function. - Added new test combine.go that tests out closures in generic functions and instantiated function values. - Added one new variant to the settable test. - Enabling inlining functions with closures for -G=3. (For now, set Ntype on closures in -G=3 mode to keep compatibility with later parts of compiler, and allow inlining of functions with closures.) Change-Id: Iea63d5704c322e42e2f750a83adc8b44f911d4ec Reviewed-on: https://go-review.googlesource.com/c/go/+/296269 Reviewed-by: Robert Griesemer Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales --- src/cmd/compile/internal/inline/inl.go | 2 +- src/cmd/compile/internal/noder/expr.go | 11 +- src/cmd/compile/internal/noder/stencil.go | 182 +++++++++++++++++----- test/typeparam/combine.go | 65 ++++++++ test/typeparam/settable.go | 27 +++- 5 files changed, 236 insertions(+), 51 deletions(-) create mode 100644 test/typeparam/combine.go diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index e961b10844..1d049298d7 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -354,7 +354,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool { return true case ir.OCLOSURE: - if base.Debug.InlFuncsWithClosures == 0 || base.Flag.G > 0 { + if base.Debug.InlFuncsWithClosures == 0 { v.reason = "not inlining functions with closures" return true } diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index b166d34ead..3fded144dc 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -325,19 +325,22 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { return typecheck.Expr(ir.NewCompLitExpr(g.pos(lit), ir.OCOMPLIT, ir.TypeNode(g.typ(typ)), exprs)) } -func (g *irgen) funcLit(typ types2.Type, expr *syntax.FuncLit) ir.Node { +func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { fn := ir.NewFunc(g.pos(expr)) fn.SetIsHiddenClosure(ir.CurFunc != nil) fn.Nname = ir.NewNameAt(g.pos(expr), typecheck.ClosureName(ir.CurFunc)) ir.MarkFunc(fn.Nname) - fn.Nname.SetType(g.typ(typ)) + typ := g.typ(typ2) fn.Nname.Func = fn fn.Nname.Defn = fn + // Set Ntype for now to be compatible with later parts of compile, remove later. + fn.Nname.Ntype = ir.TypeNode(typ) + typed(typ, fn.Nname) + fn.SetTypecheck(1) fn.OClosure = ir.NewClosureExpr(g.pos(expr), fn) - fn.OClosure.SetType(fn.Nname.Type()) - fn.OClosure.SetTypecheck(1) + typed(typ, fn.OClosure) g.funcBody(fn, nil, expr.Type, expr.Body) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 69461a8190..fb1bbfedc8 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -27,19 +27,37 @@ func (g *irgen) stencil() { // functions calling other generic functions. for i := 0; i < len(g.target.Decls); i++ { decl := g.target.Decls[i] - if decl.Op() != ir.ODCLFUNC || decl.Type().NumTParams() > 0 { - // Skip any non-function declarations and skip generic functions + + // Look for function instantiations in bodies of non-generic + // functions or in global assignments (ignore global type and + // constant declarations). + switch decl.Op() { + case ir.ODCLFUNC: + if decl.Type().HasTParam() { + // Skip any generic functions + continue + } + + case ir.OAS: + + case ir.OAS2: + + default: continue } - // For each non-generic function, search for any function calls using - // generic function instantiations. (We don't yet handle generic - // function instantiations that are not immediately called.) - // Then create the needed instantiated function if it hasn't been - // created yet, and change to calling that function directly. - f := decl.(*ir.Func) + // For all non-generic code, search for any function calls using + // generic function instantiations. Then create the needed + // instantiated function if it hasn't been created yet, and change + // to calling that function directly. modified := false - ir.VisitList(f.Body, func(n ir.Node) { + foundFuncInst := false + ir.Visit(decl, func(n ir.Node) { + if n.Op() == ir.OFUNCINST { + // We found a function instantiation that is not + // immediately called. + foundFuncInst = true + } if n.Op() != ir.OCALLFUNC || n.(*ir.CallExpr).X.Op() != ir.OFUNCINST { return } @@ -47,19 +65,7 @@ func (g *irgen) stencil() { // instantiation. call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) - sym := makeInstName(inst) - //fmt.Printf("Found generic func call in %v to %v\n", f, s) - st := g.target.Stencils[sym] - if st == nil { - // If instantiation doesn't exist yet, create it and add - // to the list of decls. - st = genericSubst(sym, inst) - g.target.Stencils[sym] = st - g.target.Decls = append(g.target.Decls, st) - if base.Flag.W > 1 { - ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) - } - } + st := g.getInstantiation(inst) // Replace the OFUNCINST with a direct reference to the // new stenciled function call.X = st.Nname @@ -76,6 +82,26 @@ func (g *irgen) stencil() { } modified = true }) + + // If we found an OFUNCINST without a corresponding call in the + // above decl, then traverse the nodes of decl again (with + // EditChildren rather than Visit), where we actually change the + // OFUNCINST node to an ONAME for the instantiated function. + // EditChildren is more expensive than Visit, so we only do this + // in the infrequent case of an OFUNCINSt without a corresponding + // call. + if foundFuncInst { + var edit func(ir.Node) ir.Node + edit = func(x ir.Node) ir.Node { + if x.Op() == ir.OFUNCINST { + st := g.getInstantiation(x.(*ir.InstExpr)) + return st.Nname + } + ir.EditChildren(x, edit) + return x + } + edit(decl) + } if base.Flag.W > 1 && modified { ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl) } @@ -83,18 +109,39 @@ func (g *irgen) stencil() { } -// makeInstName makes the unique name for a stenciled generic function, based on -// the name of the function and the types of the type params. -func makeInstName(inst *ir.InstExpr) *types.Sym { - b := bytes.NewBufferString("#") +// getInstantiation gets the instantiated function corresponding to inst. If the +// instantiated function is not already cached, then it calls genericStub to +// create the new instantiation. +func (g *irgen) getInstantiation(inst *ir.InstExpr) *ir.Func { + var sym *types.Sym if meth, ok := inst.X.(*ir.SelectorExpr); ok { // Write the name of the generic method, including receiver type - b.WriteString(meth.Selection.Nname.Sym().Name) + sym = makeInstName(meth.Selection.Nname.Sym(), inst.Targs) } else { - b.WriteString(inst.X.(*ir.Name).Name().Sym().Name) + sym = makeInstName(inst.X.(*ir.Name).Name().Sym(), inst.Targs) } + //fmt.Printf("Found generic func call in %v to %v\n", f, s) + st := g.target.Stencils[sym] + if st == nil { + // If instantiation doesn't exist yet, create it and add + // to the list of decls. + st = g.genericSubst(sym, inst) + g.target.Stencils[sym] = st + g.target.Decls = append(g.target.Decls, st) + if base.Flag.W > 1 { + ir.Dump(fmt.Sprintf("\nstenciled %v", st), st) + } + } + return st +} + +// makeInstName makes the unique name for a stenciled generic function, based on +// the name of the function and the targs. +func makeInstName(fnsym *types.Sym, targs []ir.Node) *types.Sym { + b := bytes.NewBufferString("#") + b.WriteString(fnsym.Name) b.WriteString("[") - for i, targ := range inst.Targs { + for i, targ := range targs { if i > 0 { b.WriteString(",") } @@ -107,6 +154,7 @@ func makeInstName(inst *ir.InstExpr) *types.Sym { // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { + g *irgen newf *ir.Func // Func node for the new stenciled function tparams []*types.Field targs []ir.Node @@ -121,7 +169,7 @@ type subster struct { // inst. For a method with a generic receiver, it returns an instantiated function // type where the receiver becomes the first parameter. Otherwise the instantiated // method would still need to be transformed by later compiler phases. -func genericSubst(name *types.Sym, inst *ir.InstExpr) *ir.Func { +func (g *irgen) genericSubst(name *types.Sym, inst *ir.InstExpr) *ir.Func { var nameNode *ir.Name var tparams []*types.Field if selExpr, ok := inst.X.(*ir.SelectorExpr); ok { @@ -148,6 +196,7 @@ func genericSubst(name *types.Sym, inst *ir.InstExpr) *ir.Func { name.Def = newf.Nname subst := &subster{ + g: g, newf: newf, tparams: tparams, targs: inst.Targs, @@ -198,6 +247,9 @@ func (subst *subster) node(n ir.Node) ir.Node { return v } m := ir.NewNameAt(name.Pos(), name.Sym()) + if name.IsClosureVar() { + m.SetIsClosureVar(true) + } t := x.Type() newt := subst.typ(t) m.SetType(newt) @@ -219,10 +271,12 @@ func (subst *subster) node(n ir.Node) ir.Node { // t can be nil only if this is a call that has no // return values, so allow that and otherwise give // an error. - if _, isCallExpr := m.(*ir.CallExpr); !isCallExpr { + _, isCallExpr := m.(*ir.CallExpr) + _, isStructKeyExpr := m.(*ir.StructKeyExpr) + if !isCallExpr && !isStructKeyExpr { base.Fatalf(fmt.Sprintf("Nil type for %v", x)) } - } else { + } else if x.Op() != ir.OCLOSURE { m.SetType(subst.typ(x.Type())) } } @@ -270,14 +324,27 @@ func (subst *subster) node(n ir.Node) ir.Node { if oldfn.ClosureCalled() { newfn.SetClosureCalled(true) } + newfn.SetIsHiddenClosure(true) m.(*ir.ClosureExpr).Func = newfn - newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym()) - newfn.Nname.SetType(oldfn.Nname.Type()) - newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype) + newsym := makeInstName(oldfn.Nname.Sym(), subst.targs) + newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym) + newfn.Nname.Func = newfn + newfn.Nname.Defn = newfn + ir.MarkFunc(newfn.Nname) + newfn.OClosure = m.(*ir.ClosureExpr) + + saveNewf := subst.newf + subst.newf = newfn + newfn.Dcl = subst.namelist(oldfn.Dcl) + newfn.ClosureVars = subst.namelist(oldfn.ClosureVars) newfn.Body = subst.list(oldfn.Body) - // Make shallow copy of the Dcl and ClosureVar slices - newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...) - newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...) + subst.newf = saveNewf + + // Set Ntype for now to be compatible with later parts of compiler + newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype) + typed(subst.typ(oldfn.Nname.Type()), newfn.Nname) + newfn.SetTypecheck(1) + subst.g.target.Decls = append(subst.g.target.Decls, newfn) } return m } @@ -285,6 +352,20 @@ func (subst *subster) node(n ir.Node) ir.Node { return edit(n) } +func (subst *subster) namelist(l []*ir.Name) []*ir.Name { + s := make([]*ir.Name, len(l)) + for i, n := range l { + s[i] = subst.node(n).(*ir.Name) + if n.Defn != nil { + s[i].Defn = subst.node(n.Defn) + } + if n.Outer != nil { + s[i].Outer = subst.node(n.Outer).(*ir.Name) + } + } + return s +} + func (subst *subster) list(l []ir.Node) []ir.Node { s := make([]ir.Node, len(l)) for i, n := range l { @@ -293,7 +374,9 @@ func (subst *subster) list(l []ir.Node) []ir.Node { return s } -// tstruct substitutes type params in a structure type +// tstruct substitutes type params in types of the fields of a structure type. For +// each field, if Nname is set, tstruct also translates the Nname using subst.vars, if +// Nname is in subst.vars. func (subst *subster) tstruct(t *types.Type) *types.Type { if t.NumFields() == 0 { return t @@ -301,7 +384,7 @@ func (subst *subster) tstruct(t *types.Type) *types.Type { var newfields []*types.Field for i, f := range t.Fields().Slice() { t2 := subst.typ(f.Type) - if t2 != f.Type && newfields == nil { + if (t2 != f.Type || f.Nname != nil) && newfields == nil { newfields = make([]*types.Field, t.NumFields()) for j := 0; j < i; j++ { newfields[j] = t.Field(j) @@ -309,6 +392,12 @@ func (subst *subster) tstruct(t *types.Type) *types.Type { } if newfields != nil { newfields[i] = types.NewField(f.Pos, f.Sym, t2) + if f.Nname != nil { + // f.Nname may not be in subst.vars[] if this is + // a function name or a function instantiation type + // that we are translating + newfields[i].Nname = subst.vars[f.Nname.(*ir.Name)] + } } } if newfields != nil { @@ -319,14 +408,14 @@ func (subst *subster) tstruct(t *types.Type) *types.Type { } // instTypeName creates a name for an instantiated type, based on the type args -func instTypeName(name string, targs []ir.Node) string { +func instTypeName(name string, targs []*types.Type) string { b := bytes.NewBufferString(name) b.WriteByte('[') for i, targ := range targs { if i > 0 { b.WriteByte(',') } - b.WriteString(targ.Type().String()) + b.WriteString(targ.String()) } b.WriteByte(']') return b.String() @@ -415,10 +504,17 @@ func (subst *subster) typ(t *types.Type) *types.Type { // Since we've substituted types, we also need to change // the defined name of the type, by removing the old types // (in brackets) from the name, and adding the new types. + + // Translate the type params for this type according to + // the tparam/targs mapping of the function. + neededTargs := make([]*types.Type, len(t.RParams)) + for i, rparam := range t.RParams { + neededTargs[i] = subst.typ(rparam) + } oldname := t.Sym().Name i := strings.Index(oldname, "[") oldname = oldname[:i] - sym := t.Sym().Pkg.Lookup(instTypeName(oldname, subst.targs)) + sym := t.Sym().Pkg.Lookup(instTypeName(oldname, neededTargs)) if sym.Def != nil { // We've already created this instantiated defined type. return sym.Def.Type() diff --git a/test/typeparam/combine.go b/test/typeparam/combine.go new file mode 100644 index 0000000000..d4a2988a7b --- /dev/null +++ b/test/typeparam/combine.go @@ -0,0 +1,65 @@ +// run -gcflags=-G=3 + +// Copyright 2021 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 ( + "fmt" +) + +type _Gen[A any] func() (A, bool) + +func combine[T1, T2, T any](g1 _Gen[T1], g2 _Gen[T2], join func(T1, T2) T) _Gen[T] { + return func() (T, bool) { + var t T + t1, ok := g1() + if !ok { + return t, false + } + t2, ok := g2() + if !ok { + return t, false + } + return join(t1, t2), true + } +} + +type _Pair[A, B any] struct { + A A + B B +} + +func _NewPair[A, B any](a A, b B) _Pair[A, B] { + return _Pair[A, B]{a, b} +} + +func _Combine2[A, B any](ga _Gen[A], gb _Gen[B]) _Gen[_Pair[A, B]] { + return combine(ga, gb, _NewPair[A, B]) +} + +func main() { + var g1 _Gen[int] = func() (int, bool) { return 3, true } + var g2 _Gen[string] = func() (string, bool) { return "x", false } + var g3 _Gen[string] = func() (string, bool) { return "y", true } + + gc := combine(g1, g2, _NewPair[int, string]) + if got, ok := gc(); ok { + panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) + } + gc2 := _Combine2(g1, g2) + if got, ok := gc2(); ok { + panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok)) + } + + gc3 := combine(g1, g3, _NewPair[int, string]) + if got, ok := gc3(); !ok || got.A != 3 || got.B != "y" { + panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) + } + gc4 := _Combine2(g1, g3) + if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" { + panic (fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok)) + } +} diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go index 3bd141f784..7532953a77 100644 --- a/test/typeparam/settable.go +++ b/test/typeparam/settable.go @@ -11,7 +11,24 @@ import ( "strconv" ) -func fromStrings3[T any](s []string, set func(*T, string)) []T { +type Setter[B any] interface { + Set(string) + type *B +} + +func fromStrings1[T any, PT Setter[T]](s []string) []T { + result := make([]T, len(s)) + for i, v := range s { + // The type of &result[i] is *T which is in the type list + // of Setter, so we can convert it to PT. + p := PT(&result[i]) + // PT has a Set method. + p.Set(v) + } + return result +} + +func fromStrings2[T any](s []string, set func(*T, string)) []T { results := make([]T, len(s)) for i, v := range s { set(&results[i], v) @@ -30,8 +47,12 @@ func (p *Settable) Set(s string) { } func main() { - s := fromStrings3([]string{"1"}, - func(p *Settable, s string) { p.Set(s) }) + s := fromStrings1[Settable, *Settable]([]string{"1"}) + if len(s) != 1 || s[0] != 1 { + panic(fmt.Sprintf("got %v, want %v", s, []int{1})) + } + + s = fromStrings2([]string{"1"}, func(p *Settable, s string) { p.Set(s) }) if len(s) != 1 || s[0] != 1 { panic(fmt.Sprintf("got %v, want %v", s, []int{1})) } -- GitLab From cda8ee095e487951eab5a53a097e2b8f400f237d Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 17 Feb 2021 19:14:03 +0000 Subject: [PATCH 0127/1298] reflect: fix register ABI spill space calculation Currently this does things the old way by computing the number of registers, but we're going to be using their ABI0 layout for the spill space for now. Change-Id: Ibcef1ee48fd834af7cbdaabe704bcabe066ed358 Reviewed-on: https://go-review.googlesource.com/c/go/+/293011 Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Michael Knyszek --- src/reflect/abi.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 88af212717..20f41d96b5 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -334,8 +334,7 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { // // TODO(mknyszek): Remove this when we no longer have // caller reserved spill space. - spillInt := uintptr(0) - spillFloat := uintptr(0) + spill := uintptr(0) // Compute gc program & stack bitmap for stack arguments stackPtrs := new(bitVector) @@ -351,21 +350,19 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { stackPtrs.append(0) } } else { - spillInt += ptrSize + spill += ptrSize } } for _, arg := range t.in() { - i, f := in.iregs, in.fregs stkStep := in.addArg(arg) if stkStep != nil { addTypeBits(stackPtrs, stkStep.stkOff, arg) } else { - i, f = in.iregs-i, in.fregs-f - spillInt += uintptr(i) * ptrSize - spillFloat += uintptr(f) * abi.EffectiveFloatRegSize + spill = align(spill, uintptr(arg.align)) + spill += arg.size } } - spill := align(spillInt+spillFloat, ptrSize) + spill = align(spill, ptrSize) // From the input parameters alone, we now know // the stackCallArgsSize and retOffset. -- GitLab From d9fd38e68ba00a51c2c7363150688d0e7687ef84 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 25 Feb 2021 10:01:56 -0800 Subject: [PATCH 0128/1298] time: correct unusual extension string cases This fixes two uncommon cases. First, the tzdata code permits timezone offsets up to 24 * 7, although the POSIX TZ parsing does not. The tzdata code uses this to specify a day of week in some cases. Second, we incorrectly rejected a negative time offset for when a time zone change comes into effect. Fixes #44385 Change-Id: I5f2efc1d385e9bfa974a0de3fa81e7a94b827602 Reviewed-on: https://go-review.googlesource.com/c/go/+/296392 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Tobias Klauser --- src/time/zoneinfo.go | 6 ++-- src/time/zoneinfo_test.go | 60 +++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go index c3662297c7..6db9443474 100644 --- a/src/time/zoneinfo.go +++ b/src/time/zoneinfo.go @@ -377,8 +377,10 @@ func tzsetOffset(s string) (offset int, rest string, ok bool) { neg = true } + // The tzdata code permits values up to 24 * 7 here, + // although POSIX does not. var hours int - hours, s, ok = tzsetNum(s, 0, 24) + hours, s, ok = tzsetNum(s, 0, 24*7) if !ok { return 0, "", false } @@ -487,7 +489,7 @@ func tzsetRule(s string) (rule, string, bool) { } offset, s, ok := tzsetOffset(s[1:]) - if !ok || offset < 0 { + if !ok { return rule{}, "", false } r.time = offset diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index 277b68f798..d043e1e9f1 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -183,22 +183,50 @@ func TestMalformedTZData(t *testing.T) { } } -func TestLoadLocationFromTZDataSlim(t *testing.T) { - // A 2020b slim tzdata for Europe/Berlin - tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#3<-02>,M3.5.0/-2,M10.5.0/-1\n", + wantName: "-03", + wantOffset: -10800, + }, + { + // 2021a slim tzdata for Asia/Gaza. + zoneName: "Asia/Gaza", + tzData: "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xffͬ\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xffϏ\x83\x00\xff\xff\xff\xffЩ\xa4\x00\xff\xff\xff\xffф}\x00\xff\xff\xff\xffҊ׀\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\v\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\v\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\u007f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xffﰳp\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\b|\x8b\xe0\x00\x00\x00\x00\b\xfd\xb0\xd0\x00\x00\x00\x00\t\xf6\xea`\x00\x00\x00\x00\n\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\"^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\v\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\a\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\n`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\u007f\x05\xe0\x00\x00\x00\x00A\\\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\\`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00Xդ\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[ӎ`\x00\x00\x00\x00\\\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\t\x00\x00*0\x01\r\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\nEET-2EEST,M3.4.4/48,M10.4.4/49\n", + wantName: "EET", + wantOffset: 7200, + }, +} - reference, err := time.LoadLocationFromTZData("Europe/Berlin", []byte(tzData)) - if err != nil { - t.Fatal(err) - } +func TestLoadLocationFromTZDataSlim(t *testing.T) { + for _, test := range slimTests { + reference, err := time.LoadLocationFromTZData(test.zoneName, []byte(test.tzData)) + if err != nil { + t.Fatal(err) + } - d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference) - tzName, tzOffset := d.Zone() - if want := "CET"; tzName != want { - t.Errorf("Zone name == %s, want %s", tzName, want) - } - if want := 3600; tzOffset != want { - t.Errorf("Zone offset == %d, want %d", tzOffset, want) + d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference) + tzName, tzOffset := d.Zone() + if tzName != test.wantName { + t.Errorf("Zone name == %s, want %s", tzName, test.wantName) + } + if tzOffset != test.wantOffset { + t.Errorf("Zone offset == %d, want %d", tzOffset, test.wantOffset) + } } } @@ -263,7 +291,8 @@ func TestTzsetOffset(t *testing.T) { {"+08", 8 * 60 * 60, "", true}, {"-01:02:03", -1*60*60 - 2*60 - 3, "", true}, {"01", 1 * 60 * 60, "", true}, - {"100", 0, "", false}, + {"100", 100 * 60 * 60, "", true}, + {"1000", 0, "", false}, {"8PDT", 8 * 60 * 60, "PDT", true}, } { off, out, ok := time.TzsetOffset(test.in) @@ -288,6 +317,7 @@ func TestTzsetRule(t *testing.T) { {"30/03:00:00", time.Rule{Kind: time.RuleDOY, Day: 30, Time: 3 * 60 * 60}, "", true}, {"M4.5.6/03:00:00", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: 3 * 60 * 60}, "", true}, {"M4.5.7/03:00:00", time.Rule{}, "", false}, + {"M4.5.6/-04", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: -4 * 60 * 60}, "", true}, } { r, out, ok := time.TzsetRule(test.in) if r != test.r || out != test.out || ok != test.ok { -- GitLab From 998fe70b683ed64d0bc67d9e0a35f8a7bcbe161d Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 26 Feb 2021 17:37:26 -0500 Subject: [PATCH 0129/1298] cmd/compile: fixed which-result confusion in presence of 0-width types A function returning multiple results, some of them zero-width, will have more than one result present at an offset. Be sure that offset AND type match. Includes test. Change-Id: I3eb1f56116d989b4e73f533fefabb1bf554c901b Reviewed-on: https://go-review.googlesource.com/c/go/+/297169 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/ssa/op.go | 9 ++++--- src/cmd/compile/internal/ssagen/ssa.go | 4 ++-- test/abi/f_ret_z_not.go | 33 ++++++++++++++++++++++++++ test/abi/f_ret_z_not.out | 1 + 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 test/abi/f_ret_z_not.go create mode 100644 test/abi/f_ret_z_not.out diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 6949bdca31..ece274b083 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -86,12 +86,15 @@ type AuxCall struct { abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information. } -// ResultForOffset returns the index of the result at a particular offset among the results +// ResultForOffsetAndType returns the index of a t-typed result at *A* particular offset among the results. +// An arbitrary number of zero-width-typed results may reside at the same offset with a single not-zero-width +// typed result, but the ones with the same type are all indistinguishable so it doesn't matter "which one" +// is obtained. // This does not include the mem result for the call opcode. -func (a *AuxCall) ResultForOffset(offset int64) int64 { +func (a *AuxCall) ResultForOffsetAndType(offset int64, t *types.Type) int64 { which := int64(-1) for i := int64(0); i < a.NResults(); i++ { // note aux NResults does not include mem result. - if a.OffsetOfResult(i) == offset { + if a.OffsetOfResult(i) == offset && a.TypeOfResult(i) == t { which = i break } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index ba00b9c7f6..865630dd3e 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -2909,7 +2909,7 @@ func (s *state) expr(n ir.Node) *ssa.Value { addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset) return s.rawLoad(n.Type(), addr) } - which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Offset) + which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffsetAndType(n.Offset, n.Type()) if which == -1 { // Do the old thing // TODO: Panic instead. addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset) @@ -5119,7 +5119,7 @@ func (s *state) addr(n ir.Node) *ssa.Value { if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall { return s.constOffPtrSP(t, n.Offset) } - which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Offset) + which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffsetAndType(n.Offset, n.Type()) if which == -1 { // Do the old thing // TODO: Panic instead. return s.constOffPtrSP(t, n.Offset) diff --git a/test/abi/f_ret_z_not.go b/test/abi/f_ret_z_not.go new file mode 100644 index 0000000000..b072aea75e --- /dev/null +++ b/test/abi/f_ret_z_not.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2021 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 "fmt" + +type Z struct { +} + +type NZ struct { + x, y int +} + +//go:noinline +func f(x,y int) (Z,NZ,Z) { + var z Z + return z,NZ{x,y},z +} + +//go:noinline +func g() (Z,NZ,Z) { + a,b,c := f(3,4) + return c,b,a +} + +func main() { + _,b,_ := g() + fmt.Println(b.x+b.y) +} diff --git a/test/abi/f_ret_z_not.out b/test/abi/f_ret_z_not.out new file mode 100644 index 0000000000..7f8f011eb7 --- /dev/null +++ b/test/abi/f_ret_z_not.out @@ -0,0 +1 @@ +7 -- GitLab From a429926159232f2e127d46698633ffce5896ae30 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 27 Feb 2021 09:41:19 -0800 Subject: [PATCH 0130/1298] cmd/compile: fix escape analysis of heap-allocated results One of escape analysis's responsibilities is to summarize whether/how each function parameter flows to the heap so we can correctly incorporate those flows into callers' escape analysis data flow graphs. As an optimization, we separately record when parameters flow to result parameters, so that we can more precisely analyze parameter flows based on how the results are used at the call site. However, if a named result parameter itself needs to be heap allocated, this optimization isn't safe and the parameter needs to be recorded as flowing to heap rather than flowing to result. Escape analysis used to get this correct because it conservatively rewalked the data-flow graph multiple times. So even though it would incorrectly record the result parameter flow, it would separately find a flow to the heap. However, CL 196811 (specifically, case 3) optimized the walking logic to reduce unnecessary rewalks causing us to stop finding the extra heap flow. This CL fixes the issue by correcting location.leakTo to be sensitive to sink.escapes and not record result-flows when the result parameter escapes to the heap. Fixes #44614. Change-Id: I48742ed35a6cab591094e2d23a439e205bd65c50 Reviewed-on: https://go-review.googlesource.com/c/go/+/297289 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/escape/escape.go | 7 ++++--- test/escape5.go | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 58cad73c76..213ef7832d 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -1625,9 +1625,10 @@ func containsClosure(f, c *ir.Func) bool { // leak records that parameter l leaks to sink. func (l *location) leakTo(sink *location, derefs int) { - // If sink is a result parameter and we can fit return bits - // into the escape analysis tag, then record a return leak. - if sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn { + // If sink is a result parameter that doesn't escape (#44614) + // and we can fit return bits into the escape analysis tag, + // then record as a result leak. + if !sink.escapes && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn { ri := sink.resultIndex - 1 if ri < numEscResults { // Leak to result parameter. diff --git a/test/escape5.go b/test/escape5.go index 2ed2023cd2..82be2c38e7 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -269,3 +269,14 @@ func f28369(n int) int { return 1 + f28369(n-1) } + +// Issue 44614: parameters that flow to a heap-allocated result +// parameter must be recorded as a heap-flow rather than a +// result-flow. + +// N.B., must match "leaking param: p", +// but *not* "leaking param: p to result r level=0". +func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r" + sink4 = &r + return p +} -- GitLab From 5ff7ec98b7727b3641df25200345b1aa50b6ff35 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 9 Feb 2021 18:09:47 -0500 Subject: [PATCH 0131/1298] cmd/compile: check frame offsets against abi this is in preparation for turning off calculation of frame offsets in types.CalcSize For #40724. Change-Id: I2c29fd289c014674076e5ec5170055dbca5ea64b Reviewed-on: https://go-review.googlesource.com/c/go/+/293392 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/abi/abiutils.go | 43 +++++++++++++-- src/cmd/compile/internal/gc/compile.go | 3 + src/cmd/compile/internal/ssa/op.go | 18 +++--- src/cmd/compile/internal/ssagen/ssa.go | 55 ++++++++++++------- .../compile/internal/test/abiutilsaux_test.go | 32 ----------- 5 files changed, 85 insertions(+), 66 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index b43d95e976..f5f3b25726 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -52,12 +52,12 @@ func (a *ABIParamResultInfo) OutRegistersUsed() int { return a.outRegistersUsed } -func (a *ABIParamResultInfo) InParam(i int) ABIParamAssignment { - return a.inparams[i] +func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment { + return &a.inparams[i] } -func (a *ABIParamResultInfo) OutParam(i int) ABIParamAssignment { - return a.outparams[i] +func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment { + return &a.outparams[i] } func (a *ABIParamResultInfo) SpillAreaOffset() int64 { @@ -111,6 +111,18 @@ func (a *ABIParamAssignment) SpillOffset() int32 { return a.offset } +// FrameOffset returns the location that a value would spill to, if any exists. +// For register-allocated inputs, that is their spill offset reserved for morestack +// (might as well use it, it is there); for stack-allocated inputs and outputs, +// that is their location on the stack. For register-allocated outputs, there is +// no defined spill area, so return -1. +func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 { + if len(a.Registers) == 0 || a.offset == -1 { + return int64(a.offset) + } + return int64(a.offset) + i.SpillAreaOffset() +} + // RegAmounts holds a specified number of integer/float registers. type RegAmounts struct { intRegs int @@ -265,9 +277,32 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + // Fill in the frame offsets for receiver, inputs, results + k := 0 + if t.NumRecvs() != 0 { + config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false) + k++ + } + for i, f := range ft.Params.FieldSlice() { + config.updateOffset(result, f, result.inparams[k+i], false) + } + for i, f := range ft.Results.FieldSlice() { + config.updateOffset(result, f, result.outparams[i], true) + } return result } +func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) { + if !isReturn || len(a.Registers) == 0 { + // TODO in next CL, assign + if f.Offset != a.FrameOffset(result) { + if config.regAmounts.intRegs == 0 && config.regAmounts.floatRegs == 0 { + panic(fmt.Errorf("Expected node offset %d != abi offset %d", f.Offset, a.FrameOffset(result))) + } + } + } +} + //...................................................................... // // Non-public portions. diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index ba67c58c45..9a4c00a341 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -43,6 +43,9 @@ func enqueueFunc(fn *ir.Func) { if len(fn.Body) == 0 { // Initialize ABI wrappers if necessary. ssagen.InitLSym(fn, false) + types.CalcSize(fn.Type()) // TODO register args; remove this once all is done by abiutils + a := ssagen.AbiForFunc(fn) + a.ABIAnalyze(fn.Type()) // will set parameter spill/home locations correctly liveness.WriteFuncMap(fn) return } diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index ece274b083..e5778cb31a 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -104,13 +104,13 @@ func (a *AuxCall) ResultForOffsetAndType(offset int64, t *types.Type) int64 { // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { - return int64(a.results[which].Offset) + return int64(a.abiInfo.OutParam(int(which)).Offset()) } // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) OffsetOfArg(which int64) int64 { - return int64(a.args[which].Offset) + return int64(a.abiInfo.InParam(int(which)).Offset()) } // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). @@ -206,6 +206,9 @@ func (a *AuxCall) String() string { return fn + "}" } +// ACParamsToTypes translates a slice of Param into a slice of *types.Type +// This is a helper call for ssagen/ssa.go. +// TODO remove this, as part of replacing fields of AuxCall with abi.ABIParamResultInfo. func ACParamsToTypes(ps []Param) (ts []*types.Type) { for _, p := range ps { ts = append(ts, p.Type) @@ -215,7 +218,6 @@ func ACParamsToTypes(ps []Param) (ts []*types.Type) { // StaticAuxCall returns an AuxCall for a static call. func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - // TODO Create regInfo for AuxCall if paramResultInfo == nil { panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) } @@ -223,15 +225,13 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo } // InterfaceAuxCall returns an AuxCall for an interface call. -func InterfaceAuxCall(args []Param, results []Param) *AuxCall { - // TODO Create regInfo for AuxCall - return &AuxCall{Fn: nil, args: args, results: results} +func InterfaceAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} } // ClosureAuxCall returns an AuxCall for a closure call. -func ClosureAuxCall(args []Param, results []Param) *AuxCall { - // TODO Create regInfo for AuxCall - return &AuxCall{Fn: nil, args: args, results: results} +func ClosureAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} } func (*AuxCall) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 865630dd3e..81e8eccf32 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7,6 +7,7 @@ package ssagen import ( "bufio" "bytes" + "cmd/compile/internal/abi" "encoding/binary" "fmt" "go/constant" @@ -208,6 +209,32 @@ func InitConfig() { ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic") } +// AbiForFunc returns the ABI for a function, used to figure out arg/result mapping for rtcall and bodyless functions. +// This follows policy for GOEXPERIMENT=regabi, //go:registerparams, and currently defined ABIInternal. +// Policy is subject to change.... +// This always returns a freshly copied ABI. +func AbiForFunc(fn *ir.Func) *abi.ABIConfig { + return abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1).Copy() // No idea what races will result, be safe +} + +// abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. +// Passing a nil function returns ABIInternal. +func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { + a := abi1 + if true || objabi.Regabi_enabled == 0 { + a = abi0 + } + if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + name := ir.FuncName(fn) + if strings.Contains(name, ".") { + base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) + } + a = abi1 + base.WarnfAt(fn.Pos(), "declared function %v has register params", fn) + } + return a +} + // getParam returns the Field of ith param of node n (which is a // function/method/interface call), where the receiver of a method call is // considered as the 0th parameter. This does not include the receiver of an @@ -357,25 +384,10 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { if fn.Pragma&ir.Nosplit != 0 { s.f.NoSplit = true } - s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-width cache. + s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-register-width cache. s.f.ABI1 = ssaConfig.ABI1.Copy() - - s.f.ABIDefault = s.f.ABI1 // Default ABI for function calls with no parsed signature for a pragma, e.g. rtcall - // TODO(register args) -- remove "true ||"; in the short run, turning on the register ABI experiment still leaves the compiler defaulting to ABI0. - // TODO(register args) -- remove this conditional entirely when register ABI is not an experiment. - if true || objabi.Regabi_enabled == 0 { - s.f.ABIDefault = s.f.ABI0 // reset - } - - s.f.ABISelf = s.f.ABIDefault - - if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working - s.f.ABISelf = s.f.ABI1 - if strings.Contains(name, ".") { - base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) - } - s.f.Warnl(fn.Pos(), "declared function %v has register params", fn) - } + s.f.ABIDefault = abiForFunc(nil, s.f.ABI0, s.f.ABI1) + s.f.ABISelf = abiForFunc(fn, s.f.ABI0, s.f.ABI1) s.panics = map[funcLine]*ssa.Block{} s.softFloat = s.config.SoftFloat @@ -4731,7 +4743,7 @@ func (s *state) openDeferExit() { v := s.load(r.closure.Type.Elem(), r.closure) s.maybeNilCheckClosure(v, callDefer) codeptr := s.rawLoad(types.Types[types.TUINTPTR], v) - aux := ssa.ClosureAuxCall(ACArgs, ACResults) + aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v) } else { aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, @@ -4972,10 +4984,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // critical that we not clobber any arguments already // stored onto the stack. codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure) - aux := ssa.ClosureAuxCall(ACArgs, ACResults) + aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure) case codeptr != nil: - aux := ssa.InterfaceAuxCall(ACArgs, ACResults) + // Note that the "receiver" parameter is nil because the actual receiver is the first input parameter. + aux := ssa.InterfaceAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr) case callee != nil: aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params) diff --git a/src/cmd/compile/internal/test/abiutilsaux_test.go b/src/cmd/compile/internal/test/abiutilsaux_test.go index bac0c7639d..7eb273273d 100644 --- a/src/cmd/compile/internal/test/abiutilsaux_test.go +++ b/src/cmd/compile/internal/test/abiutilsaux_test.go @@ -129,36 +129,4 @@ func abitest(t *testing.T, ft *types.Type, exp expectedDump) { strings.TrimSpace(exp.dump), regResString, reason) } - // Analyze again with empty register set. - empty := abi.NewABIConfig(0, 0) - emptyRes := empty.ABIAnalyze(ft) - emptyResString := emptyRes.String() - - // Walk the results and make sure the offsets assigned match - // up with those assiged by CalcSize. This checks to make sure that - // when we have no available registers the ABI assignment degenerates - // back to the original ABI0. - - // receiver - failed := 0 - rfsl := ft.Recvs().Fields().Slice() - poff := 0 - if len(rfsl) != 0 { - failed |= verifyParamResultOffset(t, rfsl[0], emptyRes.InParams()[0], "receiver", 0) - poff = 1 - } - // params - pfsl := ft.Params().Fields().Slice() - for k, f := range pfsl { - verifyParamResultOffset(t, f, emptyRes.InParams()[k+poff], "param", k) - } - // results - ofsl := ft.Results().Fields().Slice() - for k, f := range ofsl { - failed |= verifyParamResultOffset(t, f, emptyRes.OutParams()[k], "result", k) - } - - if failed != 0 { - t.Logf("emptyres:\n%s\n", emptyResString) - } } -- GitLab From 2a8df4488ee893353b1200794bde758e9726e7c7 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 31 Jan 2021 19:51:45 +0100 Subject: [PATCH 0132/1298] os: mark pipes returned by os.Pipe() as inheritable by default Now that we don't automatically pass all inheritable handles to new processes, we can make pipes returned by os.Pipe() inheritable, just like they are on Unix. This then allows them to be passed through the SysProcAttr.AdditionalInheritedHandles parameter simply. Updates #44011. Fixes #21085. Change-Id: I8eae329fbc74f9dc7962136fa9aae8fb66879751 Reviewed-on: https://go-review.googlesource.com/c/go/+/288299 Trust: Jason A. Donenfeld Trust: Alex Brainman Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- src/os/exec/exec_test.go | 10 ++++++++ src/os/exec/exec_windows_test.go | 43 ++++++++++++++++++++++++++++++++ src/os/file_windows.go | 5 ++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/os/exec/exec_windows_test.go diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 8b0c93f382..57591a38ab 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -915,6 +915,16 @@ func TestHelperProcess(*testing.T) { case "sleep": time.Sleep(3 * time.Second) os.Exit(0) + case "pipehandle": + handle, _ := strconv.ParseUint(args[0], 16, 64) + pipe := os.NewFile(uintptr(handle), "") + _, err := fmt.Fprint(pipe, args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "writing to pipe failed: %v\n", err) + os.Exit(1) + } + pipe.Close() + os.Exit(0) default: fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) os.Exit(2) diff --git a/src/os/exec/exec_windows_test.go b/src/os/exec/exec_windows_test.go new file mode 100644 index 0000000000..fbccffec0e --- /dev/null +++ b/src/os/exec/exec_windows_test.go @@ -0,0 +1,43 @@ +// Copyright 2021 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. + +//go:build windows +// +build windows + +package exec_test + +import ( + "io" + "os" + "strconv" + "syscall" + "testing" +) + +func TestPipePassing(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Error(err) + } + const marker = "arrakis, dune, desert planet" + childProc := helperCommand(t, "pipehandle", strconv.FormatUint(uint64(w.Fd()), 16), marker) + childProc.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(w.Fd())}} + err = childProc.Start() + if err != nil { + t.Error(err) + } + w.Close() + response, err := io.ReadAll(r) + if err != nil { + t.Error(err) + } + r.Close() + if string(response) != marker { + t.Errorf("got %q; want %q", string(response), marker) + } + err = childProc.Wait() + if err != nil { + t.Error(err) + } +} diff --git a/src/os/file_windows.go b/src/os/file_windows.go index dfc5fc6ce6..0d3c048a75 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -279,10 +279,11 @@ func rename(oldname, newname string) error { } // Pipe returns a connected pair of Files; reads from r return bytes written to w. -// It returns the files and an error, if any. +// It returns the files and an error, if any. The Windows handles underlying +// the returned files are marked as inheritable by child processes. func Pipe() (r *File, w *File, err error) { var p [2]syscall.Handle - e := syscall.CreatePipe(&p[0], &p[1], nil, 0) + e := syscall.Pipe(p[:]) if e != nil { return nil, nil, NewSyscallError("pipe", e) } -- GitLab From 5fafc0bbd4819578e58e5b9163981b0074ab0b01 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Thu, 25 Feb 2021 18:38:43 -0500 Subject: [PATCH 0133/1298] cmd/go/internal/modload: don't query when fixing canonical versions If a canonical version is passed to fixVersion when loading the main go.mod and that version don't match the module path's major version suffix, don't call Query. Query doesn't return a useful error in this case when the path is malformed, for example, when it doens't have a dot in the first path element. It's better to report the major version mismatch error. Fixes #44494 Change-Id: I97b1f64aee894fa0db6fb637aa03a51357ee782c Reviewed-on: https://go-review.googlesource.com/c/go/+/296590 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/modload/init.go | 5 ++-- .../script/mod_retract_fix_version.txt | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index bc8d17e0a5..4de5ac9303 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -539,9 +539,10 @@ func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer { } } if vers != "" && module.CanonicalVersion(vers) == vers { - if err := module.CheckPathMajor(vers, pathMajor); err == nil { - return vers, nil + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + return "", module.VersionError(module.Version{Path: path, Version: vers}, err) } + return vers, nil } info, err := Query(ctx, path, vers, "", nil) diff --git a/src/cmd/go/testdata/script/mod_retract_fix_version.txt b/src/cmd/go/testdata/script/mod_retract_fix_version.txt index f8099ec93e..e45758b627 100644 --- a/src/cmd/go/testdata/script/mod_retract_fix_version.txt +++ b/src/cmd/go/testdata/script/mod_retract_fix_version.txt @@ -12,6 +12,18 @@ go mod tidy go list -m all cmp go.mod go.mod.want +# If a retracted version doesn't match the module's major version suffx, +# an error should be reported. +! go mod edit -retract=v3.0.1 +stderr '^go mod: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$' +cp go.mod.mismatch-v2 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote/v2: version "v3.0.1" invalid: should be v2, not v3$' + +cp go.mod.mismatch-v1 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote: version "v3.0.1" invalid: should be v0 or v1, not v3$' + -- go.mod -- go 1.16 @@ -22,3 +34,15 @@ go 1.16 retract v2.0.1 module rsc.io/quote/v2 +-- go.mod.mismatch-v2 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote/v2 +-- go.mod.mismatch-v1 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote -- GitLab From a400eb3261ee3798e0715d2ba6a4083abe59150a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 1 Mar 2021 14:43:24 +0000 Subject: [PATCH 0134/1298] Revert "cmd/compile: check frame offsets against abi" This reverts CL 293392. Reason for revert: broke most non-x86 builders Fixes #44675 Change-Id: I1e815c3ab27a02e83a2f0d221a617909dd021403 Reviewed-on: https://go-review.googlesource.com/c/go/+/297549 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/abi/abiutils.go | 43 ++------------- src/cmd/compile/internal/gc/compile.go | 3 - src/cmd/compile/internal/ssa/op.go | 18 +++--- src/cmd/compile/internal/ssagen/ssa.go | 55 +++++++------------ .../compile/internal/test/abiutilsaux_test.go | 32 +++++++++++ 5 files changed, 66 insertions(+), 85 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index f5f3b25726..b43d95e976 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -52,12 +52,12 @@ func (a *ABIParamResultInfo) OutRegistersUsed() int { return a.outRegistersUsed } -func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment { - return &a.inparams[i] +func (a *ABIParamResultInfo) InParam(i int) ABIParamAssignment { + return a.inparams[i] } -func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment { - return &a.outparams[i] +func (a *ABIParamResultInfo) OutParam(i int) ABIParamAssignment { + return a.outparams[i] } func (a *ABIParamResultInfo) SpillAreaOffset() int64 { @@ -111,18 +111,6 @@ func (a *ABIParamAssignment) SpillOffset() int32 { return a.offset } -// FrameOffset returns the location that a value would spill to, if any exists. -// For register-allocated inputs, that is their spill offset reserved for morestack -// (might as well use it, it is there); for stack-allocated inputs and outputs, -// that is their location on the stack. For register-allocated outputs, there is -// no defined spill area, so return -1. -func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 { - if len(a.Registers) == 0 || a.offset == -1 { - return int64(a.offset) - } - return int64(a.offset) + i.SpillAreaOffset() -} - // RegAmounts holds a specified number of integer/float registers. type RegAmounts struct { intRegs int @@ -277,32 +265,9 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs - // Fill in the frame offsets for receiver, inputs, results - k := 0 - if t.NumRecvs() != 0 { - config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false) - k++ - } - for i, f := range ft.Params.FieldSlice() { - config.updateOffset(result, f, result.inparams[k+i], false) - } - for i, f := range ft.Results.FieldSlice() { - config.updateOffset(result, f, result.outparams[i], true) - } return result } -func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) { - if !isReturn || len(a.Registers) == 0 { - // TODO in next CL, assign - if f.Offset != a.FrameOffset(result) { - if config.regAmounts.intRegs == 0 && config.regAmounts.floatRegs == 0 { - panic(fmt.Errorf("Expected node offset %d != abi offset %d", f.Offset, a.FrameOffset(result))) - } - } - } -} - //...................................................................... // // Non-public portions. diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index 9a4c00a341..ba67c58c45 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -43,9 +43,6 @@ func enqueueFunc(fn *ir.Func) { if len(fn.Body) == 0 { // Initialize ABI wrappers if necessary. ssagen.InitLSym(fn, false) - types.CalcSize(fn.Type()) // TODO register args; remove this once all is done by abiutils - a := ssagen.AbiForFunc(fn) - a.ABIAnalyze(fn.Type()) // will set parameter spill/home locations correctly liveness.WriteFuncMap(fn) return } diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index e5778cb31a..ece274b083 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -104,13 +104,13 @@ func (a *AuxCall) ResultForOffsetAndType(offset int64, t *types.Type) int64 { // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { - return int64(a.abiInfo.OutParam(int(which)).Offset()) + return int64(a.results[which].Offset) } // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) OffsetOfArg(which int64) int64 { - return int64(a.abiInfo.InParam(int(which)).Offset()) + return int64(a.args[which].Offset) } // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). @@ -206,9 +206,6 @@ func (a *AuxCall) String() string { return fn + "}" } -// ACParamsToTypes translates a slice of Param into a slice of *types.Type -// This is a helper call for ssagen/ssa.go. -// TODO remove this, as part of replacing fields of AuxCall with abi.ABIParamResultInfo. func ACParamsToTypes(ps []Param) (ts []*types.Type) { for _, p := range ps { ts = append(ts, p.Type) @@ -218,6 +215,7 @@ func ACParamsToTypes(ps []Param) (ts []*types.Type) { // StaticAuxCall returns an AuxCall for a static call. func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { + // TODO Create regInfo for AuxCall if paramResultInfo == nil { panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) } @@ -225,13 +223,15 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo } // InterfaceAuxCall returns an AuxCall for an interface call. -func InterfaceAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} +func InterfaceAuxCall(args []Param, results []Param) *AuxCall { + // TODO Create regInfo for AuxCall + return &AuxCall{Fn: nil, args: args, results: results} } // ClosureAuxCall returns an AuxCall for a closure call. -func ClosureAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} +func ClosureAuxCall(args []Param, results []Param) *AuxCall { + // TODO Create regInfo for AuxCall + return &AuxCall{Fn: nil, args: args, results: results} } func (*AuxCall) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 81e8eccf32..865630dd3e 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7,7 +7,6 @@ package ssagen import ( "bufio" "bytes" - "cmd/compile/internal/abi" "encoding/binary" "fmt" "go/constant" @@ -209,32 +208,6 @@ func InitConfig() { ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic") } -// AbiForFunc returns the ABI for a function, used to figure out arg/result mapping for rtcall and bodyless functions. -// This follows policy for GOEXPERIMENT=regabi, //go:registerparams, and currently defined ABIInternal. -// Policy is subject to change.... -// This always returns a freshly copied ABI. -func AbiForFunc(fn *ir.Func) *abi.ABIConfig { - return abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1).Copy() // No idea what races will result, be safe -} - -// abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. -// Passing a nil function returns ABIInternal. -func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { - a := abi1 - if true || objabi.Regabi_enabled == 0 { - a = abi0 - } - if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working - name := ir.FuncName(fn) - if strings.Contains(name, ".") { - base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) - } - a = abi1 - base.WarnfAt(fn.Pos(), "declared function %v has register params", fn) - } - return a -} - // getParam returns the Field of ith param of node n (which is a // function/method/interface call), where the receiver of a method call is // considered as the 0th parameter. This does not include the receiver of an @@ -384,10 +357,25 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { if fn.Pragma&ir.Nosplit != 0 { s.f.NoSplit = true } - s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-register-width cache. + s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-width cache. s.f.ABI1 = ssaConfig.ABI1.Copy() - s.f.ABIDefault = abiForFunc(nil, s.f.ABI0, s.f.ABI1) - s.f.ABISelf = abiForFunc(fn, s.f.ABI0, s.f.ABI1) + + s.f.ABIDefault = s.f.ABI1 // Default ABI for function calls with no parsed signature for a pragma, e.g. rtcall + // TODO(register args) -- remove "true ||"; in the short run, turning on the register ABI experiment still leaves the compiler defaulting to ABI0. + // TODO(register args) -- remove this conditional entirely when register ABI is not an experiment. + if true || objabi.Regabi_enabled == 0 { + s.f.ABIDefault = s.f.ABI0 // reset + } + + s.f.ABISelf = s.f.ABIDefault + + if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + s.f.ABISelf = s.f.ABI1 + if strings.Contains(name, ".") { + base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) + } + s.f.Warnl(fn.Pos(), "declared function %v has register params", fn) + } s.panics = map[funcLine]*ssa.Block{} s.softFloat = s.config.SoftFloat @@ -4743,7 +4731,7 @@ func (s *state) openDeferExit() { v := s.load(r.closure.Type.Elem(), r.closure) s.maybeNilCheckClosure(v, callDefer) codeptr := s.rawLoad(types.Types[types.TUINTPTR], v) - aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) + aux := ssa.ClosureAuxCall(ACArgs, ACResults) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v) } else { aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, @@ -4984,11 +4972,10 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // critical that we not clobber any arguments already // stored onto the stack. codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure) - aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) + aux := ssa.ClosureAuxCall(ACArgs, ACResults) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure) case codeptr != nil: - // Note that the "receiver" parameter is nil because the actual receiver is the first input parameter. - aux := ssa.InterfaceAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) + aux := ssa.InterfaceAuxCall(ACArgs, ACResults) call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr) case callee != nil: aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params) diff --git a/src/cmd/compile/internal/test/abiutilsaux_test.go b/src/cmd/compile/internal/test/abiutilsaux_test.go index 7eb273273d..bac0c7639d 100644 --- a/src/cmd/compile/internal/test/abiutilsaux_test.go +++ b/src/cmd/compile/internal/test/abiutilsaux_test.go @@ -129,4 +129,36 @@ func abitest(t *testing.T, ft *types.Type, exp expectedDump) { strings.TrimSpace(exp.dump), regResString, reason) } + // Analyze again with empty register set. + empty := abi.NewABIConfig(0, 0) + emptyRes := empty.ABIAnalyze(ft) + emptyResString := emptyRes.String() + + // Walk the results and make sure the offsets assigned match + // up with those assiged by CalcSize. This checks to make sure that + // when we have no available registers the ABI assignment degenerates + // back to the original ABI0. + + // receiver + failed := 0 + rfsl := ft.Recvs().Fields().Slice() + poff := 0 + if len(rfsl) != 0 { + failed |= verifyParamResultOffset(t, rfsl[0], emptyRes.InParams()[0], "receiver", 0) + poff = 1 + } + // params + pfsl := ft.Params().Fields().Slice() + for k, f := range pfsl { + verifyParamResultOffset(t, f, emptyRes.InParams()[k+poff], "param", k) + } + // results + ofsl := ft.Results().Fields().Slice() + for k, f := range ofsl { + failed |= verifyParamResultOffset(t, f, emptyRes.OutParams()[k], "result", k) + } + + if failed != 0 { + t.Logf("emptyres:\n%s\n", emptyResString) + } } -- GitLab From 87beecd6dfd3b12ed30785ec502f7380dc79ec29 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Sat, 27 Feb 2021 23:06:23 -0500 Subject: [PATCH 0135/1298] cmd/go: add missing newline to retraction warning message Fixes #44674 Change-Id: Icbdb79084bf7bd2f52cc0a53abcc1ec6f0c4a1bf Reviewed-on: https://go-review.googlesource.com/c/go/+/297350 Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Trust: Jay Conrod --- src/cmd/go/internal/modget/get.go | 2 +- src/cmd/go/testdata/script/mod_get_retract.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 6b328d8bc8..971c5a8d8a 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -1530,7 +1530,7 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns } } if retractPath != "" { - fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest", retractPath) + fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath) } } diff --git a/src/cmd/go/testdata/script/mod_get_retract.txt b/src/cmd/go/testdata/script/mod_get_retract.txt index fe0ac88629..560fa7bfb2 100644 --- a/src/cmd/go/testdata/script/mod_get_retract.txt +++ b/src/cmd/go/testdata/script/mod_get_retract.txt @@ -11,7 +11,7 @@ cp go.mod.orig go.mod go mod edit -require example.com/retract/self/prev@v1.9.0 go get -d example.com/retract/self/prev stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' -stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest$' +stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest\n$' go list -m example.com/retract/self/prev stdout '^example.com/retract/self/prev v1.9.0$' -- GitLab From f6a74c656837fcb0ea04e7b605ccdce7d10c45db Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 26 Feb 2021 09:25:22 -0500 Subject: [PATCH 0136/1298] cmd/compile/internal/ir: fix up stale comment Fix a small stale comment in FinishCaptureNames (refers to old code structure before the big refactoring). Change-Id: I2dfb84ce238f919f6e17061439a8bd9b09459dae Reviewed-on: https://go-review.googlesource.com/c/go/+/296829 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/ir/name.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go index 6240852aaf..035c9cd3d0 100644 --- a/src/cmd/compile/internal/ir/name.go +++ b/src/cmd/compile/internal/ir/name.go @@ -398,7 +398,7 @@ func FinishCaptureNames(pos src.XPos, outerfn, fn *Func) { // unhook them. // make the list of pointers for the closure call. for _, cv := range fn.ClosureVars { - // Unlink from n; see comment in syntax.go type Param for these fields. + // Unlink from n; see comment above on type Name for these fields. n := cv.Defn.(*Name) n.Innermost = cv.Outer -- GitLab From 97bdac03aee805cfa54e7762037a568d85339970 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 1 Mar 2021 10:00:09 -0500 Subject: [PATCH 0137/1298] cmd: upgrade golang.org/x/mod to relax import path check This incorporates CL 297089, which allows leading dots in import path elements but not module path elements. Also added a test. Fixes #43985 Updates #34992 Change-Id: I2d5faabd8f7b23a7943d3f3ccb6707ab5dc2ce3c Reviewed-on: https://go-review.googlesource.com/c/go/+/297530 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/go/internal/get/get.go | 30 +++++++++++++- .../go/testdata/script/mod_invalid_path.txt | 24 +++++++++++ .../vendor/golang.org/x/mod/module/module.go | 40 ++++++++++++------- src/cmd/vendor/modules.txt | 2 +- 6 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 8ca3b982ee..ef05ca1ad1 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc + golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 7de27879f6..77063f76af 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc h1:xQukuh0OD2SNSUK1CCBFATgHYx5ye75S/bAWEU/PT0E= -golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa h1:Ci2bbuyE4ah9djFByg+fdNQcqc8DVSdcXbrWy6MBoEs= +golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 38ff3823f2..329a2f5eda 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -431,7 +431,7 @@ func downloadPackage(p *load.Package) error { } importPrefix = importPrefix[:slash] } - if err := module.CheckImportPath(importPrefix); err != nil { + if err := checkImportPath(importPrefix); err != nil { return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) } security := web.SecureOnly @@ -591,3 +591,31 @@ func selectTag(goVersion string, tags []string) (match string) { } return "" } + +// checkImportPath is like module.CheckImportPath, but it forbids leading dots +// in path elements. This can lead to 'go get' creating .git and other VCS +// directories in places we might run VCS tools later. +func checkImportPath(path string) error { + if err := module.CheckImportPath(path); err != nil { + return err + } + checkElem := func(elem string) error { + if elem[0] == '.' { + return fmt.Errorf("malformed import path %q: leading dot in path element", path) + } + return nil + } + elemStart := 0 + for i, r := range path { + if r == '/' { + if err := checkElem(path[elemStart:]); err != nil { + return err + } + elemStart = i + 1 + } + } + if err := checkElem(path[elemStart:]); err != nil { + return err + } + return nil +} diff --git a/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt index 667828839f..c8c075daae 100644 --- a/src/cmd/go/testdata/script/mod_invalid_path.txt +++ b/src/cmd/go/testdata/script/mod_invalid_path.txt @@ -23,6 +23,20 @@ cd $WORK/gopath/src/badname ! go list . stderr 'invalid module path' +# Test that an import path containing an element with a leading dot is valid, +# but such a module path is not. +# Verifies #43985. +cd $WORK/gopath/src/dotname +go list ./.dot +stdout '^example.com/dotname/.dot$' +go list ./use +stdout '^example.com/dotname/use$' +! go list -m example.com/dotname/.dot@latest +stderr '^go list -m: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$' +go get -d example.com/dotname/.dot +go get -d example.com/dotname/use +go mod tidy + -- mod/go.mod -- -- mod/foo.go -- @@ -38,3 +52,13 @@ module .\. -- badname/foo.go -- package badname +-- dotname/go.mod -- +module example.com/dotname + +go 1.16 +-- dotname/.dot/dot.go -- +package dot +-- dotname/use/use.go -- +package use + +import _ "example.com/dotname/.dot" diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go index c1c5263c42..272baeef17 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/module.go +++ b/src/cmd/vendor/golang.org/x/mod/module/module.go @@ -270,7 +270,7 @@ func fileNameOK(r rune) bool { // CheckPath checks that a module path is valid. // A valid module path is a valid import path, as checked by CheckImportPath, -// with two additional constraints. +// with three additional constraints. // First, the leading path element (up to the first slash, if any), // by convention a domain name, must contain only lower-case ASCII letters, // ASCII digits, dots (U+002E), and dashes (U+002D); @@ -280,8 +280,9 @@ func fileNameOK(r rune) bool { // and must not contain any dots. For paths beginning with "gopkg.in/", // this second requirement is replaced by a requirement that the path // follow the gopkg.in server's conventions. +// Third, no path element may begin with a dot. func CheckPath(path string) error { - if err := checkPath(path, false); err != nil { + if err := checkPath(path, modulePath); err != nil { return fmt.Errorf("malformed module path %q: %v", path, err) } i := strings.Index(path, "/") @@ -315,7 +316,7 @@ func CheckPath(path string) error { // // A valid path element is a non-empty string made up of // ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. -// It must not begin or end with a dot (U+002E), nor contain two dots in a row. +// It must not end with a dot (U+002E), nor contain two dots in a row. // // The element prefix up to the first dot must not be a reserved file name // on Windows, regardless of case (CON, com1, NuL, and so on). The element @@ -326,19 +327,29 @@ func CheckPath(path string) error { // top-level package documentation for additional information about // subtleties of Unicode. func CheckImportPath(path string) error { - if err := checkPath(path, false); err != nil { + if err := checkPath(path, importPath); err != nil { return fmt.Errorf("malformed import path %q: %v", path, err) } return nil } +// pathKind indicates what kind of path we're checking. Module paths, +// import paths, and file paths have different restrictions. +type pathKind int + +const ( + modulePath pathKind = iota + importPath + filePath +) + // checkPath checks that a general path is valid. // It returns an error describing why but not mentioning path. // Because these checks apply to both module paths and import paths, // the caller is expected to add the "malformed ___ path %q: " prefix. // fileName indicates whether the final element of the path is a file name // (as opposed to a directory name). -func checkPath(path string, fileName bool) error { +func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") } @@ -357,35 +368,34 @@ func checkPath(path string, fileName bool) error { elemStart := 0 for i, r := range path { if r == '/' { - if err := checkElem(path[elemStart:i], fileName); err != nil { + if err := checkElem(path[elemStart:i], kind); err != nil { return err } elemStart = i + 1 } } - if err := checkElem(path[elemStart:], fileName); err != nil { + if err := checkElem(path[elemStart:], kind); err != nil { return err } return nil } // checkElem checks whether an individual path element is valid. -// fileName indicates whether the element is a file name (not a directory name). -func checkElem(elem string, fileName bool) error { +func checkElem(elem string, kind pathKind) error { if elem == "" { return fmt.Errorf("empty path element") } if strings.Count(elem, ".") == len(elem) { return fmt.Errorf("invalid path element %q", elem) } - if elem[0] == '.' && !fileName { + if elem[0] == '.' && kind == modulePath { return fmt.Errorf("leading dot in path element") } if elem[len(elem)-1] == '.' { return fmt.Errorf("trailing dot in path element") } charOK := pathOK - if fileName { + if kind == filePath { charOK = fileNameOK } for _, r := range elem { @@ -406,7 +416,7 @@ func checkElem(elem string, fileName bool) error { } } - if fileName { + if kind == filePath { // don't check for Windows short-names in file names. They're // only an issue for import paths. return nil @@ -444,7 +454,7 @@ func checkElem(elem string, fileName bool) error { // top-level package documentation for additional information about // subtleties of Unicode. func CheckFilePath(path string) error { - if err := checkPath(path, true); err != nil { + if err := checkPath(path, filePath); err != nil { return fmt.Errorf("malformed file path %q: %v", path, err) } return nil @@ -647,7 +657,7 @@ func EscapePath(path string) (escaped string, err error) { // Versions are allowed to be in non-semver form but must be valid file names // and not contain exclamation marks. func EscapeVersion(v string) (escaped string, err error) { - if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { + if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { return "", &InvalidVersionError{ Version: v, Err: fmt.Errorf("disallowed version string"), @@ -706,7 +716,7 @@ func UnescapeVersion(escaped string) (v string, err error) { if !ok { return "", fmt.Errorf("invalid escaped version %q", escaped) } - if err := checkElem(v, true); err != nil { + if err := checkElem(v, filePath); err != nil { return "", fmt.Errorf("invalid escaped version %q: %v", v, err) } return v, nil diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 03853007e0..e4dfd32315 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.2-0.20210225160341-66bf157bf5bc +# golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile -- GitLab From b98ce3b606b2bb620c9c62482cd73f068157a32c Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Mon, 1 Mar 2021 09:05:58 -0800 Subject: [PATCH 0138/1298] cmd/compile: import empty closure function correctly On import, make sure that an empty closure is represented as a single empty block statement. Otherwise, the closure is dropped. Block statements are not exported explicitly, so must recreate on import. Fixes #44330 Change-Id: I061598f0f859dd71d2d0cbd10c77cdd81525d1f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/297569 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky Trust: Dan Scales --- src/cmd/compile/internal/typecheck/iimport.go | 5 ++++ test/fixedbugs/issue44330.dir/a.go | 21 +++++++++++++++++ test/fixedbugs/issue44330.dir/b.go | 23 +++++++++++++++++++ test/fixedbugs/issue44330.go | 7 ++++++ 4 files changed, 56 insertions(+) create mode 100644 test/fixedbugs/issue44330.dir/a.go create mode 100644 test/fixedbugs/issue44330.dir/b.go create mode 100644 test/fixedbugs/issue44330.go diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 17aa35549d..9355174da8 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -992,6 +992,11 @@ func (r *importReader) node() ir.Node { r.funcBody(fn) fn.Dcl = fn.Inl.Dcl fn.Body = fn.Inl.Body + if len(fn.Body) == 0 { + // An empty closure must be represented as a single empty + // block statement, else it will be dropped. + fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)} + } fn.Inl = nil ir.FinishCaptureNames(pos, r.curfn, fn) diff --git a/test/fixedbugs/issue44330.dir/a.go b/test/fixedbugs/issue44330.dir/a.go new file mode 100644 index 0000000000..9d3ab9fe80 --- /dev/null +++ b/test/fixedbugs/issue44330.dir/a.go @@ -0,0 +1,21 @@ +// Copyright 2021 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 a + +type Table struct { + ColumnSeparator bool + RowSeparator bool + + // ColumnResizer is called on each Draw. Can be used for custom column sizing. + ColumnResizer func() +} + +func NewTable() *Table { + return &Table{ + ColumnSeparator: true, + RowSeparator: true, + ColumnResizer: func() {}, + } +} diff --git a/test/fixedbugs/issue44330.dir/b.go b/test/fixedbugs/issue44330.dir/b.go new file mode 100644 index 0000000000..1d5742421b --- /dev/null +++ b/test/fixedbugs/issue44330.dir/b.go @@ -0,0 +1,23 @@ +// Copyright 2021 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 ( + "./a" +) + +type Term struct { + top *a.Table +} + +//go:noinline +func NewFred() *Term { + table := a.NewTable() + return &Term{top: table} +} + +func main() { + NewFred() +} diff --git a/test/fixedbugs/issue44330.go b/test/fixedbugs/issue44330.go new file mode 100644 index 0000000000..682d9c5bf3 --- /dev/null +++ b/test/fixedbugs/issue44330.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2021 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 ignored -- GitLab From a69c45213d7fa18a09e59274e0e18db7766bf5c8 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 23 Feb 2021 16:29:33 -0500 Subject: [PATCH 0139/1298] go/types: review of expr.go The changes from the (reviewed) dev.regabi copy of expr.go can be seen by comparing patchset 2 and 7. The actual change is some small improvements to readability and consistency in untyped conversion, adding some missing documentation, and removing the "// REVIEW INCOMPLETE" marker. Note that expr.go diverges from types2 in its handling of untyped conversion. Change-Id: I13a85f6e08f43343e249818245aa857b1f4bf29c Reviewed-on: https://go-review.googlesource.com/c/go/+/295729 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/expr.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 77807e3b5b..9b51ce94b7 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1,4 +1,3 @@ -// REVIEW INCOMPLETE // Copyright 2012 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. @@ -100,8 +99,8 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) { // Typed constants must be representable in // their type after each constant operation. - if typ := asBasic(x.typ); typ != nil && isTyped(typ) { - check.representable(x, typ) + if isTyped(x.typ) { + check.representable(x, asBasic(x.typ)) return } @@ -191,10 +190,9 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { // nothing to do (and don't cause an error below in the overflow check) return } - typ := asBasic(x.typ) var prec uint - if isUnsigned(typ) { - prec = uint(check.conf.sizeof(typ) * 8) + if isUnsigned(x.typ) { + prec = uint(check.conf.sizeof(x.typ) * 8) } x.val = constant.UnaryOp(e.Op, x.val, prec) x.expr = e @@ -400,14 +398,20 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c // representable checks that a constant operand is representable in the given // basic type. func (check *Checker) representable(x *operand, typ *Basic) { - if v, code := check.representation(x, typ); code != 0 { + v, code := check.representation(x, typ) + if code != 0 { check.invalidConversion(code, x, typ) x.mode = invalid - } else if v != nil { - x.val = v + return } + assert(v != nil) + x.val = v } +// representation returns the representation of the constant operand x as the +// basic type typ. +// +// If no such representation is possible, it returns a non-zero error code. func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, errorCode) { assert(x.mode == constant_) v := x.val @@ -593,7 +597,10 @@ func (check *Checker) convertUntyped(x *operand, target Type) { // implicitTypeAndValue returns the implicit type of x when used in a context // where the target type is expected. If no such implicit conversion is -// possible, it returns a nil Type. +// possible, it returns a nil Type and non-zero error code. +// +// If x is a constant operand, the returned constant.Value will be the +// representation of x in this context. func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) { target = expand(target) if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] { @@ -994,9 +1001,8 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token // x.typ is unchanged return } - typ := asBasic(x.typ) // force integer division of integer operands - if op == token.QUO && isInteger(typ) { + if op == token.QUO && isInteger(x.typ) { op = token.QUO_ASSIGN } x.val = constant.BinaryOp(x.val, op, y.val) -- GitLab From 700b73975e9a925584773e6df85b175371cf9d95 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 25 Jan 2021 17:13:51 -0500 Subject: [PATCH 0140/1298] runtime: use entersyscall in syscall_syscallX on Darwin CL 197938 changed syscall* functions to call entersyscall, instead of entersyscallblock. It missed syscall_syscallX, probably because it was in sys_darwin_64.go, not sys_darwin.go like others. Change that one as well. Found during the review of CL 270380 (thanks Joel). Change-Id: I0884fc766703f555a3895be332dccfa7d2431374 Reviewed-on: https://go-review.googlesource.com/c/go/+/286435 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/runtime/sys_darwin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index dacce2ee1a..4ae259ac63 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -27,7 +27,7 @@ func syscall() //go:nosplit //go:cgo_unsafe_args func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - entersyscallblock() + entersyscall() libcCall(unsafe.Pointer(funcPC(syscallX)), unsafe.Pointer(&fn)) exitsyscall() return -- GitLab From ff5cf4ced3f1681ec972cd954d4b476f87616fe3 Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Sat, 20 Jun 2020 14:04:54 +0000 Subject: [PATCH 0141/1298] cmd/link,debug/elf: mips32, add .gnu.attributes and .MIPS.abiflags sections MIPS32 uses .gnu.attributes and .MIPS.abiflags sections to mark FP ABI the object is using, and the kernel will set the correct FP mode for it. Currrently Go doesn't generate these 2 sections. If we link object without these 2 sections togather FPXX objects, the result will be FPXX, which is wrong: FP32 + FPXX -> FP32 FPXX + FP64 -> FP64 FP32 + FP64 -> reject These 2 sections is also needed to support FPXX and FP64 in future. More details about FP32/FPXX/FP64 are explained in: https://web.archive.org/web/20180828210612/https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking Fixes #39677 Change-Id: Ia34e7461dee38a4f575dd8ace609988744512ac1 Reviewed-on: https://go-review.googlesource.com/c/go/+/239217 Run-TryBot: Cherry Zhang Reviewed-by: Cherry Zhang TryBot-Result: Go Bot Trust: Meng Zhuo --- src/cmd/link/internal/ld/elf.go | 145 ++++++++++++++++++++++++++++++++ src/debug/elf/elf.go | 2 + 2 files changed, 147 insertions(+) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 37b2dc640d..d3e598b312 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -519,6 +519,90 @@ func elfwriteinterp(out *OutBuf) int { return int(sh.Size) } +// member of .gnu.attributes of MIPS for fpAbi +const ( + // No floating point is present in the module (default) + MIPS_FPABI_NONE = 0 + // FP code in the module uses the FP32 ABI for a 32-bit ABI + MIPS_FPABI_ANY = 1 + // FP code in the module only uses single precision ABI + MIPS_FPABI_SINGLE = 2 + // FP code in the module uses soft-float ABI + MIPS_FPABI_SOFT = 3 + // FP code in the module assumes an FPU with FR=1 and has 12 + // callee-saved doubles. Historic, no longer supported. + MIPS_FPABI_HIST = 4 + // FP code in the module uses the FPXX ABI + MIPS_FPABI_FPXX = 5 + // FP code in the module uses the FP64 ABI + MIPS_FPABI_FP64 = 6 + // FP code in the module uses the FP64A ABI + MIPS_FPABI_FP64A = 7 +) + +func elfMipsAbiFlags(sh *ElfShdr, startva uint64, resoff uint64) int { + n := 24 + sh.Addr = startva + resoff - uint64(n) + sh.Off = resoff - uint64(n) + sh.Size = uint64(n) + sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) + sh.Flags = uint64(elf.SHF_ALLOC) + + return n +} + +//typedef struct +//{ +// /* Version of flags structure. */ +// uint16_t version; +// /* The level of the ISA: 1-5, 32, 64. */ +// uint8_t isa_level; +// /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */ +// uint8_t isa_rev; +// /* The size of general purpose registers. */ +// uint8_t gpr_size; +// /* The size of co-processor 1 registers. */ +// uint8_t cpr1_size; +// /* The size of co-processor 2 registers. */ +// uint8_t cpr2_size; +// /* The floating-point ABI. */ +// uint8_t fp_abi; +// /* Processor-specific extension. */ +// uint32_t isa_ext; +// /* Mask of ASEs used. */ +// uint32_t ases; +// /* Mask of general flags. */ +// uint32_t flags1; +// uint32_t flags2; +//} Elf_Internal_ABIFlags_v0; +func elfWriteMipsAbiFlags(ctxt *Link) int { + sh := elfshname(".MIPS.abiflags") + ctxt.Out.SeekSet(int64(sh.Off)) + ctxt.Out.Write16(0) // version + ctxt.Out.Write8(32) // isaLevel + ctxt.Out.Write8(1) // isaRev + ctxt.Out.Write8(1) // gprSize + ctxt.Out.Write8(1) // cpr1Size + ctxt.Out.Write8(0) // cpr2Size + if objabi.GOMIPS == "softfloat" { + ctxt.Out.Write8(MIPS_FPABI_SOFT) // fpAbi + } else { + // Go cannot make sure non odd-number-fpr is used (ie, in load a double from memory). + // So, we mark the object is MIPS I style paired float/double register scheme, + // aka MIPS_FPABI_ANY. If we mark the object as FPXX, the kernel may use FR=1 mode, + // then we meet some problem. + // Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage. + // It is not for 'ANY'. + // TODO: switch to FPXX after be sure that no odd-number-fpr is used. + ctxt.Out.Write8(MIPS_FPABI_ANY) // fpAbi + } + ctxt.Out.Write32(0) // isaExt + ctxt.Out.Write32(0) // ases + ctxt.Out.Write32(0) // flags1 + ctxt.Out.Write32(0) // flags2 + return int(sh.Size) +} + func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int { n := 3*4 + uint64(sz) + resoff%4 @@ -1204,6 +1288,10 @@ func (ctxt *Link) doelf() { shstrtab.Addstring(".noptrbss") shstrtab.Addstring("__libfuzzer_extra_counters") shstrtab.Addstring(".go.buildinfo") + if ctxt.IsMIPS() { + shstrtab.Addstring(".MIPS.abiflags") + shstrtab.Addstring(".gnu.attributes") + } // generate .tbss section for dynamic internal linker or external // linking, so that various binutils could correctly calculate @@ -1254,6 +1342,10 @@ func (ctxt *Link) doelf() { shstrtab.Addstring(elfRelType + ".data.rel.ro") } shstrtab.Addstring(elfRelType + ".go.buildinfo") + if ctxt.IsMIPS() { + shstrtab.Addstring(elfRelType + ".MIPS.abiflags") + shstrtab.Addstring(elfRelType + ".gnu.attributes") + } // add a .note.GNU-stack section to mark the stack as non-executable shstrtab.Addstring(".note.GNU-stack") @@ -1445,6 +1537,36 @@ func (ctxt *Link) doelf() { if ctxt.LinkMode == LinkExternal && *flagBuildid != "" { addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid)) } + + + //type mipsGnuAttributes struct { + // version uint8 // 'A' + // length uint32 // 15 including itself + // gnu [4]byte // "gnu\0" + // tag uint8 // 1:file, 2: section, 3: symbol, 1 here + // taglen uint32 // tag length, including tag, 7 here + // tagfp uint8 // 4 + // fpAbi uint8 // see .MIPS.abiflags + //} + if ctxt.IsMIPS() { + gnuattributes := ldr.CreateSymForUpdate(".gnu.attributes", 0) + gnuattributes.SetType(sym.SELFROSECT) + gnuattributes.SetReachable(true) + gnuattributes.AddUint8('A') // version 'A' + gnuattributes.AddUint32(ctxt.Arch, 15) // length 15 including itself + gnuattributes.AddBytes([]byte("gnu\x00")) // "gnu\0" + gnuattributes.AddUint8(1) // 1:file, 2: section, 3: symbol, 1 here + gnuattributes.AddUint32(ctxt.Arch, 7) // tag length, including tag, 7 here + gnuattributes.AddUint8(4) // 4 for FP, 8 for MSA + if objabi.GOMIPS == "softfloat" { + gnuattributes.AddUint8(MIPS_FPABI_SOFT) + } else { + // Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage. + // It is not for 'ANY'. + // TODO: switch to FPXX after be sure that no odd-number-fpr is used. + gnuattributes.AddUint8(MIPS_FPABI_ANY) + } + } } // Do not write DT_NULL. elfdynhash will finish it. @@ -1910,6 +2032,25 @@ elfobj: shsym(sh, ldr, ldr.Lookup(".shstrtab", 0)) eh.Shstrndx = uint16(sh.shnum) + if ctxt.IsMIPS() { + sh = elfshname(".MIPS.abiflags") + sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) + sh.Flags = uint64(elf.SHF_ALLOC) + sh.Addralign = 8 + resoff -= int64(elfMipsAbiFlags(sh, uint64(startva), uint64(resoff))) + + ph := newElfPhdr() + ph.Type = elf.PT_MIPS_ABIFLAGS + ph.Flags = elf.PF_R + phsh(ph, sh) + + sh = elfshname(".gnu.attributes") + sh.Type = uint32(elf.SHT_GNU_ATTRIBUTES) + sh.Addralign = 1 + ldr := ctxt.loader + shsym(sh, ldr, ldr.Lookup(".gnu.attributes", 0)) + } + // put these sections early in the list if !*FlagS { elfshname(".symtab") @@ -2029,6 +2170,10 @@ elfobj: if !*FlagD { a += int64(elfwriteinterp(ctxt.Out)) } + if ctxt.IsMIPS() { + a += int64(elfWriteMipsAbiFlags(ctxt)) + } + if ctxt.LinkMode != LinkExternal { if ctxt.HeadType == objabi.Hnetbsd { a += int64(elfwritenetbsdsig(ctxt.Out)) diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go index 2b777eabac..b04d874019 100644 --- a/src/debug/elf/elf.go +++ b/src/debug/elf/elf.go @@ -644,6 +644,7 @@ const ( SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */ SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */ SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */ + SHT_MIPS_ABIFLAGS SectionType = 0x7000002a /* .MIPS.abiflags */ SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */ SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */ SHT_HIUSER SectionType = 0xffffffff /* specific indexes */ @@ -675,6 +676,7 @@ var shtStrings = []intName{ {0x6ffffffe, "SHT_GNU_VERNEED"}, {0x6fffffff, "SHT_GNU_VERSYM"}, {0x70000000, "SHT_LOPROC"}, + {0x7000002a, "SHT_MIPS_ABIFLAGS"}, {0x7fffffff, "SHT_HIPROC"}, {0x80000000, "SHT_LOUSER"}, {0xffffffff, "SHT_HIUSER"}, -- GitLab From a6eeb4add46eddb19ceba36bdd448738808e5ce2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 24 Feb 2021 10:31:11 -0500 Subject: [PATCH 0142/1298] go/parser,go/types: hide API changes related to type parameters While the dev.typeparams branch was merged, the type parameter API is slated for go1.18. Hide these changes to the go/parser and go/types API. This was done as follows: + For APIs that will probably not be needed for go1.18, simply unexport them. + For APIs that we expect to export in go1.18, prefix symbols with '_', so that the planned (upper-cased) symbol name is apparent. + For APIs that must be exported for testing, move both API and tests to files guarded by the go1.18 build constraint. + parser.ParseTypeParams is unexported and copied wherever it is needed. + The -G flag is removed from gofmt, replaced by enabling type parameters if built with the go1.18 build constraint. Notably, changes related to type parameters in go/ast are currently left exported. We're looking at the AST API separately. The new API diff from 1.16 is: +pkg go/ast, method (*FuncDecl) IsMethod() bool +pkg go/ast, method (*ListExpr) End() token.Pos +pkg go/ast, method (*ListExpr) Pos() token.Pos +pkg go/ast, type FuncType struct, TParams *FieldList +pkg go/ast, type ListExpr struct +pkg go/ast, type ListExpr struct, ElemList []Expr +pkg go/ast, type TypeSpec struct, TParams *FieldList +pkg go/types, type Config struct, GoVersion string Change-Id: I1baf67e26279b49092e774309a836c460979774a Reviewed-on: https://go-review.googlesource.com/c/go/+/295929 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/gofmt/gofmt.go | 25 ++++-- src/cmd/gofmt/gofmt_go1.18.go | 12 +++ src/cmd/gofmt/gofmt_test.go | 3 +- src/go/parser/error_test.go | 2 +- src/go/parser/interface.go | 8 +- src/go/parser/parser.go | 22 ++--- src/go/parser/short_test.go | 14 ++-- src/go/printer/printer_test.go | 17 +++- src/go/types/api.go | 10 +-- src/go/types/api_go1.18.go | 22 +++++ src/go/types/api_go1.18_test.go | 138 ++++++++++++++++++++++++++++++ src/go/types/api_test.go | 124 +-------------------------- src/go/types/builtins.go | 8 +- src/go/types/call.go | 2 +- src/go/types/check.go | 4 +- src/go/types/check_test.go | 6 +- src/go/types/decl.go | 4 +- src/go/types/expr.go | 8 +- src/go/types/infer.go | 8 +- src/go/types/lookup.go | 4 +- src/go/types/operand.go | 2 +- src/go/types/predicates.go | 22 ++--- src/go/types/sanitize.go | 8 +- src/go/types/scope.go | 4 +- src/go/types/sizes.go | 2 +- src/go/types/stmt.go | 2 +- src/go/types/subst.go | 20 ++--- src/go/types/type.go | 143 +++++++++++++++----------------- src/go/types/typestring.go | 8 +- src/go/types/typexpr.go | 14 ++-- src/go/types/unify.go | 8 +- 31 files changed, 370 insertions(+), 304 deletions(-) create mode 100644 src/cmd/gofmt/gofmt_go1.18.go create mode 100644 src/go/types/api_go1.18.go create mode 100644 src/go/types/api_go1.18_test.go diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index b82aa7e7a9..95f537d91e 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -26,13 +26,16 @@ import ( var ( // main operation modes - list = flag.Bool("l", false, "list files whose formatting differs from gofmt's") - write = flag.Bool("w", false, "write result to (source) file instead of stdout") - rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')") - simplifyAST = flag.Bool("s", false, "simplify code") - doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") - allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)") - allowTypeParams = flag.Bool("G", false, "allow generic code") + list = flag.Bool("l", false, "list files whose formatting differs from gofmt's") + write = flag.Bool("w", false, "write result to (source) file instead of stdout") + rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')") + simplifyAST = flag.Bool("s", false, "simplify code") + doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") + allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)") + + // allowTypeParams controls whether type parameters are allowed in the code + // being formatted. It is enabled for go1.18 in gofmt_go1.18.go. + allowTypeParams = false // debugging cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file") @@ -48,6 +51,10 @@ const ( // // This value is defined in go/printer specifically for go/format and cmd/gofmt. printerNormalizeNumbers = 1 << 30 + + // parseTypeParams tells go/parser to parse type parameters. Must be kept in + // sync with go/parser/interface.go. + parseTypeParams parser.Mode = 1 << 30 ) var ( @@ -72,8 +79,8 @@ func initParserMode() { if *allErrors { parserMode |= parser.AllErrors } - if *allowTypeParams { - parserMode |= parser.ParseTypeParams + if allowTypeParams { + parserMode |= parseTypeParams } } diff --git a/src/cmd/gofmt/gofmt_go1.18.go b/src/cmd/gofmt/gofmt_go1.18.go new file mode 100644 index 0000000000..be7b46b5ed --- /dev/null +++ b/src/cmd/gofmt/gofmt_go1.18.go @@ -0,0 +1,12 @@ +// Copyright 2021 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. + +//go:build go1.18 +// +build go1.18 + +package main + +func init() { + allowTypeParams = true +} diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index 60e4f2e03d..9e2239a692 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -78,7 +78,8 @@ func runTest(t *testing.T, in, out string) { // fake flag - pretend input is from stdin stdin = true case "-G": - *allowTypeParams = true + // fake flag - allow parsing type parameters + allowTypeParams = true default: t.Errorf("unrecognized flag name: %s", name) } diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go index 8e20b7b468..3caa3571e6 100644 --- a/src/go/parser/error_test.go +++ b/src/go/parser/error_test.go @@ -188,7 +188,7 @@ func TestErrors(t *testing.T) { if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) { mode := DeclarationErrors | AllErrors if strings.HasSuffix(name, ".go2") { - mode |= ParseTypeParams + mode |= parseTypeParams } checkErrors(t, filepath.Join(testdata, name), nil, mode, true) } diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go index b8b312463f..123faaee77 100644 --- a/src/go/parser/interface.go +++ b/src/go/parser/interface.go @@ -55,8 +55,14 @@ const ( Trace // print a trace of parsed productions DeclarationErrors // report declaration errors SpuriousErrors // same as AllErrors, for backward-compatibility - ParseTypeParams // Placeholder. Will control the parsing of type parameters. AllErrors = SpuriousErrors // report all errors (not just the first 10 on different lines) + + // parseTypeParams controls the parsing of type parameters. Must be + // kept in sync with: + // go/printer/printer_test.go + // go/types/check_test.go + // cmd/gofmt/gofmt.go + parseTypeParams = 1 << 30 ) // ParseFile parses the source code of a single Go source file and returns diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 5c4cea8638..ed1867b3b3 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -651,7 +651,7 @@ func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr { } typ := p.parseTypeName(ident) - if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 { + if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 { typ = p.parseTypeInstance(typ) } @@ -712,7 +712,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex // TODO(rfindley): consider changing parseRhsOrType so that this function variable // is not needed. argparser := p.parseRhsOrType - if p.mode&ParseTypeParams == 0 { + if p.mode&parseTypeParams == 0 { argparser = p.parseRhs } if p.tok != token.RBRACK { @@ -742,13 +742,13 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex // x [P]E return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt} } - if p.mode&ParseTypeParams == 0 { + if p.mode&parseTypeParams == 0 { p.error(rbrack, "missing element type in array type expression") return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()} } } - if p.mode&ParseTypeParams == 0 { + if p.mode&parseTypeParams == 0 { p.error(firstComma, "expected ']', found ','") return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()} } @@ -1045,7 +1045,7 @@ func (p *parser) parseParameters(scope *ast.Scope, acceptTParams bool) (tparams, defer un(trace(p, "Parameters")) } - if p.mode&ParseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK { + if p.mode&parseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK { opening := p.pos p.next() // [T any](params) syntax @@ -1119,7 +1119,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { x := p.parseTypeName(nil) if ident, _ := x.(*ast.Ident); ident != nil { switch { - case p.tok == token.LBRACK && p.mode&ParseTypeParams != 0: + case p.tok == token.LBRACK && p.mode&parseTypeParams != 0: // generic method or embedded instantiated type lbrack := p.pos p.next() @@ -1171,7 +1171,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { } else { // embedded, possibly instantiated type typ = x - if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 { + if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 { // embedded instantiated interface typ = p.parseTypeInstance(typ) } @@ -1193,7 +1193,7 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { lbrace := p.expect(token.LBRACE) scope := ast.NewScope(nil) // interface scope var list []*ast.Field - for p.tok == token.IDENT || p.mode&ParseTypeParams != 0 && p.tok == token.TYPE { + for p.tok == token.IDENT || p.mode&parseTypeParams != 0 && p.tok == token.TYPE { if p.tok == token.IDENT { list = append(list, p.parseMethodSpec(scope)) } else { @@ -1289,7 +1289,7 @@ func (p *parser) tryIdentOrType() ast.Expr { switch p.tok { case token.IDENT: typ := p.parseTypeName(nil) - if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 { + if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 { typ = p.parseTypeInstance(typ) } return typ @@ -1552,7 +1552,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr { return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack} } - if p.mode&ParseTypeParams == 0 { + if p.mode&parseTypeParams == 0 { p.error(firstComma, "expected ']' or ':', found ','") return &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()} } @@ -2696,7 +2696,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token p.exprLev++ x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr p.exprLev-- - if name0, _ := x.(*ast.Ident); p.mode&ParseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK { + if name0, _ := x.(*ast.Ident); p.mode&parseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK { // generic type [T any]; p.parseGenericType(spec, lbrack, name0, token.RBRACK) } else { diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 3676c27559..b21dd0aa60 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -64,8 +64,8 @@ var valids = []string{ } // validWithTParamsOnly holds source code examples that are valid if -// ParseTypeParams is set, but invalid if not. When checking with the -// ParseTypeParams set, errors are ignored. +// parseTypeParams is set, but invalid if not. When checking with the +// parseTypeParams set, errors are ignored. var validWithTParamsOnly = []string{ `package p; type _ []T[ /* ERROR "expected ';', found '\['" */ int]`, `package p; type T[P any /* ERROR "expected ']', found any" */ ] struct { P }`, @@ -131,10 +131,10 @@ func TestValid(t *testing.T) { }) t.Run("tparams", func(t *testing.T) { for _, src := range valids { - checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false) + checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, false) } for _, src := range validWithTParamsOnly { - checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false) + checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, false) } }) } @@ -142,7 +142,7 @@ func TestValid(t *testing.T) { // TestSingle is useful to track down a problem with a single short test program. func TestSingle(t *testing.T) { const src = `package p; var _ = T[P]{}` - checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true) + checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true) } var invalids = []string{ @@ -261,10 +261,10 @@ func TestInvalid(t *testing.T) { }) t.Run("tparams", func(t *testing.T) { for _, src := range invalids { - checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true) + checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true) } for _, src := range invalidTParamErrs { - checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true) + checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true) } }) } diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index 03c4badb04..e03c2df063 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -19,6 +19,10 @@ import ( "time" ) +// parseTypeParams tells go/parser to parse type parameters. Must be kept in +// sync with go/parser/interface.go. +const parseTypeParams parser.Mode = 1 << 30 + const ( dataDir = "testdata" tabwidth = 8 @@ -35,6 +39,7 @@ const ( rawFormat normNumber idempotent + allowTypeParams ) // format parses src, prints the corresponding AST, verifies the resulting @@ -42,7 +47,11 @@ const ( // if any. func format(src []byte, mode checkMode) ([]byte, error) { // parse src - f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams) + parseMode := parser.ParseComments + if mode&allowTypeParams != 0 { + parseMode |= parseTypeParams + } + f, err := parser.ParseFile(fset, "", src, parseMode) if err != nil { return nil, fmt.Errorf("parse: %s\n%s", err, src) } @@ -70,7 +79,7 @@ func format(src []byte, mode checkMode) ([]byte, error) { // make sure formatted output is syntactically correct res := buf.Bytes() - if _, err := parser.ParseFile(fset, "", res, parser.ParseTypeParams); err != nil { + if _, err := parser.ParseFile(fset, "", res, parseTypeParams); err != nil { return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes()) } @@ -201,13 +210,13 @@ var data = []entry{ {"linebreaks.input", "linebreaks.golden", idempotent}, {"expressions.input", "expressions.golden", idempotent}, {"expressions.input", "expressions.raw", rawFormat | idempotent}, - {"declarations.input", "declarations.golden", 0}, + {"declarations.input", "declarations.golden", allowTypeParams}, {"statements.input", "statements.golden", 0}, {"slow.input", "slow.golden", idempotent}, {"complit.input", "complit.x", export}, {"go2numbers.input", "go2numbers.golden", idempotent}, {"go2numbers.input", "go2numbers.norm", normNumber | idempotent}, - {"generics.input", "generics.golden", idempotent}, + {"generics.input", "generics.golden", idempotent | allowTypeParams}, {"gobuild1.input", "gobuild1.golden", idempotent}, {"gobuild2.input", "gobuild2.golden", idempotent}, {"gobuild3.input", "gobuild3.golden", idempotent}, diff --git a/src/go/types/api.go b/src/go/types/api.go index 09ac65b81f..436c23099b 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -184,11 +184,11 @@ type Info struct { // qualified identifiers are collected in the Uses map. Types map[ast.Expr]TypeAndValue - // Inferred maps calls of parameterized functions that use - // type inference to the inferred type arguments and signature + // _Inferred maps calls of parameterized functions that use + // type inference to the _Inferred type arguments and signature // of the function called. The recorded "call" expression may be // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]). - Inferred map[ast.Expr]Inferred + _Inferred map[ast.Expr]_Inferred // Defs maps identifiers to the objects they define (including // package names, dots "." of dot-imports, and blank "_" identifiers). @@ -346,9 +346,9 @@ func (tv TypeAndValue) HasOk() bool { return tv.mode == commaok || tv.mode == mapindex } -// Inferred reports the inferred type arguments and signature +// _Inferred reports the _Inferred type arguments and signature // for a parameterized function call that uses type inference. -type Inferred struct { +type _Inferred struct { Targs []Type Sig *Signature } diff --git a/src/go/types/api_go1.18.go b/src/go/types/api_go1.18.go new file mode 100644 index 0000000000..d98f4ef0dc --- /dev/null +++ b/src/go/types/api_go1.18.go @@ -0,0 +1,22 @@ +// Copyright 2021 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. + +//go:build go1.18 +// +build go1.18 + +package types + +import ( + "go/ast" +) + +type Inferred = _Inferred + +func GetInferred(info *Info) map[ast.Expr]Inferred { + return info._Inferred +} + +func SetInferred(info *Info, inferred map[ast.Expr]Inferred) { + info._Inferred = inferred +} diff --git a/src/go/types/api_go1.18_test.go b/src/go/types/api_go1.18_test.go new file mode 100644 index 0000000000..bbbf70581d --- /dev/null +++ b/src/go/types/api_go1.18_test.go @@ -0,0 +1,138 @@ +// Copyright 2021 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. + +//go:build go1.18 + +package types_test + +import ( + "fmt" + "go/ast" + "testing" + + . "go/types" +) + +func TestInferredInfo(t *testing.T) { + var tests = []struct { + src string + fun string + targs []string + sig string + }{ + {genericPkg + `p0; func f[T any](T); func _() { f(42) }`, + `f`, + []string{`int`}, + `func(int)`, + }, + {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`, + `f`, + []string{`rune`}, + `func(rune) rune`, + }, + {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`, + `f`, + []string{`complex128`}, + `func(...complex128) complex128`, + }, + {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`, + `f`, + []string{`float64`, `string`, `byte`}, + `func(float64, *string, []byte)`, + }, + {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`, + `f`, + []string{`float64`, `byte`}, + `func(float64, *byte, ...[]byte)`, + }, + + {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`, + `f`, + []string{`string`, `*string`}, + `func(x string)`, + }, + {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `*int`}, + `func(x []int)`, + }, + {genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `chan<- int`}, + `func(x []int)`, + }, + {genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, + `f`, + []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, + `func(x []int)`, + }, + + {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`, + `f`, + []string{`string`, `*string`}, + `func() string`, + }, + {genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, + `f`, + []string{`int`, `chan<- int`}, + `func() []int`, + }, + {genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, + `f`, + []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, + `func() []int`, + }, + } + + for _, test := range tests { + info := Info{} + SetInferred(&info, make(map[ast.Expr]Inferred)) + name, err := mayTypecheck(t, "InferredInfo", test.src, &info) + if err != nil { + t.Errorf("package %s: %v", name, err) + continue + } + + // look for inferred type arguments and signature + var targs []Type + var sig *Signature + for call, inf := range GetInferred(&info) { + var fun ast.Expr + switch x := call.(type) { + case *ast.CallExpr: + fun = x.Fun + case *ast.IndexExpr: + fun = x.X + default: + panic(fmt.Sprintf("unexpected call expression type %T", call)) + } + if ExprString(fun) == test.fun { + targs = inf.Targs + sig = inf.Sig + break + } + } + if targs == nil { + t.Errorf("package %s: no inferred information found for %s", name, test.fun) + continue + } + + // check that type arguments are correct + if len(targs) != len(test.targs) { + t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs)) + continue + } + for i, targ := range targs { + if got := targ.String(); got != test.targs[i] { + t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i]) + continue + } + } + + // check that signature is correct + if got := sig.String(); got != test.sig { + t.Errorf("package %s: got %s; want %s", name, got, test.sig) + } + } +} diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 20648f1cf6..0226a857bd 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -49,7 +49,7 @@ const genericPkg = "package generic_" func modeForSource(src string) parser.Mode { if strings.HasPrefix(src, genericPkg) { - return parser.ParseTypeParams + return parseTypeParams } return 0 } @@ -377,128 +377,6 @@ func TestTypesInfo(t *testing.T) { } } -func TestInferredInfo(t *testing.T) { - var tests = []struct { - src string - fun string - targs []string - sig string - }{ - {genericPkg + `p0; func f[T any](T); func _() { f(42) }`, - `f`, - []string{`int`}, - `func(int)`, - }, - {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`, - `f`, - []string{`rune`}, - `func(rune) rune`, - }, - {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`, - `f`, - []string{`complex128`}, - `func(...complex128) complex128`, - }, - {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`, - `f`, - []string{`float64`, `string`, `byte`}, - `func(float64, *string, []byte)`, - }, - {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`, - `f`, - []string{`float64`, `byte`}, - `func(float64, *byte, ...[]byte)`, - }, - - {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`, - `f`, - []string{`string`, `*string`}, - `func(x string)`, - }, - {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `*int`}, - `func(x []int)`, - }, - {genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`}, - `func(x []int)`, - }, - {genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func(x []int)`, - }, - - {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`, - `f`, - []string{`string`, `*string`}, - `func() string`, - }, - {genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`, - `f`, - []string{`int`, `chan<- int`}, - `func() []int`, - }, - {genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func() []int`, - }, - } - - for _, test := range tests { - info := Info{Inferred: make(map[ast.Expr]Inferred)} - name, err := mayTypecheck(t, "InferredInfo", test.src, &info) - if err != nil { - t.Errorf("package %s: %v", name, err) - continue - } - - // look for inferred type arguments and signature - var targs []Type - var sig *Signature - for call, inf := range info.Inferred { - var fun ast.Expr - switch x := call.(type) { - case *ast.CallExpr: - fun = x.Fun - case *ast.IndexExpr: - fun = x.X - default: - panic(fmt.Sprintf("unexpected call expression type %T", call)) - } - if ExprString(fun) == test.fun { - targs = inf.Targs - sig = inf.Sig - break - } - } - if targs == nil { - t.Errorf("package %s: no inferred information found for %s", name, test.fun) - continue - } - - // check that type arguments are correct - if len(targs) != len(test.targs) { - t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs)) - continue - } - for i, targ := range targs { - if got := targ.String(); got != test.targs[i] { - t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i]) - continue - } - } - - // check that signature is correct - if got := sig.String(); got != test.sig { - t.Errorf("package %s: got %s; want %s", name, got, test.sig) - } - } -} - func TestDefsInfo(t *testing.T) { var tests = []struct { src string diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index d45cd9b278..3df82fffda 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -179,7 +179,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b mode = value } - case *Sum: + case *_Sum: if t.is(func(t Type) bool { switch t := under(t).(type) { case *Basic: @@ -469,7 +469,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b m = 2 case *Map, *Chan: m = 1 - case *Sum: + case *_Sum: return t.is(valid) default: return false @@ -732,8 +732,8 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "", nil) - ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := NewSum(rtypes) + ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect + tsum := _NewSum(rtypes) ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/go/types/call.go b/src/go/types/call.go index e56f741370..bd10f6fbc3 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -128,7 +128,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind { } if t := asInterface(T); t != nil { check.completeInterface(token.NoPos, t) - if t.IsConstraint() { + if t._IsConstraint() { check.errorf(call, _Todo, "cannot use interface %s in conversion (contains type list or is comparable)", T) break } diff --git a/src/go/types/check.go b/src/go/types/check.go index 4cc3024de9..69e9466a8b 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -396,8 +396,8 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) { func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) { assert(call != nil) assert(sig != nil) - if m := check.Inferred; m != nil { - m[call] = Inferred{targs, sig} + if m := check._Inferred; m != nil { + m[call] = _Inferred{targs, sig} } } diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index c92855b3d8..9812b3808b 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -44,6 +44,10 @@ import ( . "go/types" ) +// parseTypeParams tells go/parser to parse type parameters. Must be kept in +// sync with go/parser/interface.go. +const parseTypeParams parser.Mode = 1 << 30 + var ( haltOnError = flag.Bool("halt", false, "halt on error") listErrors = flag.Bool("errlist", false, "list errors") @@ -210,7 +214,7 @@ func checkFiles(t *testing.T, goVersion string, filenames []string, srcs [][]byt mode := parser.AllErrors if strings.HasSuffix(filenames[0], ".go2") { - mode |= parser.ParseTypeParams + mode |= parseTypeParams } // parse files and collect parser errors diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 1134607e92..2eb2c39745 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -713,7 +713,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam setBoundAt := func(at int, bound Type) { assert(IsInterface(bound)) - tparams[at].typ.(*TypeParam).bound = bound + tparams[at].typ.(*_TypeParam).bound = bound } index := 0 @@ -756,7 +756,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName { for _, name := range names { tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil) - check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect + check.newTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position tparams = append(tparams, tpar) } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 9b51ce94b7..e1b484c410 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -660,7 +660,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const default: return nil, nil, _InvalidUntypedConversion } - case *Sum: + case *_Sum: ok := t.is(func(t Type) bool { target, _, _ := check.implicitTypeAndValue(x, t) return target != nil @@ -1517,7 +1517,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { x.expr = e return expression - case *Sum: + case *_Sum: // A sum type can be indexed if all of the sum's types // support indexing and have the same index and element // type. Special rules apply for maps in the sum type. @@ -1549,7 +1549,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { tkey = t.key e = t.elem nmaps++ - case *TypeParam: + case *_TypeParam: check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x) case *instance: panic("unimplemented") @@ -1661,7 +1661,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { valid = true // x.typ doesn't change - case *Sum, *TypeParam: + case *_Sum, *_TypeParam: check.errorf(x, 0, "generic slice expressions not yet implemented") goto Error } diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 95bd3cb378..4b20836f88 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -98,7 +98,7 @@ func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) // only parameter type it can possibly match against is a *TypeParam. // Thus, only keep the indices of generic parameters that are not of // composite types and which don't have a type inferred yet. - if tpar, _ := par.typ.(*TypeParam); tpar != nil && u.x.at(tpar.index) == nil { + if tpar, _ := par.typ.(*_TypeParam); tpar != nil && u.x.at(tpar.index) == nil { indices[j] = i j++ } @@ -201,7 +201,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { } } - case *Sum: + case *_Sum: return w.isParameterizedList(t.types) case *Signature: @@ -243,7 +243,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { case *Named: return w.isParameterizedList(t.targs) - case *TypeParam: + case *_TypeParam: // t must be one of w.tparams return t.index < len(w.tparams) && w.tparams[t.index].typ == t @@ -291,7 +291,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type) (types []Type, i // Unify type parameters with their structural constraints, if any. for _, tpar := range tparams { - typ := tpar.typ.(*TypeParam) + typ := tpar.typ.(*_TypeParam) sbound := check.structuralType(typ.bound) if sbound != nil { if !u.unify(typ, sbound) { diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index a0e7f3cc0d..3691b1ecaa 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -107,7 +107,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack var next []embeddedType // embedded types found at current depth // look for (pkg, name) in all types at current depth - var tpar *TypeParam // set if obj receiver is a type parameter + var tpar *_TypeParam // set if obj receiver is a type parameter for _, e := range current { typ := e.typ @@ -195,7 +195,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack indirect = e.indirect } - case *TypeParam: + case *_TypeParam: // only consider explicit methods in the type parameter bound, not // methods that may be common to all types in the type list. if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil { diff --git a/src/go/types/operand.go b/src/go/types/operand.go index 8f9c9d09bf..8344c059c4 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -242,7 +242,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er // x is an untyped value representable by a value of type T. if isUntyped(Vu) { - if t, ok := Tu.(*Sum); ok { + if t, ok := Tu.(*_Sum); ok { return t.is(func(t Type) bool { // TODO(gri) this could probably be more efficient ok, _ := x.assignableTo(check, t, reason) diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 0ff8fcbbf7..7bb026414f 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -14,7 +14,7 @@ import ( // isNamed may be called with types that are not fully set up. func isNamed(typ Type) bool { switch typ.(type) { - case *Basic, *Named, *TypeParam, *instance: + case *Basic, *Named, *_TypeParam, *instance: return true } return false @@ -32,7 +32,7 @@ func is(typ Type, what BasicInfo) bool { switch t := optype(typ).(type) { case *Basic: return t.info&what != 0 - case *Sum: + case *_Sum: return t.is(func(typ Type) bool { return is(typ, what) }) } return false @@ -109,7 +109,7 @@ func comparable(T Type, seen map[Type]bool) bool { // // is not comparable because []byte is not comparable. if t := asTypeParam(T); t != nil && optype(t) == theTop { - return t.Bound().IsComparable() + return t.Bound()._IsComparable() } switch t := optype(T).(type) { @@ -128,13 +128,13 @@ func comparable(T Type, seen map[Type]bool) bool { return true case *Array: return comparable(t.elem, seen) - case *Sum: + case *_Sum: pred := func(t Type) bool { return comparable(t, seen) } return t.is(pred) - case *TypeParam: - return t.Bound().IsComparable() + case *_TypeParam: + return t.Bound()._IsComparable() } return false } @@ -146,7 +146,7 @@ func hasNil(typ Type) bool { return t.kind == UnsafePointer case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: return true - case *Sum: + case *_Sum: return t.is(hasNil) } return false @@ -265,14 +265,14 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { check.identical0(x.results, y.results, cmpTags, p) } - case *Sum: + case *_Sum: // Two sum types are identical if they contain the same types. // (Sum types always consist of at least two types. Also, the // the set (list) of types in a sum type consists of unique // types - each type appears exactly once. Thus, two sum types // must contain the same number of types to have chance of // being equal. - if y, ok := y.(*Sum); ok && len(x.types) == len(y.types) { + if y, ok := y.(*_Sum); ok && len(x.types) == len(y.types) { // Every type in x.types must be in y.types. // Quadratic algorithm, but probably good enough for now. // TODO(gri) we need a fast quick type ID/hash for all types. @@ -370,7 +370,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { return x.obj == y.obj } - case *TypeParam: + case *_TypeParam: // nothing to do (x and y being equal is caught in the very beginning of this function) // case *instance: @@ -397,7 +397,7 @@ func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifaceP } for i, x := range x { y := y[i] - if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) { + if !check.identical0(x.typ.(*_TypeParam).bound, y.typ.(*_TypeParam).bound, cmpTags, p) { return false } } diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go index 3a6896c5c2..3429867321 100644 --- a/src/go/types/sanitize.go +++ b/src/go/types/sanitize.go @@ -24,7 +24,7 @@ func sanitizeInfo(info *Info) { } } - for e, inf := range info.Inferred { + for e, inf := range info._Inferred { changed := false for i, targ := range inf.Targs { if typ := s.typ(targ); typ != targ { @@ -37,7 +37,7 @@ func sanitizeInfo(info *Info) { changed = true } if changed { - info.Inferred[e] = inf + info._Inferred[e] = inf } } @@ -102,7 +102,7 @@ func (s sanitizer) typ(typ Type) Type { s.tuple(t.params) s.tuple(t.results) - case *Sum: + case *_Sum: s.typeList(t.types) case *Interface: @@ -135,7 +135,7 @@ func (s sanitizer) typ(typ Type) Type { s.typeList(t.targs) s.funcList(t.methods) - case *TypeParam: + case *_TypeParam: if bound := s.typ(t.bound); bound != t.bound { t.bound = bound } diff --git a/src/go/types/scope.go b/src/go/types/scope.go index 157b1b7066..26c28d1c4e 100644 --- a/src/go/types/scope.go +++ b/src/go/types/scope.go @@ -108,13 +108,13 @@ func (s *Scope) Insert(obj Object) Object { return nil } -// Squash merges s with its parent scope p by adding all +// squash merges s with its parent scope p by adding all // objects of s to p, adding all children of s to the // children of p, and removing s from p's children. // The function f is called for each object obj in s which // has an object alt in p. s should be discarded after // having been squashed. -func (s *Scope) Squash(err func(obj, alt Object)) { +func (s *Scope) squash(err func(obj, alt Object)) { p := s.parent assert(p != nil) for _, obj := range s.elems { diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index e8377a4f92..67052bb816 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -148,7 +148,7 @@ func (s *StdSizes) Sizeof(T Type) int64 { } offsets := s.Offsetsof(t.fields) return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) - case *Sum: + case *_Sum: panic("Sizeof unimplemented for type sum") case *Interface: return s.WordSize * 2 diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index 82c21c2a7a..27da198a85 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -907,7 +907,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) { msg = "send-only channel" } return typ.elem, Typ[Invalid], msg - case *Sum: + case *_Sum: first := true var key, val Type var msg string diff --git a/src/go/types/subst.go b/src/go/types/subst.go index ed27488503..931375f1f2 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -22,21 +22,21 @@ type substMap struct { // TODO(gri) rewrite that code, get rid of this field, and make this // struct just the map (proj) targs []Type - proj map[*TypeParam]Type + proj map[*_TypeParam]Type } // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i]. // If targs[i] is nil, tpars[i] is not substituted. func makeSubstMap(tpars []*TypeName, targs []Type) *substMap { assert(len(tpars) == len(targs)) - proj := make(map[*TypeParam]Type, len(tpars)) + proj := make(map[*_TypeParam]Type, len(tpars)) for i, tpar := range tpars { // We must expand type arguments otherwise *instance // types end up as components in composite types. // TODO(gri) explain why this causes problems, if it does targ := expand(targs[i]) // possibly nil targs[i] = targ - proj[tpar.typ.(*TypeParam)] = targ + proj[tpar.typ.(*_TypeParam)] = targ } return &substMap{targs, proj} } @@ -49,7 +49,7 @@ func (m *substMap) empty() bool { return len(m.proj) == 0 } -func (m *substMap) lookup(tpar *TypeParam) Type { +func (m *substMap) lookup(tpar *_TypeParam) Type { if t := m.proj[tpar]; t != nil { return t } @@ -121,7 +121,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // check bounds for i, tname := range tparams { - tpar := tname.typ.(*TypeParam) + tpar := tname.typ.(*_TypeParam) iface := tpar.Bound() if iface.Empty() { continue // no type bound @@ -222,7 +222,7 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type { switch t := typ.(type) { case *Basic: return typ // nothing to do - case *TypeParam: + case *_TypeParam: return smap.lookup(t) } @@ -293,13 +293,13 @@ func (subst *subster) typ(typ Type) Type { } } - case *Sum: + case *_Sum: types, copied := subst.typeList(t.types) if copied { // Don't do it manually, with a Sum literal: the new // types list may not be unique and NewSum may remove // duplicates. - return NewSum(types) + return _NewSum(types) } case *Interface: @@ -389,7 +389,7 @@ func (subst *subster) typ(typ Type) Type { // create a new named type and populate caches to avoid endless recursion tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil) - named := subst.check.NewNamed(tname, t.underlying, t.methods) // method signatures are updated lazily + named := subst.check.newNamed(tname, t.underlying, t.methods) // method signatures are updated lazily named.tparams = t.tparams // new type is still parameterized named.targs = newTargs subst.check.typMap[h] = named @@ -402,7 +402,7 @@ func (subst *subster) typ(typ Type) Type { return named - case *TypeParam: + case *_TypeParam: return subst.smap.lookup(t) case *instance: diff --git a/src/go/types/type.go b/src/go/types/type.go index 21892c9270..201da95a58 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -240,11 +240,11 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { // contain methods whose receiver type is a different interface. func (s *Signature) Recv() *Var { return s.recv } -// TParams returns the type parameters of signature s, or nil. -func (s *Signature) TParams() []*TypeName { return s.tparams } +// _TParams returns the type parameters of signature s, or nil. +func (s *Signature) _TParams() []*TypeName { return s.tparams } -// SetTParams sets the type parameters of signature s. -func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } +// _SetTParams sets the type parameters of signature s. +func (s *Signature) _SetTParams(tparams []*TypeName) { s.tparams = tparams } // Params returns the parameters of signature s, or nil. func (s *Signature) Params() *Tuple { return s.params } @@ -255,19 +255,19 @@ func (s *Signature) Results() *Tuple { return s.results } // Variadic reports whether the signature s is variadic. func (s *Signature) Variadic() bool { return s.variadic } -// A Sum represents a set of possible types. +// A _Sum represents a set of possible types. // Sums are currently used to represent type lists of interfaces // and thus the underlying types of type parameters; they are not // first class types of Go. -type Sum struct { +type _Sum struct { types []Type // types are unique } -// NewSum returns a new Sum type consisting of the provided +// _NewSum returns a new Sum type consisting of the provided // types if there are more than one. If there is exactly one // type, it returns that type. If the list of types is empty // the result is nil. -func NewSum(types []Type) Type { +func _NewSum(types []Type) Type { if len(types) == 0 { return nil } @@ -278,7 +278,7 @@ func NewSum(types []Type) Type { // current use case of type lists. // TODO(gri) Come up with the rules for sum types. for _, t := range types { - if _, ok := t.(*Sum); ok { + if _, ok := t.(*_Sum); ok { panic("sum type contains sum type - unimplemented") } } @@ -286,11 +286,11 @@ func NewSum(types []Type) Type { if len(types) == 1 { return types[0] } - return &Sum{types: types} + return &_Sum{types: types} } // is reports whether all types in t satisfy pred. -func (s *Sum) is(pred func(Type) bool) bool { +func (s *_Sum) is(pred func(Type) bool) bool { if s == nil { return false } @@ -446,8 +446,8 @@ func (t *Interface) Empty() bool { }, nil) } -// HasTypeList reports whether interface t has a type list, possibly from an embedded type. -func (t *Interface) HasTypeList() bool { +// _HasTypeList reports whether interface t has a type list, possibly from an embedded type. +func (t *Interface) _HasTypeList() bool { if t.allMethods != nil { // interface is complete - quick test return t.allTypes != nil @@ -458,8 +458,8 @@ func (t *Interface) HasTypeList() bool { }, nil) } -// IsComparable reports whether interface t is or embeds the predeclared interface "comparable". -func (t *Interface) IsComparable() bool { +// _IsComparable reports whether interface t is or embeds the predeclared interface "comparable". +func (t *Interface) _IsComparable() bool { if t.allMethods != nil { // interface is complete - quick test _, m := lookupMethod(t.allMethods, nil, "==") @@ -472,8 +472,8 @@ func (t *Interface) IsComparable() bool { }, nil) } -// IsConstraint reports t.HasTypeList() || t.IsComparable(). -func (t *Interface) IsConstraint() bool { +// _IsConstraint reports t.HasTypeList() || t.IsComparable(). +func (t *Interface) _IsConstraint() bool { if t.allMethods != nil { // interface is complete - quick test if t.allTypes != nil { @@ -667,7 +667,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { return typ } -func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { +func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) *Named { typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods} if obj.typ == nil { obj.typ = typ @@ -681,15 +681,15 @@ func (t *Named) Obj() *TypeName { return t.obj } // TODO(gri) Come up with a better representation and API to distinguish // between parameterized instantiated and non-instantiated types. -// TParams returns the type parameters of the named type t, or nil. +// _TParams returns the type parameters of the named type t, or nil. // The result is non-nil for an (originally) parameterized type even if it is instantiated. -func (t *Named) TParams() []*TypeName { return t.tparams } +func (t *Named) _TParams() []*TypeName { return t.tparams } -// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. -func (t *Named) TArgs() []Type { return t.targs } +// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated. +func (t *Named) _TArgs() []Type { return t.targs } -// SetTArgs sets the type arguments of Named. -func (t *Named) SetTArgs(args []Type) { t.targs = args } +// _SetTArgs sets the type arguments of Named. +func (t *Named) _SetTArgs(args []Type) { t.targs = args } // NumMethods returns the number of explicit methods whose receiver is named type t. func (t *Named) NumMethods() int { return len(t.methods) } @@ -715,8 +715,8 @@ func (t *Named) AddMethod(m *Func) { } } -// A TypeParam represents a type parameter type. -type TypeParam struct { +// A _TypeParam represents a type parameter type. +type _TypeParam struct { check *Checker // for lazy type bound completion id uint64 // unique id obj *TypeName // corresponding type name @@ -724,10 +724,10 @@ type TypeParam struct { bound Type // *Named or *Interface; underlying type is always *Interface } -// NewTypeParam returns a new TypeParam. -func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam { +// newTypeParam returns a new TypeParam. +func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *_TypeParam { assert(bound != nil) - typ := &TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound} + typ := &_TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound} check.nextId++ if obj.typ == nil { obj.typ = typ @@ -735,7 +735,7 @@ func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypePa return typ } -func (t *TypeParam) Bound() *Interface { +func (t *_TypeParam) Bound() *Interface { iface := asInterface(t.bound) // use the type bound position if we have one pos := token.NoPos @@ -839,40 +839,40 @@ type top struct{} var theTop = &top{} // Type-specific implementations of Underlying. -func (t *Basic) Underlying() Type { return t } -func (t *Array) Underlying() Type { return t } -func (t *Slice) Underlying() Type { return t } -func (t *Struct) Underlying() Type { return t } -func (t *Pointer) Underlying() Type { return t } -func (t *Tuple) Underlying() Type { return t } -func (t *Signature) Underlying() Type { return t } -func (t *Sum) Underlying() Type { return t } -func (t *Interface) Underlying() Type { return t } -func (t *Map) Underlying() Type { return t } -func (t *Chan) Underlying() Type { return t } -func (t *Named) Underlying() Type { return t.underlying } -func (t *TypeParam) Underlying() Type { return t } -func (t *instance) Underlying() Type { return t } -func (t *bottom) Underlying() Type { return t } -func (t *top) Underlying() Type { return t } +func (t *Basic) Underlying() Type { return t } +func (t *Array) Underlying() Type { return t } +func (t *Slice) Underlying() Type { return t } +func (t *Struct) Underlying() Type { return t } +func (t *Pointer) Underlying() Type { return t } +func (t *Tuple) Underlying() Type { return t } +func (t *Signature) Underlying() Type { return t } +func (t *_Sum) Underlying() Type { return t } +func (t *Interface) Underlying() Type { return t } +func (t *Map) Underlying() Type { return t } +func (t *Chan) Underlying() Type { return t } +func (t *Named) Underlying() Type { return t.underlying } +func (t *_TypeParam) Underlying() Type { return t } +func (t *instance) Underlying() Type { return t } +func (t *bottom) Underlying() Type { return t } +func (t *top) Underlying() Type { return t } // Type-specific implementations of String. -func (t *Basic) String() string { return TypeString(t, nil) } -func (t *Array) String() string { return TypeString(t, nil) } -func (t *Slice) String() string { return TypeString(t, nil) } -func (t *Struct) String() string { return TypeString(t, nil) } -func (t *Pointer) String() string { return TypeString(t, nil) } -func (t *Tuple) String() string { return TypeString(t, nil) } -func (t *Signature) String() string { return TypeString(t, nil) } -func (t *Sum) String() string { return TypeString(t, nil) } -func (t *Interface) String() string { return TypeString(t, nil) } -func (t *Map) String() string { return TypeString(t, nil) } -func (t *Chan) String() string { return TypeString(t, nil) } -func (t *Named) String() string { return TypeString(t, nil) } -func (t *TypeParam) String() string { return TypeString(t, nil) } -func (t *instance) String() string { return TypeString(t, nil) } -func (t *bottom) String() string { return TypeString(t, nil) } -func (t *top) String() string { return TypeString(t, nil) } +func (t *Basic) String() string { return TypeString(t, nil) } +func (t *Array) String() string { return TypeString(t, nil) } +func (t *Slice) String() string { return TypeString(t, nil) } +func (t *Struct) String() string { return TypeString(t, nil) } +func (t *Pointer) String() string { return TypeString(t, nil) } +func (t *Tuple) String() string { return TypeString(t, nil) } +func (t *Signature) String() string { return TypeString(t, nil) } +func (t *_Sum) String() string { return TypeString(t, nil) } +func (t *Interface) String() string { return TypeString(t, nil) } +func (t *Map) String() string { return TypeString(t, nil) } +func (t *Chan) String() string { return TypeString(t, nil) } +func (t *Named) String() string { return TypeString(t, nil) } +func (t *_TypeParam) String() string { return TypeString(t, nil) } +func (t *instance) String() string { return TypeString(t, nil) } +func (t *bottom) String() string { return TypeString(t, nil) } +func (t *top) String() string { return TypeString(t, nil) } // under returns the true expanded underlying type. // If it doesn't exist, the result is Typ[Invalid]. @@ -909,22 +909,11 @@ func asSlice(t Type) *Slice { return op } -// TODO (rFindley) delete this on the dev.typeparams branch. This is only -// exported in the prototype for legacy compatibility. -func AsStruct(t Type) *Struct { - return asStruct(t) -} - func asStruct(t Type) *Struct { op, _ := optype(t).(*Struct) return op } -// TODO(rFindley) delete this on the dev.typeparams branch (see ToStruct). -func AsPointer(t Type) *Pointer { - return asPointer(t) -} - func asPointer(t Type) *Pointer { op, _ := optype(t).(*Pointer) return op @@ -940,8 +929,8 @@ func asSignature(t Type) *Signature { return op } -func asSum(t Type) *Sum { - op, _ := optype(t).(*Sum) +func asSum(t Type) *_Sum { + op, _ := optype(t).(*_Sum) return op } @@ -969,7 +958,7 @@ func asNamed(t Type) *Named { return e } -func asTypeParam(t Type) *TypeParam { - u, _ := under(t).(*TypeParam) +func asTypeParam(t Type) *_TypeParam { + u, _ := under(t).(*_TypeParam) return u } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index a0caded160..fe27f0f276 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -158,7 +158,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { buf.WriteString("func") writeSignature(buf, t, qf, visited) - case *Sum: + case *_Sum: for i, t := range t.types { if i > 0 { buf.WriteString(", ") @@ -279,7 +279,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { writeTParamList(buf, t.tparams, qf, visited) } - case *TypeParam: + case *_TypeParam: s := "?" if t.obj != nil { s = t.obj.name @@ -321,7 +321,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited for i, p := range list { // TODO(rFindley) support 'any' sugar here. var b Type = &emptyInterface - if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil { + if t, _ := p.typ.(*_TypeParam); t != nil && t.bound != nil { b = t.bound } if i > 0 { @@ -334,7 +334,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited } prev = b - if t, _ := p.typ.(*TypeParam); t != nil { + if t, _ := p.typ.(*_TypeParam); t != nil { writeType(buf, t, qf, visited) } else { buf.WriteString(p.name) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 53c87f20d5..8f30a67a2f 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -146,7 +146,7 @@ func (check *Checker) ordinaryType(pos positioner, typ Type) { check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes) return } - if t.IsComparable() { + if t._IsComparable() { check.softErrorf(pos, _Todo, "interface is (or embeds) comparable") } } @@ -301,7 +301,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast } smap := makeSubstMap(recvTParams, list) for i, tname := range sig.rparams { - bound := recvTParams[i].typ.(*TypeParam).bound + bound := recvTParams[i].typ.(*_TypeParam).bound // bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the // current context. @@ -309,7 +309,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // (no bound == empty interface) if bound != nil { bound = check.subst(tname.pos, bound, smap) - tname.typ.(*TypeParam).bound = bound + tname.typ.(*_TypeParam).bound = bound } } } @@ -333,7 +333,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any params, variadic := check.collectParams(scope, ftyp.Params, nil, true) results, _ := check.collectParams(scope, ftyp.Results, nil, false) - scope.Squash(func(obj, alt Object) { + scope.squash(func(obj, alt Object) { check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name()) check.reportAltDecl(alt) }) @@ -823,7 +823,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d } // type constraints - ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types)) + ityp.types = _NewSum(check.collectTypeConstraints(iface.Pos(), types)) if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { // empty interface @@ -928,7 +928,7 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { if etyp == nil { if utyp != Typ[Invalid] { var format string - if _, ok := utyp.(*TypeParam); ok { + if _, ok := utyp.(*_TypeParam); ok { format = "%s is a type parameter, not an interface" } else { format = "%s is not an interface" @@ -987,7 +987,7 @@ func intersect(x, y Type) (r Type) { if rtypes == nil { return theBottom } - return NewSum(rtypes) + return _NewSum(rtypes) } func sortTypes(list []Type) { diff --git a/src/go/types/unify.go b/src/go/types/unify.go index ab18febbdf..fbcd64c442 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -83,7 +83,7 @@ func (d *tparamsList) init(tparams []*TypeName) { } if debug { for i, tpar := range tparams { - assert(i == tpar.typ.(*TypeParam).index) + assert(i == tpar.typ.(*_TypeParam).index) } } d.tparams = tparams @@ -131,7 +131,7 @@ func (u *unifier) join(i, j int) bool { // If typ is a type parameter of d, index returns the type parameter index. // Otherwise, the result is < 0. func (d *tparamsList) index(typ Type) int { - if t, ok := typ.(*TypeParam); ok { + if t, ok := typ.(*_TypeParam); ok { if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t { return i } @@ -335,7 +335,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { u.nify(x.results, y.results, p) } - case *Sum: + case *_Sum: // This should not happen with the current internal use of sum types. panic("type inference across sum types not implemented") @@ -431,7 +431,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } } - case *TypeParam: + case *_TypeParam: // Two type parameters (which are not part of the type parameters of the // enclosing type as those are handled in the beginning of this function) // are identical if they originate in the same declaration. -- GitLab From 580636a78a8e2462f4c5cbbac04c6403c81401ff Mon Sep 17 00:00:00 2001 From: John Bampton Date: Mon, 1 Mar 2021 09:47:09 +0000 Subject: [PATCH 0143/1298] all: fix spelling Change-Id: Iad14571c3e19b01740cd744f0b3025b3e2f1cb72 GitHub-Last-Rev: e8064019299f4e593116060ce2bbd14d62830af7 GitHub-Pull-Request: golang/go#44685 Reviewed-on: https://go-review.googlesource.com/c/go/+/297409 Trust: Alberto Donizetti Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/ir/visit.go | 8 ++++---- src/cmd/compile/internal/types2/call.go | 4 ++-- src/cmd/compile/internal/types2/typexpr.go | 4 ++-- src/go/types/call.go | 4 ++-- src/go/types/examples/types.go2 | 2 +- src/go/types/typexpr.go | 4 ++-- src/reflect/abi.go | 2 +- src/syscall/exec_windows_test.go | 2 +- test/run.go | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/ir/visit.go b/src/cmd/compile/internal/ir/visit.go index c1b3d4ed95..e4aeae3522 100644 --- a/src/cmd/compile/internal/ir/visit.go +++ b/src/cmd/compile/internal/ir/visit.go @@ -25,10 +25,10 @@ package ir // // var do func(ir.Node) bool // do = func(x ir.Node) bool { -// ... processing BEFORE visting children ... +// ... processing BEFORE visiting children ... // if ... should visit children ... { // ir.DoChildren(x, do) -// ... processing AFTER visting children ... +// ... processing AFTER visiting children ... // } // if ... should stop parent DoChildren call from visiting siblings ... { // return true @@ -43,11 +43,11 @@ package ir // // var do func(ir.Node) bool // do = func(x ir.Node) bool { -// ... processing BEFORE visting children ... +// ... processing BEFORE visiting children ... // if ... should visit children ... { // ir.DoChildren(x, do) // } -// ... processing AFTER visting children ... +// ... processing AFTER visiting children ... // return false // } // do(root) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 72805c453b..3f40a99b07 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -71,7 +71,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) { x.expr = inst return } - // all type arguments were inferred sucessfully + // all type arguments were inferred successfully if debug { for _, targ := range targs { assert(targ != nil) @@ -402,7 +402,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, args []*o return } } - // all type arguments were inferred sucessfully + // all type arguments were inferred successfully if debug { for _, targ := range targs { assert(targ != nil) diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 7190cb446a..02f9b2804d 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -426,7 +426,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] } // goTypeName returns the Go type name for typ and -// removes any occurences of "types." from that name. +// removes any occurrences of "types." from that name. func goTypeName(typ Type) string { return strings.Replace(fmt.Sprintf("%T", typ), "types.", "", -1) // strings.ReplaceAll is not available in Go 1.4 } @@ -710,7 +710,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 { } // typeList provides the list of types corresponding to the incoming expression list. -// If an error occured, the result is nil, but all list elements were type-checked. +// If an error occurred, the result is nil, but all list elements were type-checked. func (check *Checker) typeList(list []syntax.Expr) []Type { res := make([]Type, len(list)) // res != nil even if len(list) == 0 for i, x := range list { diff --git a/src/go/types/call.go b/src/go/types/call.go index bd10f6fbc3..f23ca02e1d 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -73,7 +73,7 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { x.expr = inst return } - // all type arguments were inferred sucessfully + // all type arguments were inferred successfully if debug { for _, targ := range targs { assert(targ != nil) @@ -404,7 +404,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper return } } - // all type arguments were inferred sucessfully + // all type arguments were inferred successfully if debug { for _, targ := range targs { assert(targ != nil) diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2 index 20abefbe05..59c8804ad2 100644 --- a/src/go/types/examples/types.go2 +++ b/src/go/types/examples/types.go2 @@ -146,7 +146,7 @@ func _() { // We accept parenthesized embedded struct fields so we can distinguish between // a named field with a parenthesized type foo (T) and an embedded parameterized -// type (foo(T)), similarly to interace embedding. +// type (foo(T)), similarly to interface embedding. // They still need to be valid embedded types after the parentheses are stripped // (i.e., in contrast to interfaces, we cannot embed a struct literal). The name // of the embedded field is derived as before, after stripping parentheses. diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 8f30a67a2f..63e37de4b7 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -398,7 +398,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast } // goTypeName returns the Go type name for typ and -// removes any occurences of "types." from that name. +// removes any occurrences of "types." from that name. func goTypeName(typ Type) string { return strings.ReplaceAll(fmt.Sprintf("%T", typ), "types.", "") } @@ -674,7 +674,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { } // typeList provides the list of types corresponding to the incoming expression list. -// If an error occured, the result is nil, but all list elements were type-checked. +// If an error occurred, the result is nil, but all list elements were type-checked. func (check *Checker) typeList(list []ast.Expr) []Type { res := make([]Type, len(list)) // res != nil even if len(list) == 0 for i, x := range list { diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 20f41d96b5..36d6b3095b 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -378,7 +378,7 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc { // Stack-assigned return values do not share // space with arguments like they do with registers, // so we need to inject a stack offset here. - // Fake it by artifically extending stackBytes by + // Fake it by artificially extending stackBytes by // the return offset. out.stackBytes = retOffset for i, res := range t.out() { diff --git a/src/syscall/exec_windows_test.go b/src/syscall/exec_windows_test.go index 8a1c2ceaae..fb2c767c35 100644 --- a/src/syscall/exec_windows_test.go +++ b/src/syscall/exec_windows_test.go @@ -108,7 +108,7 @@ func TestChangingProcessParent(t *testing.T) { } childOutput, err = ioutil.ReadFile(childDumpPath) if err != nil { - t.Fatalf("reading child ouput failed: %v", err) + t.Fatalf("reading child output failed: %v", err) } if got, want := string(childOutput), fmt.Sprintf("%d", parent.Process.Pid); got != want { t.Fatalf("child output: want %q, got %q", want, got) diff --git a/test/run.go b/test/run.go index 657632643e..570768e680 100644 --- a/test/run.go +++ b/test/run.go @@ -757,7 +757,7 @@ func (t *test) run() { // up and running against the existing test cases. The explicitly // listed files don't pass yet, usually because the error messages // are slightly different (this list is not complete). Any errorcheck - // tests that require output from analysis phases past intial type- + // tests that require output from analysis phases past initial type- // checking are also excluded since these phases are not running yet. // We can get rid of this code once types2 is fully plugged in. -- GitLab From 4c1a7ab49c4c68907bc7f7f7f776edd9116584a5 Mon Sep 17 00:00:00 2001 From: Baokun Lee Date: Mon, 18 Jan 2021 14:41:20 +0800 Subject: [PATCH 0144/1298] cmd/go: reject relative paths in GOMODCACHE environment Go already rejects relative paths in a couple environment variables, It should reject relative paths in GOMODCACHE. Fixes #43715 Change-Id: Id1ceff839c7ab21c00cf4ace45ce48324733a526 Reviewed-on: https://go-review.googlesource.com/c/go/+/284432 Run-TryBot: Baokun Lee TryBot-Result: Go Bot Reviewed-by: Jay Conrod Reviewed-by: Bryan C. Mills Trust: Jay Conrod Trust: Baokun Lee --- src/cmd/go/internal/envcmd/env.go | 2 +- src/cmd/go/internal/modfetch/cache.go | 31 ++++++++++++-------- src/cmd/go/internal/modfetch/fetch.go | 6 ++-- src/cmd/go/testdata/script/env_write.txt | 6 ++++ src/cmd/go/testdata/script/mod_cache_dir.txt | 11 +++++++ 5 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_cache_dir.txt diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index 6937187522..aad5d704e5 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -428,7 +428,7 @@ func checkEnvWrite(key, val string) error { return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val) } // Make sure CC and CXX are absolute paths - case "CC", "CXX": + case "CC", "CXX", "GOMODCACHE": if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) { return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val) } diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 3a2ff63721..9e751931a0 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -28,10 +28,8 @@ import ( ) func cacheDir(path string) (string, error) { - if cfg.GOMODCACHE == "" { - // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE - // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. - return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set") + if err := checkCacheDir(); err != nil { + return "", err } enc, err := module.EscapePath(path) if err != nil { @@ -64,10 +62,8 @@ func CachePath(m module.Version, suffix string) (string, error) { // along with the directory if the directory does not exist or if the directory // is not completely populated. func DownloadDir(m module.Version) (string, error) { - if cfg.GOMODCACHE == "" { - // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE - // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. - return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set") + if err := checkCacheDir(); err != nil { + return "", err } enc, err := module.EscapePath(m.Path) if err != nil { @@ -134,10 +130,8 @@ func lockVersion(mod module.Version) (unlock func(), err error) { // user's working directory. // If err is nil, the caller MUST eventually call the unlock function. func SideLock() (unlock func(), err error) { - if cfg.GOMODCACHE == "" { - // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE - // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. - base.Fatalf("go: internal error: cfg.GOMODCACHE not set") + if err := checkCacheDir(); err != nil { + base.Fatalf("go: %v", err) } path := filepath.Join(cfg.GOMODCACHE, "cache", "lock") @@ -633,3 +627,16 @@ func rewriteVersionList(dir string) { base.Fatalf("go: failed to write version list: %v", err) } } + +func checkCacheDir() error { + if cfg.GOMODCACHE == "" { + // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE + // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. + return fmt.Errorf("internal error: cfg.GOMODCACHE not set") + } + + if !filepath.IsAbs(cfg.GOMODCACHE) { + return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q.\n", cfg.GOMODCACHE) + } + return nil +} diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index c55c3cf253..d5ad277dd0 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -37,10 +37,8 @@ var downloadCache par.Cache // local download cache and returns the name of the directory // corresponding to the root of the module's file tree. func Download(ctx context.Context, mod module.Version) (dir string, err error) { - if cfg.GOMODCACHE == "" { - // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE - // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. - base.Fatalf("go: internal error: cfg.GOMODCACHE not set") + if err := checkCacheDir(); err != nil { + base.Fatalf("go: %v", err) } // The par.Cache here avoids duplicate work. diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt index bda1e57826..4fa39df104 100644 --- a/src/cmd/go/testdata/script/env_write.txt +++ b/src/cmd/go/testdata/script/env_write.txt @@ -173,3 +173,9 @@ go env -w GOOS=linux GOARCH=mips env GOOS=windows ! go env -u GOOS stderr 'unsupported GOOS/GOARCH.*windows/mips$' + +# go env -w should reject relative paths in GOMODCACHE environment. +! go env -w GOMODCACHE=~/test +stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "~/test"' +! go env -w GOMODCACHE=./test +stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "./test"' diff --git a/src/cmd/go/testdata/script/mod_cache_dir.txt b/src/cmd/go/testdata/script/mod_cache_dir.txt new file mode 100644 index 0000000000..7284ccf8ba --- /dev/null +++ b/src/cmd/go/testdata/script/mod_cache_dir.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +# Go should reject relative paths in GOMODCACHE environment. + +env GOMODCACHE="~/test" +! go get example.com/tools/cmd/hello +stderr 'must be absolute path' + +env GOMODCACHE="./test" +! go get example.com/tools/cmd/hello +stderr 'must be absolute path' -- GitLab From ebb92dfed96fadb3c563ff11cead85bbb7536793 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 1 Mar 2021 19:55:22 +0100 Subject: [PATCH 0145/1298] internal/poll, runtime: handle netpollopen error in poll_runtime_pollOpen When netpollopen in poll_runtime_pollOpen returns an error, the work in runtime_pollUnblock and runtime_pollClose can be avoided since the underlying system call to set up the poller failed. E.g. on linux, this avoids calling netpollclose and thus epoll_ctl(fd, EPOLL_CTL_DEL, ...) in case the file does not support epoll, i.e. epoll_ctl(fd, EPOLL_CTL_ADD, ...) in netpollopen failed. Fixes #44552 Change-Id: I564d90340fd1ab3a6490526353616a447ae0cfb8 Reviewed-on: https://go-review.googlesource.com/c/go/+/297392 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/internal/poll/fd_poll_runtime.go | 4 ---- src/runtime/netpoll.go | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go index beb0f7d6a6..b072af00ea 100644 --- a/src/internal/poll/fd_poll_runtime.go +++ b/src/internal/poll/fd_poll_runtime.go @@ -39,10 +39,6 @@ func (pd *pollDesc) init(fd *FD) error { serverInit.Do(runtime_pollServerInit) ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd)) if errno != 0 { - if ctx != 0 { - runtime_pollUnblock(ctx) - runtime_pollClose(ctx) - } return errnoErr(syscall.Errno(errno)) } pd.runtimeCtx = ctx diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index afb208a455..202aef593f 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -162,9 +162,12 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) { pd.self = pd unlock(&pd.lock) - var errno int32 - errno = netpollopen(fd, pd) - return pd, int(errno) + errno := netpollopen(fd, pd) + if errno != 0 { + pollcache.free(pd) + return nil, int(errno) + } + return pd, 0 } //go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose -- GitLab From 2b50ab2aee75d3c361fcd1eb39e830e2e73056b6 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Mon, 7 Dec 2020 19:15:15 +0800 Subject: [PATCH 0146/1298] cmd/compile: optimize single-precision floating point square root Add generic rule to rewrite the single-precision square root expression with one single-precision instruction. The optimization will reduce two times of precision converting between double-precision and single-precision. On arm64 flatform. previous: FCVTSD F0, F0 FSQRTD F0, F0 FCVTDS F0, F0 optimized: FSQRTS S0, S0 And this patch adds the test case to check the correctness. This patch refers to CL 241877, contributed by Alice Xu (dianhong.xu@arm.com) Change-Id: I6de5d02281c693017ac4bd4c10963dd55989bd7e Reviewed-on: https://go-review.googlesource.com/c/go/+/276873 Trust: fannie zhang Run-TryBot: fannie zhang TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/amd64/ssa.go | 4 +- src/cmd/compile/internal/arm/ssa.go | 1 + src/cmd/compile/internal/arm64/ssa.go | 1 + src/cmd/compile/internal/mips/ssa.go | 1 + src/cmd/compile/internal/mips64/ssa.go | 1 + src/cmd/compile/internal/s390x/ssa.go | 2 +- src/cmd/compile/internal/ssa/gen/386.rules | 1 + src/cmd/compile/internal/ssa/gen/386Ops.go | 1 + src/cmd/compile/internal/ssa/gen/AMD64.rules | 1 + src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/ARM.rules | 1 + src/cmd/compile/internal/ssa/gen/ARM64.rules | 2 + src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/ARMOps.go | 1 + src/cmd/compile/internal/ssa/gen/MIPS.rules | 1 + src/cmd/compile/internal/ssa/gen/MIPS64.rules | 1 + src/cmd/compile/internal/ssa/gen/MIPS64Ops.go | 1 + src/cmd/compile/internal/ssa/gen/MIPSOps.go | 1 + src/cmd/compile/internal/ssa/gen/PPC64.rules | 1 + .../compile/internal/ssa/gen/RISCV64.rules | 1 + src/cmd/compile/internal/ssa/gen/S390X.rules | 2 + src/cmd/compile/internal/ssa/gen/S390XOps.go | 1 + src/cmd/compile/internal/ssa/gen/Wasm.rules | 2 + src/cmd/compile/internal/ssa/gen/WasmOps.go | 14 +- .../compile/internal/ssa/gen/generic.rules | 3 + .../compile/internal/ssa/gen/genericOps.go | 5 +- src/cmd/compile/internal/ssa/opGen.go | 134 ++++++++++++++++-- src/cmd/compile/internal/ssa/rewrite386.go | 3 + src/cmd/compile/internal/ssa/rewriteAMD64.go | 3 + src/cmd/compile/internal/ssa/rewriteARM.go | 3 + src/cmd/compile/internal/ssa/rewriteARM64.go | 3 + src/cmd/compile/internal/ssa/rewriteMIPS.go | 3 + src/cmd/compile/internal/ssa/rewriteMIPS64.go | 3 + src/cmd/compile/internal/ssa/rewritePPC64.go | 3 + .../compile/internal/ssa/rewriteRISCV64.go | 3 + src/cmd/compile/internal/ssa/rewriteS390X.go | 3 + src/cmd/compile/internal/ssa/rewriteWasm.go | 3 + .../compile/internal/ssa/rewritegeneric.go | 20 +++ src/cmd/compile/internal/x86/ssa.go | 2 +- src/math/all_test.go | 34 +++++ test/codegen/math.go | 11 ++ 41 files changed, 255 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 32cb0a9368..d83d78f080 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -1053,7 +1053,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg0() - case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD: + case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD, ssa.OpAMD64SQRTSS: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() @@ -1061,7 +1061,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { switch v.Op { case ssa.OpAMD64BSFQ, ssa.OpAMD64BSRQ: p.To.Reg = v.Reg0() - case ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD: + case ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD, ssa.OpAMD64SQRTSS: p.To.Reg = v.Reg() } case ssa.OpAMD64ROUNDSD: diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go index c4d8cbf149..7b2fec3765 100644 --- a/src/cmd/compile/internal/arm/ssa.go +++ b/src/cmd/compile/internal/arm/ssa.go @@ -654,6 +654,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARMREV, ssa.OpARMREV16, ssa.OpARMRBIT, + ssa.OpARMSQRTF, ssa.OpARMSQRTD, ssa.OpARMNEGF, ssa.OpARMNEGD, diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 5067d92dfe..056a6eb62d 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -893,6 +893,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARM64FMOVSgpfp, ssa.OpARM64FNEGS, ssa.OpARM64FNEGD, + ssa.OpARM64FSQRTS, ssa.OpARM64FSQRTD, ssa.OpARM64FCVTZSSW, ssa.OpARM64FCVTZSDW, diff --git a/src/cmd/compile/internal/mips/ssa.go b/src/cmd/compile/internal/mips/ssa.go index 115e3cb8e2..13736d12b4 100644 --- a/src/cmd/compile/internal/mips/ssa.go +++ b/src/cmd/compile/internal/mips/ssa.go @@ -363,6 +363,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpMIPSMOVDF, ssa.OpMIPSNEGF, ssa.OpMIPSNEGD, + ssa.OpMIPSSQRTF, ssa.OpMIPSSQRTD, ssa.OpMIPSCLZ: p := s.Prog(v.Op.Asm()) diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go index d9c47751e1..c5a3ca305a 100644 --- a/src/cmd/compile/internal/mips64/ssa.go +++ b/src/cmd/compile/internal/mips64/ssa.go @@ -355,6 +355,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpMIPS64MOVDF, ssa.OpMIPS64NEGF, ssa.OpMIPS64NEGD, + ssa.OpMIPS64SQRTF, ssa.OpMIPS64SQRTD: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index 4830d902c2..ca6720bb33 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -586,7 +586,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.Reg = v.Args[1].Reg() p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpS390XFSQRT: + case ssa.OpS390XFSQRTS, ssa.OpS390XFSQRT: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index df03cb71a6..d6d122dc78 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -54,6 +54,7 @@ (Bswap32 ...) => (BSWAPL ...) (Sqrt ...) => (SQRTSD ...) +(Sqrt32 ...) => (SQRTSS ...) (Ctz16 x) => (BSFL (ORLconst [0x10000] x)) (Ctz16NonZero ...) => (BSFL ...) diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go index 2b7185e537..c4b49fbb23 100644 --- a/src/cmd/compile/internal/ssa/gen/386Ops.go +++ b/src/cmd/compile/internal/ssa/gen/386Ops.go @@ -308,6 +308,7 @@ func init() { {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes {name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0) + {name: "SQRTSS", argLength: 1, reg: fp11, asm: "SQRTSS"}, // sqrt(arg0), float32 {name: "SBBLcarrymask", argLength: 1, reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear. // Note: SBBW and SBBB are subsumed by SBBL diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index f2bcbd2dfc..bab9cee88c 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -104,6 +104,7 @@ (PopCount8 x) => (POPCNTL (MOVBQZX x)) (Sqrt ...) => (SQRTSD ...) +(Sqrt32 ...) => (SQRTSS ...) (RoundToEven x) => (ROUNDSD [0] x) (Floor x) => (ROUNDSD [1] x) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 96475672a8..fd2c2023e6 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -594,6 +594,7 @@ func init() { {name: "POPCNTL", argLength: 1, reg: gp11, asm: "POPCNTL", clobberFlags: true}, // count number of set bits in arg0 {name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0) + {name: "SQRTSS", argLength: 1, reg: fp11, asm: "SQRTSS"}, // sqrt(arg0), float32 // ROUNDSD instruction isn't guaranteed to be on the target platform (it is SSE4.1) // Any use must be preceded by a successful check of runtime.x86HasSSE41. diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index cbafd12a4f..f46f4238f7 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -56,6 +56,7 @@ (Com(32|16|8) ...) => (MVN ...) (Sqrt ...) => (SQRTD ...) +(Sqrt32 ...) => (SQRTF ...) (Abs ...) => (ABSD ...) // TODO: optimize this for ARMv5 and ARMv6 diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 98503748db..ea912f9f97 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -60,6 +60,8 @@ (Trunc ...) => (FRINTZD ...) (FMA x y z) => (FMADDD z x y) +(Sqrt32 ...) => (FSQRTS ...) + // lowering rotates (RotateLeft8 x (MOVDconst [c])) => (Or8 (Lsh8x64 x (MOVDconst [c&7])) (Rsh8Ux64 x (MOVDconst [-c&7]))) (RotateLeft16 x (MOVDconst [c])) => (Or16 (Lsh16x64 x (MOVDconst [c&15])) (Rsh16Ux64 x (MOVDconst [-c&15]))) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index e826e75252..0a4fd14b2b 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -236,6 +236,7 @@ func init() { {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS"}, // -arg0, float32 {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD"}, // -arg0, float64 {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD"}, // sqrt(arg0), float64 + {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0), float32 {name: "REV", argLength: 1, reg: gp11, asm: "REV"}, // byte reverse, 64-bit {name: "REVW", argLength: 1, reg: gp11, asm: "REVW"}, // byte reverse, 32-bit {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W"}, // byte reverse in each 16-bit halfword, 32-bit diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go index 70c789937a..253ff573ec 100644 --- a/src/cmd/compile/internal/ssa/gen/ARMOps.go +++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go @@ -217,6 +217,7 @@ func init() { {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 + {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32 {name: "ABSD", argLength: 1, reg: fp11, asm: "ABSD"}, // abs(arg0), float64 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index bc1ce82940..6b59555cbe 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -121,6 +121,7 @@ (Com(32|16|8) x) => (NORconst [0] x) (Sqrt ...) => (SQRTD ...) +(Sqrt32 ...) => (SQRTF ...) // TODO: optimize this case? (Ctz32NonZero ...) => (Ctz32 ...) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules index e3f7633274..bc51a0d53d 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules @@ -121,6 +121,7 @@ (Com(64|32|16|8) x) => (NOR (MOVVconst [0]) x) (Sqrt ...) => (SQRTD ...) +(Sqrt32 ...) => (SQRTF ...) // boolean ops -- booleans are represented with 0=false, 1=true (AndB ...) => (AND ...) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go index e1e3933502..77f251c0d3 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go @@ -199,6 +199,7 @@ func init() { {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 + {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32 // shifts {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go index 75ab99ea26..b92e8cb9f1 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPSOps.go +++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.go @@ -182,6 +182,7 @@ func init() { {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 + {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32 // shifts {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 32 diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index a762be65d4..85ce9a5b54 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -71,6 +71,7 @@ (Round(32|64)F ...) => (LoweredRound(32|64)F ...) (Sqrt ...) => (FSQRT ...) +(Sqrt32 ...) => (FSQRTS ...) (Floor ...) => (FFLOOR ...) (Ceil ...) => (FCEIL ...) (Trunc ...) => (FTRUNC ...) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules index 9119ebc0e8..a11d1e6624 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules @@ -92,6 +92,7 @@ (Com8 ...) => (NOT ...) (Sqrt ...) => (FSQRTD ...) +(Sqrt32 ...) => (FSQRTS ...) // Sign and zero extension. diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index 7111d5e11a..e4a1cd6981 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -142,6 +142,8 @@ (Round x) => (FIDBR [1] x) (FMA x y z) => (FMADD z x y) +(Sqrt32 ...) => (FSQRTS ...) + // Atomic loads and stores. // The SYNC instruction (fast-BCR-serialization) prevents store-load // reordering. Other sequences of memory operations (load-load, diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go index b24fd61942..1ddad1febd 100644 --- a/src/cmd/compile/internal/ssa/gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go @@ -382,6 +382,7 @@ func init() { {name: "NOTW", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) + {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0), float32 // Conditional register-register moves. // The aux for these values is an s390x.CCMask value representing the condition code mask. diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index fc45cd3ed5..7cda16b4b5 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -332,6 +332,8 @@ (Abs ...) => (F64Abs ...) (Copysign ...) => (F64Copysign ...) +(Sqrt32 ...) => (F32Sqrt ...) + (Ctz64 ...) => (I64Ctz ...) (Ctz32 x) => (I64Ctz (I64Or x (I64Const [0x100000000]))) (Ctz16 x) => (I64Ctz (I64Or x (I64Const [0x10000]))) diff --git a/src/cmd/compile/internal/ssa/gen/WasmOps.go b/src/cmd/compile/internal/ssa/gen/WasmOps.go index 36c53bc78c..c92878ca73 100644 --- a/src/cmd/compile/internal/ssa/gen/WasmOps.go +++ b/src/cmd/compile/internal/ssa/gen/WasmOps.go @@ -238,13 +238,13 @@ func init() { {name: "I64Extend16S", asm: "I64Extend16S", argLength: 1, reg: gp11, typ: "Int64"}, // sign-extend arg0 from 16 to 64 bit {name: "I64Extend32S", asm: "I64Extend32S", argLength: 1, reg: gp11, typ: "Int64"}, // sign-extend arg0 from 32 to 64 bit - {name: "F32Sqrt", asm: "F32Sqrt", argLength: 1, reg: fp64_11, typ: "Float32"}, // sqrt(arg0) - {name: "F32Trunc", asm: "F32Trunc", argLength: 1, reg: fp64_11, typ: "Float32"}, // trunc(arg0) - {name: "F32Ceil", asm: "F32Ceil", argLength: 1, reg: fp64_11, typ: "Float32"}, // ceil(arg0) - {name: "F32Floor", asm: "F32Floor", argLength: 1, reg: fp64_11, typ: "Float32"}, // floor(arg0) - {name: "F32Nearest", asm: "F32Nearest", argLength: 1, reg: fp64_11, typ: "Float32"}, // round(arg0) - {name: "F32Abs", asm: "F32Abs", argLength: 1, reg: fp64_11, typ: "Float32"}, // abs(arg0) - {name: "F32Copysign", asm: "F32Copysign", argLength: 2, reg: fp64_21, typ: "Float32"}, // copysign(arg0, arg1) + {name: "F32Sqrt", asm: "F32Sqrt", argLength: 1, reg: fp32_11, typ: "Float32"}, // sqrt(arg0) + {name: "F32Trunc", asm: "F32Trunc", argLength: 1, reg: fp32_11, typ: "Float32"}, // trunc(arg0) + {name: "F32Ceil", asm: "F32Ceil", argLength: 1, reg: fp32_11, typ: "Float32"}, // ceil(arg0) + {name: "F32Floor", asm: "F32Floor", argLength: 1, reg: fp32_11, typ: "Float32"}, // floor(arg0) + {name: "F32Nearest", asm: "F32Nearest", argLength: 1, reg: fp32_11, typ: "Float32"}, // round(arg0) + {name: "F32Abs", asm: "F32Abs", argLength: 1, reg: fp32_11, typ: "Float32"}, // abs(arg0) + {name: "F32Copysign", asm: "F32Copysign", argLength: 2, reg: fp32_21, typ: "Float32"}, // copysign(arg0, arg1) {name: "F64Sqrt", asm: "F64Sqrt", argLength: 1, reg: fp64_11, typ: "Float64"}, // sqrt(arg0) {name: "F64Trunc", asm: "F64Trunc", argLength: 1, reg: fp64_11, typ: "Float64"}, // trunc(arg0) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index fab45243ed..9dd20a7cfa 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -1968,6 +1968,9 @@ (Div32F x (Const32F [c])) && reciprocalExact32(c) => (Mul32F x (Const32F [1/c])) (Div64F x (Const64F [c])) && reciprocalExact64(c) => (Mul64F x (Const64F [1/c])) +// rewrite single-precision sqrt expression "float32(math.Sqrt(float64(x)))" +(Cvt64Fto32F sqrt0:(Sqrt (Cvt32Fto64F x))) && sqrt0.Uses==1 => (Sqrt32 x) + (Sqrt (Const64F [c])) && !math.IsNaN(math.Sqrt(c)) => (Const64F [math.Sqrt(c)]) // for rewriting results of some late-expanded rewrites (below) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 043f445c16..b730c436cf 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -258,13 +258,14 @@ var genericOps = []opData{ {name: "RotateLeft32", argLength: 2}, // Rotate bits in arg[0] left by arg[1] {name: "RotateLeft64", argLength: 2}, // Rotate bits in arg[0] left by arg[1] - // Square root, float64 only. + // Square root. // Special cases: // +∞ → +∞ // ±0 → ±0 (sign preserved) // x<0 → NaN // NaN → NaN - {name: "Sqrt", argLength: 1}, // √arg0 + {name: "Sqrt", argLength: 1}, // √arg0 (floating point, double precision) + {name: "Sqrt32", argLength: 1}, // √arg0 (floating point, single precision) // Round to integer, float64 only. // Special cases: diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 2d37ae4357..bd9741fe3e 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -432,6 +432,7 @@ const ( Op386BSRW Op386BSWAPL Op386SQRTSD + Op386SQRTSS Op386SBBLcarrymask Op386SETEQ Op386SETNE @@ -888,6 +889,7 @@ const ( OpAMD64POPCNTQ OpAMD64POPCNTL OpAMD64SQRTSD + OpAMD64SQRTSS OpAMD64ROUNDSD OpAMD64VFMADD231SD OpAMD64SBBQcarrymask @@ -1090,6 +1092,7 @@ const ( OpARMNEGF OpARMNEGD OpARMSQRTD + OpARMSQRTF OpARMABSD OpARMCLZ OpARMREV @@ -1358,6 +1361,7 @@ const ( OpARM64FNEGS OpARM64FNEGD OpARM64FSQRTD + OpARM64FSQRTS OpARM64REV OpARM64REVW OpARM64REV16W @@ -1641,6 +1645,7 @@ const ( OpMIPSNEGF OpMIPSNEGD OpMIPSSQRTD + OpMIPSSQRTF OpMIPSSLL OpMIPSSLLconst OpMIPSSRL @@ -1751,6 +1756,7 @@ const ( OpMIPS64NEGF OpMIPS64NEGD OpMIPS64SQRTD + OpMIPS64SQRTF OpMIPS64SLLV OpMIPS64SLLVconst OpMIPS64SRLV @@ -2301,6 +2307,7 @@ const ( OpS390XNOT OpS390XNOTW OpS390XFSQRT + OpS390XFSQRTS OpS390XLOCGR OpS390XMOVBreg OpS390XMOVBZreg @@ -2727,6 +2734,7 @@ const ( OpRotateLeft32 OpRotateLeft64 OpSqrt + OpSqrt32 OpFloor OpCeil OpTrunc @@ -4778,6 +4786,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "SQRTSS", + argLen: 1, + asm: x86.ASQRTSS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + }, + outputs: []outputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + }, + }, + }, { name: "SBBLcarrymask", argLen: 1, @@ -11630,6 +11651,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "SQRTSS", + argLen: 1, + asm: x86.ASQRTSS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, { name: "ROUNDSD", auxType: auxInt8, @@ -14424,6 +14458,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "SQRTF", + argLen: 1, + asm: arm.ASQRTF, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 + }, + outputs: []outputInfo{ + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 + }, + }, + }, { name: "ABSD", argLen: 1, @@ -18086,6 +18133,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FSQRTS", + argLen: 1, + asm: arm64.AFSQRTS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "REV", argLen: 1, @@ -21879,6 +21939,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "SQRTF", + argLen: 1, + asm: mips.ASQRTF, + reg: regInfo{ + inputs: []inputInfo{ + {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 + }, + outputs: []outputInfo{ + {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 + }, + }, + }, { name: "SLL", argLen: 2, @@ -23358,6 +23431,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "SQRTF", + argLen: 1, + asm: mips.ASQRTF, + reg: regInfo{ + inputs: []inputInfo{ + {0, 1152921504338411520}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + outputs: []outputInfo{ + {0, 1152921504338411520}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "SLLV", argLen: 2, @@ -30942,6 +31028,19 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FSQRTS", + argLen: 1, + asm: s390x.AFSQRTS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 + }, + outputs: []outputInfo{ + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 + }, + }, + }, { name: "LOCGR", auxType: auxS390XCCMask, @@ -33876,10 +33975,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Sqrt, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33889,10 +33988,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Trunc, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33902,10 +34001,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Ceil, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33915,10 +34014,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Floor, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33928,10 +34027,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Nearest, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33941,10 +34040,10 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Abs, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -33954,11 +34053,11 @@ var opcodeTable = [...]opInfo{ asm: wasm.AF32Copysign, reg: regInfo{ inputs: []inputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 - {1, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 + {1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, outputs: []outputInfo{ - {0, 281470681743360}, // F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 }, }, }, @@ -35176,6 +35275,11 @@ var opcodeTable = [...]opInfo{ argLen: 1, generic: true, }, + { + name: "Sqrt32", + argLen: 1, + generic: true, + }, { name: "Floor", argLen: 1, diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 4e7fdb9e63..726d68e243 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -620,6 +620,9 @@ func rewriteValue386(v *Value) bool { case OpSqrt: v.Op = Op386SQRTSD return true + case OpSqrt32: + v.Op = Op386SQRTSS + return true case OpStaticCall: v.Op = Op386CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 599137c806..52d0fd095d 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1089,6 +1089,9 @@ func rewriteValueAMD64(v *Value) bool { case OpSqrt: v.Op = OpAMD64SQRTSD return true + case OpSqrt32: + v.Op = OpAMD64SQRTSS + return true case OpStaticCall: v.Op = OpAMD64CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 1adbceb0ad..ed1f85e340 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -823,6 +823,9 @@ func rewriteValueARM(v *Value) bool { case OpSqrt: v.Op = OpARMSQRTD return true + case OpSqrt32: + v.Op = OpARMSQRTF + return true case OpStaticCall: v.Op = OpARMCALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index ece834f996..55bb486600 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -999,6 +999,9 @@ func rewriteValueARM64(v *Value) bool { case OpSqrt: v.Op = OpARM64FSQRTD return true + case OpSqrt32: + v.Op = OpARM64FSQRTS + return true case OpStaticCall: v.Op = OpARM64CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index 0c074364df..fdf329cbd0 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -516,6 +516,9 @@ func rewriteValueMIPS(v *Value) bool { case OpSqrt: v.Op = OpMIPSSQRTD return true + case OpSqrt32: + v.Op = OpMIPSSQRTF + return true case OpStaticCall: v.Op = OpMIPSCALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index 073cf8726c..541bdd694a 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -596,6 +596,9 @@ func rewriteValueMIPS64(v *Value) bool { case OpSqrt: v.Op = OpMIPS64SQRTD return true + case OpSqrt32: + v.Op = OpMIPS64SQRTF + return true case OpStaticCall: v.Op = OpMIPS64CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 98f748e5fa..3357864291 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -743,6 +743,9 @@ func rewriteValuePPC64(v *Value) bool { case OpSqrt: v.Op = OpPPC64FSQRT return true + case OpSqrt32: + v.Op = OpPPC64FSQRTS + return true case OpStaticCall: v.Op = OpPPC64CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index bc47d76e87..36e152bd99 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -582,6 +582,9 @@ func rewriteValueRISCV64(v *Value) bool { case OpSqrt: v.Op = OpRISCV64FSQRTD return true + case OpSqrt32: + v.Op = OpRISCV64FSQRTS + return true case OpStaticCall: v.Op = OpRISCV64CALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index 6adae3ff35..e0a5ff4cbb 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -792,6 +792,9 @@ func rewriteValueS390X(v *Value) bool { case OpSqrt: v.Op = OpS390XFSQRT return true + case OpSqrt32: + v.Op = OpS390XFSQRTS + return true case OpStaticCall: v.Op = OpS390XCALLstatic return true diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index c8ecefc736..7258bc4f8e 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -527,6 +527,9 @@ func rewriteValueWasm(v *Value) bool { case OpSqrt: v.Op = OpWasmF64Sqrt return true + case OpSqrt32: + v.Op = OpWasmF32Sqrt + return true case OpStaticCall: v.Op = OpWasmLoweredStaticCall return true diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index e5a27199a7..7e7cf458ff 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -4085,6 +4085,26 @@ func rewriteValuegeneric_OpCvt64Fto32F(v *Value) bool { v.AuxInt = float32ToAuxInt(float32(c)) return true } + // match: (Cvt64Fto32F sqrt0:(Sqrt (Cvt32Fto64F x))) + // cond: sqrt0.Uses==1 + // result: (Sqrt32 x) + for { + sqrt0 := v_0 + if sqrt0.Op != OpSqrt { + break + } + sqrt0_0 := sqrt0.Args[0] + if sqrt0_0.Op != OpCvt32Fto64F { + break + } + x := sqrt0_0.Args[0] + if !(sqrt0.Uses == 1) { + break + } + v.reset(OpSqrt32) + v.AddArg(x) + return true + } return false } func rewriteValuegeneric_OpCvt64Fto64(v *Value) bool { diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index 4d134c6926..62982f4c6d 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -760,7 +760,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = v.Reg() case ssa.Op386BSFL, ssa.Op386BSFW, ssa.Op386BSRL, ssa.Op386BSRW, - ssa.Op386SQRTSD: + ssa.Op386SQRTSS, ssa.Op386SQRTSD: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() diff --git a/src/math/all_test.go b/src/math/all_test.go index 3aae0373c7..d154457999 100644 --- a/src/math/all_test.go +++ b/src/math/all_test.go @@ -2067,6 +2067,21 @@ var fmaC = []struct{ x, y, z, want float64 }{ {-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308}, } +var sqrt32 = []float32{ + 0, + float32(Copysign(0, -1)), + float32(NaN()), + float32(Inf(1)), + float32(Inf(-1)), + 1, + 2, + -2, + 4.9790119248836735e+00, + 7.7388724745781045e+00, + -2.7688005719200159e-01, + -5.0106036182710749e+00, +} + func tolerance(a, b, e float64) bool { // Multiplying by e here can underflow denormal values to zero. // Check a==b so that at least if a and b are small and identical @@ -3181,6 +3196,25 @@ func TestFloatMinMax(t *testing.T) { } } +var indirectSqrt = Sqrt + +// TestFloat32Sqrt checks the correctness of the float32 square root optimization result. +func TestFloat32Sqrt(t *testing.T) { + for _, v := range sqrt32 { + want := float32(indirectSqrt(float64(v))) + got := float32(Sqrt(float64(v))) + if IsNaN(float64(want)) { + if !IsNaN(float64(got)) { + t.Errorf("got=%#v want=NaN, v=%#v", got, v) + } + continue + } + if got != want { + t.Errorf("got=%#v want=%#v, v=%#v", got, want, v) + } + } +} + // Benchmarks // Global exported variables are used to store the diff --git a/test/codegen/math.go b/test/codegen/math.go index ac8071400e..243ddb0494 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -55,6 +55,17 @@ func sqrt(x float64) float64 { return math.Sqrt(x) } +func sqrt32(x float32) float32 { + // amd64:"SQRTSS" + // 386/sse2:"SQRTSS" 386/softfloat:-"SQRTS" + // arm64:"FSQRTS" + // arm/7:"SQRTF" + // mips/hardfloat:"SQRTF" mips/softfloat:-"SQRTF" + // mips64/hardfloat:"SQRTF" mips64/softfloat:-"SQRTF" + // wasm:"F32Sqrt" + return float32(math.Sqrt(float64(x))) +} + // Check that it's using integer registers func abs(x, y float64) { // amd64:"BTRQ\t[$]63" -- GitLab From 97b32a6724ebc3a6029e06b6c4b3acb9c980b15a Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 1 Mar 2021 17:31:20 -0500 Subject: [PATCH 0147/1298] cmd/compile: better version of check frame offsets against abi improved to run on more architectures. this is in preparation for turning off calculation of frame offsets in types.CalcSize. Replaces https://go-review.googlesource.com/c/go/+/293392 . Updates #44675. For #40724. Change-Id: I40ba496172447cf09b86bc646148859363c11ad9 Reviewed-on: https://go-review.googlesource.com/c/go/+/297637 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 54 ++++++++++++--- src/cmd/compile/internal/gc/compile.go | 3 + src/cmd/compile/internal/ssa/config.go | 4 +- src/cmd/compile/internal/ssa/op.go | 28 +++++--- src/cmd/compile/internal/ssagen/ssa.go | 67 ++++++++++++------- .../compile/internal/test/abiutils_test.go | 2 +- .../compile/internal/test/abiutilsaux_test.go | 32 --------- 7 files changed, 112 insertions(+), 78 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index b43d95e976..a5c85a89fb 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -52,12 +52,12 @@ func (a *ABIParamResultInfo) OutRegistersUsed() int { return a.outRegistersUsed } -func (a *ABIParamResultInfo) InParam(i int) ABIParamAssignment { - return a.inparams[i] +func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment { + return &a.inparams[i] } -func (a *ABIParamResultInfo) OutParam(i int) ABIParamAssignment { - return a.outparams[i] +func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment { + return &a.outparams[i] } func (a *ABIParamResultInfo) SpillAreaOffset() int64 { @@ -111,6 +111,18 @@ func (a *ABIParamAssignment) SpillOffset() int32 { return a.offset } +// FrameOffset returns the location that a value would spill to, if any exists. +// For register-allocated inputs, that is their spill offset reserved for morestack +// (might as well use it, it is there); for stack-allocated inputs and outputs, +// that is their location on the stack. For register-allocated outputs, there is +// no defined spill area, so return -1. +func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 { + if len(a.Registers) == 0 || a.offset == -1 { + return int64(a.offset) + } + return int64(a.offset) + i.SpillAreaOffset() +} + // RegAmounts holds a specified number of integer/float registers. type RegAmounts struct { intRegs int @@ -121,14 +133,15 @@ type RegAmounts struct { // by the ABI rules for parameter passing and result returning. type ABIConfig struct { // Do we need anything more than this? + offsetForLocals int64 // e.g., obj.(*Link).FixedFrameSize() -- extra linkage information on some architectures. regAmounts RegAmounts regsForTypeCache map[*types.Type]int } // NewABIConfig returns a new ABI configuration for an architecture with // iRegsCount integer/pointer registers and fRegsCount floating point registers. -func NewABIConfig(iRegsCount, fRegsCount int) *ABIConfig { - return &ABIConfig{regAmounts: RegAmounts{iRegsCount, fRegsCount}, regsForTypeCache: make(map[*types.Type]int)} +func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64) *ABIConfig { + return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}, regsForTypeCache: make(map[*types.Type]int)} } // Copy returns a copy of an ABIConfig for use in a function's compilation so that access to the cache does not need to be protected with a mutex. @@ -190,7 +203,8 @@ func (a *ABIParamResultInfo) preAllocateParams(hasRcvr bool, nIns, nOuts int) { func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Type) *ABIParamResultInfo { setup() s := assignState{ - rTotal: config.regAmounts, + stackOffset: config.offsetForLocals, + rTotal: config.regAmounts, } result := &ABIParamResultInfo{config: config} result.preAllocateParams(rcvr != nil, len(ins), len(outs)) @@ -230,7 +244,8 @@ func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Ty func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { setup() s := assignState{ - rTotal: config.regAmounts, + stackOffset: config.offsetForLocals, + rTotal: config.regAmounts, } result := &ABIParamResultInfo{config: config} ft := t.FuncType() @@ -265,9 +280,32 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + // Fill in the frame offsets for receiver, inputs, results + k := 0 + if t.NumRecvs() != 0 { + config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false) + k++ + } + for i, f := range ft.Params.FieldSlice() { + config.updateOffset(result, f, result.inparams[k+i], false) + } + for i, f := range ft.Results.FieldSlice() { + config.updateOffset(result, f, result.outparams[i], true) + } return result } +func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) { + if !isReturn || len(a.Registers) == 0 { + // TODO in next CL, assign + if f.Offset+config.offsetForLocals != a.FrameOffset(result) { + if config.regAmounts.intRegs == 0 && config.regAmounts.floatRegs == 0 { + panic(fmt.Errorf("Expected node offset %d != abi offset %d", f.Offset, a.FrameOffset(result))) + } + } + } +} + //...................................................................... // // Non-public portions. diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index ba67c58c45..2d7a74a403 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -43,6 +43,9 @@ func enqueueFunc(fn *ir.Func) { if len(fn.Body) == 0 { // Initialize ABI wrappers if necessary. ssagen.InitLSym(fn, false) + types.CalcSize(fn.Type()) // TODO register args; remove this once all is done by abiutils + a := ssagen.AbiForFunc(fn) + a.ABIAnalyze(fn.Type()) // will set parameter spill/home locations correctly liveness.WriteFuncMap(fn) return } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 07508d6e83..9921b51cc7 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -333,8 +333,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config c.useSSE = true c.UseFMA = true - c.ABI0 = abi.NewABIConfig(0, 0) - c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs)) + c.ABI0 = abi.NewABIConfig(0, 0, ctxt.FixedFrameSize()) + c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.FixedFrameSize()) // On Plan 9, floating point operations are not allowed in note handler. if objabi.GOOS == "plan9" { diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index ece274b083..6d2ca96293 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -104,13 +104,23 @@ func (a *AuxCall) ResultForOffsetAndType(offset int64, t *types.Type) int64 { // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { - return int64(a.results[which].Offset) + o := int64(a.results[which].Offset) + n := int64(a.abiInfo.OutParam(int(which)).Offset()) + if o != n { + panic(fmt.Errorf("Result old=%d, new=%d, auxcall=%s, oparams=%v", o, n, a, a.abiInfo.OutParams())) + } + return int64(a.abiInfo.OutParam(int(which)).Offset()) } // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) OffsetOfArg(which int64) int64 { - return int64(a.args[which].Offset) + o := int64(a.args[which].Offset) + n := int64(a.abiInfo.InParam(int(which)).Offset()) + if o != n { + panic(fmt.Errorf("Arg old=%d, new=%d, auxcall=%s, iparams=%v", o, n, a, a.abiInfo.InParams())) + } + return int64(a.abiInfo.InParam(int(which)).Offset()) } // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). @@ -206,6 +216,9 @@ func (a *AuxCall) String() string { return fn + "}" } +// ACParamsToTypes translates a slice of Param into a slice of *types.Type +// This is a helper call for ssagen/ssa.go. +// TODO remove this, as part of replacing fields of AuxCall with abi.ABIParamResultInfo. func ACParamsToTypes(ps []Param) (ts []*types.Type) { for _, p := range ps { ts = append(ts, p.Type) @@ -215,7 +228,6 @@ func ACParamsToTypes(ps []Param) (ts []*types.Type) { // StaticAuxCall returns an AuxCall for a static call. func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - // TODO Create regInfo for AuxCall if paramResultInfo == nil { panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) } @@ -223,15 +235,13 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo } // InterfaceAuxCall returns an AuxCall for an interface call. -func InterfaceAuxCall(args []Param, results []Param) *AuxCall { - // TODO Create regInfo for AuxCall - return &AuxCall{Fn: nil, args: args, results: results} +func InterfaceAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} } // ClosureAuxCall returns an AuxCall for a closure call. -func ClosureAuxCall(args []Param, results []Param) *AuxCall { - // TODO Create regInfo for AuxCall - return &AuxCall{Fn: nil, args: args, results: results} +func ClosureAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} } func (*AuxCall) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 865630dd3e..938c1e8b62 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7,6 +7,7 @@ package ssagen import ( "bufio" "bytes" + "cmd/compile/internal/abi" "encoding/binary" "fmt" "go/constant" @@ -208,6 +209,32 @@ func InitConfig() { ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic") } +// AbiForFunc returns the ABI for a function, used to figure out arg/result mapping for rtcall and bodyless functions. +// This follows policy for GOEXPERIMENT=regabi, //go:registerparams, and currently defined ABIInternal. +// Policy is subject to change.... +// This always returns a freshly copied ABI. +func AbiForFunc(fn *ir.Func) *abi.ABIConfig { + return abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1).Copy() // No idea what races will result, be safe +} + +// abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. +// Passing a nil function returns ABIInternal. +func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { + a := abi1 + if true || objabi.Regabi_enabled == 0 { + a = abi0 + } + if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + name := ir.FuncName(fn) + if strings.Contains(name, ".") { + base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) + } + a = abi1 + base.WarnfAt(fn.Pos(), "declared function %v has register params", fn) + } + return a +} + // getParam returns the Field of ith param of node n (which is a // function/method/interface call), where the receiver of a method call is // considered as the 0th parameter. This does not include the receiver of an @@ -357,25 +384,10 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { if fn.Pragma&ir.Nosplit != 0 { s.f.NoSplit = true } - s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-width cache. + s.f.ABI0 = ssaConfig.ABI0.Copy() // Make a copy to avoid racy map operations in type-register-width cache. s.f.ABI1 = ssaConfig.ABI1.Copy() - - s.f.ABIDefault = s.f.ABI1 // Default ABI for function calls with no parsed signature for a pragma, e.g. rtcall - // TODO(register args) -- remove "true ||"; in the short run, turning on the register ABI experiment still leaves the compiler defaulting to ABI0. - // TODO(register args) -- remove this conditional entirely when register ABI is not an experiment. - if true || objabi.Regabi_enabled == 0 { - s.f.ABIDefault = s.f.ABI0 // reset - } - - s.f.ABISelf = s.f.ABIDefault - - if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working - s.f.ABISelf = s.f.ABI1 - if strings.Contains(name, ".") { - base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) - } - s.f.Warnl(fn.Pos(), "declared function %v has register params", fn) - } + s.f.ABIDefault = abiForFunc(nil, s.f.ABI0, s.f.ABI1) + s.f.ABISelf = abiForFunc(fn, s.f.ABI0, s.f.ABI1) s.panics = map[funcLine]*ssa.Block{} s.softFloat = s.config.SoftFloat @@ -4731,7 +4743,7 @@ func (s *state) openDeferExit() { v := s.load(r.closure.Type.Elem(), r.closure) s.maybeNilCheckClosure(v, callDefer) codeptr := s.rawLoad(types.Types[types.TUINTPTR], v) - aux := ssa.ClosureAuxCall(ACArgs, ACResults) + aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v) } else { aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults, @@ -4842,7 +4854,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } else { o = p.SpillOffset() + int32(params.SpillAreaOffset()) } - ACResults = append(ACResults, ssa.Param{Type: p.Type, Offset: o + int32(base.Ctxt.FixedFrameSize()), Reg: r}) + ACResults = append(ACResults, ssa.Param{Type: p.Type, Offset: o, Reg: r}) } } @@ -4913,21 +4925,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // Store arguments to stack, including defer/go arguments and receiver for method calls. // These are written in SP-offset order. argStart := base.Ctxt.FixedFrameSize() + // argExtra is for combining with ABI-derived offsets; argStart is for old ABI0 code (defer, go). + argExtra := int32(0) // TODO(register args) untangle this mess when fully transition to abiutils, defer/go sanitized. // Defer/go args. if k != callNormal { // Write argsize and closure (args to newproc/deferproc). argsize := s.constInt32(types.Types[types.TUINT32], int32(stksize)) - ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINT32], Offset: int32(argStart)}) + ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINT32], Offset: int32(argStart)}) // not argExtra callArgs = append(callArgs, argsize) ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart) + int32(types.PtrSize)}) callArgs = append(callArgs, closure) stksize += 2 * int64(types.PtrSize) argStart += 2 * int64(types.PtrSize) + argExtra = 2 * int32(types.PtrSize) } // Set receiver (for interface calls). if rcvr != nil { - // ACArgs = append(ACArgs, ssa.Param{Type: types.Types[types.TUINTPTR], Offset: int32(argStart)}) callArgs = append(callArgs, rcvr) } @@ -4938,7 +4952,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val base.Fatalf("OCALLMETH missed by walkCall") } - for _, p := range params.InParams() { + for _, p := range params.InParams() { // includes receiver for interface calls r := p.Registers var o int32 if len(r) == 0 { @@ -4946,7 +4960,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } else { o = p.SpillOffset() + int32(params.SpillAreaOffset()) } - ACArg := ssa.Param{Type: p.Type, Offset: int32(argStart) + o, Reg: r} + ACArg := ssa.Param{Type: p.Type, Offset: argExtra + o, Reg: r} // o from ABI includes any architecture-dependent offsets. ACArgs = append(ACArgs, ACArg) } for i, n := range args { @@ -4972,10 +4986,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // critical that we not clobber any arguments already // stored onto the stack. codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure) - aux := ssa.ClosureAuxCall(ACArgs, ACResults) + aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure) case codeptr != nil: - aux := ssa.InterfaceAuxCall(ACArgs, ACResults) + // Note that the "receiver" parameter is nil because the actual receiver is the first input parameter. + aux := ssa.InterfaceAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr) case callee != nil: aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params) diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go index a0a11671e1..9a7d6d138c 100644 --- a/src/cmd/compile/internal/test/abiutils_test.go +++ b/src/cmd/compile/internal/test/abiutils_test.go @@ -21,7 +21,7 @@ import ( // AMD64 registers available: // - integer: RAX, RBX, RCX, RDI, RSI, R8, R9, r10, R11 // - floating point: X0 - X14 -var configAMD64 = abi.NewABIConfig(9, 15) +var configAMD64 = abi.NewABIConfig(9, 15, 0) func TestMain(m *testing.M) { ssagen.Arch.LinkArch = &x86.Linkamd64 diff --git a/src/cmd/compile/internal/test/abiutilsaux_test.go b/src/cmd/compile/internal/test/abiutilsaux_test.go index bac0c7639d..7eb273273d 100644 --- a/src/cmd/compile/internal/test/abiutilsaux_test.go +++ b/src/cmd/compile/internal/test/abiutilsaux_test.go @@ -129,36 +129,4 @@ func abitest(t *testing.T, ft *types.Type, exp expectedDump) { strings.TrimSpace(exp.dump), regResString, reason) } - // Analyze again with empty register set. - empty := abi.NewABIConfig(0, 0) - emptyRes := empty.ABIAnalyze(ft) - emptyResString := emptyRes.String() - - // Walk the results and make sure the offsets assigned match - // up with those assiged by CalcSize. This checks to make sure that - // when we have no available registers the ABI assignment degenerates - // back to the original ABI0. - - // receiver - failed := 0 - rfsl := ft.Recvs().Fields().Slice() - poff := 0 - if len(rfsl) != 0 { - failed |= verifyParamResultOffset(t, rfsl[0], emptyRes.InParams()[0], "receiver", 0) - poff = 1 - } - // params - pfsl := ft.Params().Fields().Slice() - for k, f := range pfsl { - verifyParamResultOffset(t, f, emptyRes.InParams()[k+poff], "param", k) - } - // results - ofsl := ft.Results().Fields().Slice() - for k, f := range ofsl { - failed |= verifyParamResultOffset(t, f, emptyRes.OutParams()[k], "result", k) - } - - if failed != 0 { - t.Logf("emptyres:\n%s\n", emptyResString) - } } -- GitLab From c6374f516206c02b905d0d76ee1a66dab6fcd212 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 25 Feb 2021 16:44:46 -0500 Subject: [PATCH 0148/1298] dist: generate stub go.mod in workdir ...and run commands from there. This removes the requirement that bootstrap must not run inside a module by ensuring that enclosing modules do not interfere with bootstrap. Fixes #44209. Change-Id: I700a81829226770b8160c8ff04127b855b6e26bf Reviewed-on: https://go-review.googlesource.com/c/go/+/296610 Trust: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod Reviewed-by: Bryan C. Mills --- src/cmd/dist/build.go | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 07ede42574..158cedbadc 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -111,9 +111,6 @@ func xinit() { fatalf("$GOROOT must be set") } goroot = filepath.Clean(b) - if modRoot := findModuleRoot(goroot); modRoot != "" { - fatalf("found go.mod file in %s: $GOROOT must not be inside a module", modRoot) - } b = os.Getenv("GOROOT_FINAL") if b == "" { @@ -241,6 +238,9 @@ func xinit() { os.Setenv("LANGUAGE", "en_US.UTF8") workdir = xworkdir() + if err := ioutil.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap"), 0666); err != nil { + fatalf("cannot write stub go.mod: %s", err) + } xatexit(rmworkdir) tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) @@ -1505,11 +1505,11 @@ func goCmd(goBinary string, cmd string, args ...string) { goCmd = append(goCmd, "-p=1") } - run(goroot, ShowOutput|CheckExit, append(goCmd, args...)...) + run(workdir, ShowOutput|CheckExit, append(goCmd, args...)...) } func checkNotStale(goBinary string, targets ...string) { - out := run(goroot, CheckExit, + out := run(workdir, CheckExit, append([]string{ goBinary, "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags, @@ -1519,7 +1519,7 @@ func checkNotStale(goBinary string, targets ...string) { os.Setenv("GODEBUG", "gocachehash=1") for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} { if strings.Contains(out, "STALE "+target) { - run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) + run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) break } } @@ -1615,20 +1615,6 @@ func checkCC() { } } -func findModuleRoot(dir string) (root string) { - for { - if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { - return dir - } - d := filepath.Dir(dir) - if d == dir { - break - } - dir = d - } - return "" -} - func defaulttarg() string { // xgetwd might return a path with symlinks fully resolved, and if // there happens to be symlinks in goroot, then the hasprefix test -- GitLab From 09f4ef4fa73a110eefd2cb9d78439f51d9294f65 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 19 Feb 2021 14:03:45 -0500 Subject: [PATCH 0149/1298] cmd/go/internal/mvs: prune spurious dependencies in Downgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, mvs.Downgrade could introduce spurious dependencies if the downgrade computed for one module lands on a “hidden” version (such as a pseudo-version) due to a requirement introduced by the downgrade for another module. To eliminate those spurious dependencies, we can add one more call to BuildList to recompute the “actual” downgraded versions, and then including only those actual versions in the final call to BuildList. For #36460 Change-Id: Icc6b54aa004907221b2bcbbae74598b0e4100776 Reviewed-on: https://go-review.googlesource.com/c/go/+/294294 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/mvs/mvs.go | 35 +++++++++++++++++++ src/cmd/go/internal/mvs/mvs_test.go | 7 ++-- .../script/mod_get_downup_pseudo_artifact.txt | 9 ++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go index ff2c5f963c..e30a40c97e 100644 --- a/src/cmd/go/internal/mvs/mvs.go +++ b/src/cmd/go/internal/mvs/mvs.go @@ -492,6 +492,41 @@ List: downgraded = append(downgraded, r) } + // The downgrades we computed above only downgrade to versions enumerated by + // reqs.Previous. However, reqs.Previous omits some versions — such as + // pseudo-versions and retracted versions — that may be selected as transitive + // requirements of other modules. + // + // If one of those requirements pulls the version back up above the version + // identified by reqs.Previous, then the transitive dependencies of that that + // initially-downgraded version should no longer matter — in particular, we + // should not add new dependencies on module paths that nothing else in the + // updated module graph even requires. + // + // In order to eliminate those spurious dependencies, we recompute the build + // list with the actual versions of the downgraded modules as selected by MVS, + // instead of our initial downgrades. + // (See the downhiddenartifact and downhiddencross test cases). + actual, err := BuildList(target, &override{ + target: target, + list: downgraded, + Reqs: reqs, + }) + if err != nil { + return nil, err + } + actualVersion := make(map[string]string, len(actual)) + for _, m := range actual { + actualVersion[m.Path] = m.Version + } + + downgraded = downgraded[:0] + for _, m := range list { + if v, ok := actualVersion[m.Path]; ok { + downgraded = append(downgraded, module.Version{Path: m.Path, Version: v}) + } + } + return BuildList(target, &override{ target: target, list: downgraded, diff --git a/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go index 661f68be08..598ed66688 100644 --- a/src/cmd/go/internal/mvs/mvs_test.go +++ b/src/cmd/go/internal/mvs/mvs_test.go @@ -282,8 +282,9 @@ downgrade A B1: A B1 # And C1 requires B2.hidden, and B2.hidden also meets our requirements: # it is compatible with D1 and a strict downgrade from B3. # -# BUG(?): B2.hidden does not require E1, so there is no need for E1 -# to appear in the final build list. Nonetheless, there it is. +# Since neither the initial nor the final build list includes B1, +# and the nothing in the final downgraded build list requires E at all, +# no dependency on E1 (required by only B1) should be introduced. # name: downhiddenartifact A: B3 C2 @@ -298,7 +299,7 @@ D2: build A1: A1 B3 D2 downgrade A1 D1: A1 B1 D1 E1 build A: A B3 C2 D2 -downgrade A D1: A B2.hidden C1 D1 E1 +downgrade A D1: A B2.hidden C1 D1 # Both B3 and C3 require D2. # If we downgrade D to D1, then in isolation B3 would downgrade to B1, diff --git a/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt index d773f6bd4d..c49615cecb 100644 --- a/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt +++ b/src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt @@ -26,18 +26,15 @@ cp go.mod go.mod.orig go mod tidy cmp go.mod.orig go.mod +# When we downgrade d.2 to d.1, no dependency on e should be added +# because nothing else in the module or import graph requires it. go get -d example.net/d@v0.1.0 go list -m all stdout '^example.net/b v0.2.1-0.20210219000000-000000000000 ' stdout '^example.net/c v0.1.0 ' stdout '^example.net/d v0.1.0 ' - - # BUG: A dependency on e is added even though nothing requires it. -stdout '^example.net/e ' - -go mod why -m example.net/e -stdout '^\(main module does not need module example.net/e\)' +! stdout '^example.net/e ' -- go.mod -- module example.net/a -- GitLab From e9eed78dc3f4ab9a87f43c7d902025329f622783 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 2 Mar 2021 09:52:55 -0500 Subject: [PATCH 0150/1298] cmd/go: resolve std-vendored dependencies as std packages except in 'go get' and 'go mod' In CL 251159, I removed a hard-coded special case changing the rewriting behavior for std dependencies in GOROOT/src/vendor and GOROOT/src/cmd/vendor. Unfortunately, that caused packages in 'std' to be reported as stale when run within GOROOT/src. This change restores the special-case behavior, but plumbs it through the PackageOpts explicitly instead of comparing strings stored in global variables. Fixes #44725 Change-Id: If084fe74972ce1704715ca79b0b7e092dd90c88b Reviewed-on: https://go-review.googlesource.com/c/go/+/297869 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modcmd/tidy.go | 9 +++--- src/cmd/go/internal/modcmd/vendor.go | 9 +++--- src/cmd/go/internal/modcmd/why.go | 9 +++--- src/cmd/go/internal/modget/get.go | 14 +++++---- src/cmd/go/internal/modload/load.go | 9 ++++-- src/cmd/go/testdata/script/list_std_stale.txt | 31 +++++++++++++++++++ src/cmd/go/testdata/script/mod_list_std.txt | 14 +++++---- src/cmd/go/testdata/script/mod_std_vendor.txt | 6 ++-- 8 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 src/cmd/go/testdata/script/list_std_stale.txt diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go index 3b83d87a8e..e7e63e6533 100644 --- a/src/cmd/go/internal/modcmd/tidy.go +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -62,10 +62,11 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot modload.LoadPackages(ctx, modload.PackageOpts{ - Tags: imports.AnyTags(), - ResolveMissingImports: true, - LoadTests: true, - AllowErrors: tidyE, + Tags: imports.AnyTags(), + VendorModulesInGOROOTSrc: true, + ResolveMissingImports: true, + LoadTests: true, + AllowErrors: tidyE, }, "all") modload.TidyBuildList() diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index d3ed9e00e2..2cd683b75c 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -64,10 +64,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot loadOpts := modload.PackageOpts{ - Tags: imports.AnyTags(), - ResolveMissingImports: true, - UseVendorAll: true, - AllowErrors: vendorE, + Tags: imports.AnyTags(), + VendorModulesInGOROOTSrc: true, + ResolveMissingImports: true, + UseVendorAll: true, + AllowErrors: vendorE, } _, pkgs := modload.LoadPackages(ctx, loadOpts, "all") diff --git a/src/cmd/go/internal/modcmd/why.go b/src/cmd/go/internal/modcmd/why.go index a5f3e8afcb..79d257d198 100644 --- a/src/cmd/go/internal/modcmd/why.go +++ b/src/cmd/go/internal/modcmd/why.go @@ -68,10 +68,11 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot loadOpts := modload.PackageOpts{ - Tags: imports.AnyTags(), - LoadTests: !*whyVendor, - SilenceErrors: true, - UseVendorAll: *whyVendor, + Tags: imports.AnyTags(), + VendorModulesInGOROOTSrc: true, + LoadTests: !*whyVendor, + SilenceErrors: true, + UseVendorAll: *whyVendor, } if *whyM { diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 971c5a8d8a..b875a46d81 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -1120,9 +1120,10 @@ func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) // build list. func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) { opts := modload.PackageOpts{ - Tags: imports.AnyTags(), - LoadTests: *getT, - SilenceErrors: true, // May be fixed by subsequent upgrades or downgrades. + Tags: imports.AnyTags(), + VendorModulesInGOROOTSrc: true, + LoadTests: *getT, + SilenceErrors: true, // May be fixed by subsequent upgrades or downgrades. } opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error { @@ -1459,9 +1460,10 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns // LoadPackages will print errors (since it has more context) but will not // exit, since we need to load retractions later. pkgOpts := modload.PackageOpts{ - LoadTests: *getT, - ResolveMissingImports: false, - AllowErrors: true, + VendorModulesInGOROOTSrc: true, + LoadTests: *getT, + ResolveMissingImports: false, + AllowErrors: true, } matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...) for _, m := range matches { diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 6d87acc6d3..0dba49e40e 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -134,6 +134,11 @@ type PackageOpts struct { // If nil, treated as equivalent to imports.Tags(). Tags map[string]bool + // VendorModulesInGOROOTSrc indicates that if we are within a module in + // GOROOT/src, packages in the module's vendor directory should be resolved as + // actual module dependencies (instead of standard-library packages). + VendorModulesInGOROOTSrc bool + // ResolveMissingImports indicates that we should attempt to add module // dependencies as needed to resolve imports of packages that are not found. // @@ -1170,13 +1175,13 @@ func (ld *loader) stdVendor(parentPath, path string) string { } if str.HasPathPrefix(parentPath, "cmd") { - if Target.Path != "cmd" { + if !ld.VendorModulesInGOROOTSrc || Target.Path != "cmd" { vendorPath := pathpkg.Join("cmd", "vendor", path) if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil { return vendorPath } } - } else if Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") { + } else if !ld.VendorModulesInGOROOTSrc || Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") { // If we are outside of the 'std' module, resolve imports from within 'std' // to the vendor directory. // diff --git a/src/cmd/go/testdata/script/list_std_stale.txt b/src/cmd/go/testdata/script/list_std_stale.txt new file mode 100644 index 0000000000..e5c1f334fd --- /dev/null +++ b/src/cmd/go/testdata/script/list_std_stale.txt @@ -0,0 +1,31 @@ +# https://golang.org/issue/44725: packages in std should not be reported as stale, +# regardless of whether they are listed from within or outside GOROOT/src. + +# Control case: net should not be stale at the start of the test, +# and should depend on vendor/golang.org/… instead of golang.org/…. + +! stale net + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' + +# Net should also not be stale when viewed from within GOROOT/src, +# and should still report the same package dependencies. + +cd $GOROOT/src +! stale net + +go list -deps net +stdout '^vendor/golang.org/x/net' +! stdout '^golang.org/x/net' + + +# However, 'go mod' and 'go get' subcommands should report the original module +# dependencies, not the vendored packages. + +[!net] stop + +env GOPROXY= +go mod why -m golang.org/x/net +stdout '^# golang.org/x/net\nnet\ngolang.org/x/net' diff --git a/src/cmd/go/testdata/script/mod_list_std.txt b/src/cmd/go/testdata/script/mod_list_std.txt index baf7908ab9..f4e0433d8a 100644 --- a/src/cmd/go/testdata/script/mod_list_std.txt +++ b/src/cmd/go/testdata/script/mod_list_std.txt @@ -48,18 +48,20 @@ stdout ^vendor/golang.org/x/crypto/internal/subtle ! stdout ^golang\.org/x # Within the std module, the dependencies of the non-vendored packages within -# std should appear to come from modules, but they should be loaded from the -# vendor directory (just like ordinary vendored module dependencies). +# std should appear to be packages beginning with 'vendor/', not 'golang.org/…' +# module dependencies. go list all -stdout ^golang.org/x/ +! stdout ^golang.org/x/ ! stdout ^std/ ! stdout ^cmd/ -! stdout ^vendor/ +stdout ^vendor/ go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' std -! stdout ^vendor/golang.org/x/net/http2/hpack -stdout ^golang.org/x/net/http2/hpack +! stdout . + +# However, the 'golang.org/…' module dependencies should resolve to those same +# directories. go list -f '{{.Dir}}' golang.org/x/net/http2/hpack stdout $GOROOT[/\\]src[/\\]vendor diff --git a/src/cmd/go/testdata/script/mod_std_vendor.txt b/src/cmd/go/testdata/script/mod_std_vendor.txt index fb954d74ed..c3cde52953 100644 --- a/src/cmd/go/testdata/script/mod_std_vendor.txt +++ b/src/cmd/go/testdata/script/mod_std_vendor.txt @@ -36,11 +36,11 @@ stderr 'use of vendored package' # When run within the 'std' module, 'go list -test' should report vendored -# transitive dependencies at their original module paths. +# transitive dependencies at their vendored paths. cd $GOROOT/src go list -test -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' net/http -stdout ^golang.org/x/net/http2/hpack -! stdout ^vendor/golang.org/x/net/http2/hpack +! stdout ^golang.org/x/net/http2/hpack +stdout ^vendor/golang.org/x/net/http2/hpack -- go.mod -- module m -- GitLab From b65091c11d711ff3b01cd25393305410e1b0b377 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 26 Feb 2021 17:21:21 -0500 Subject: [PATCH 0151/1298] cmd/go: add a test case that reproduces #44296 For #44296 Change-Id: I310f99ccd406622e39f3fbfa12f7a3bee39602db Reviewed-on: https://go-review.googlesource.com/c/go/+/297149 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- .../testdata/script/mod_retract_versions.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_retract_versions.txt diff --git a/src/cmd/go/testdata/script/mod_retract_versions.txt b/src/cmd/go/testdata/script/mod_retract_versions.txt new file mode 100644 index 0000000000..93ce5926e3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_versions.txt @@ -0,0 +1,18 @@ +# https://golang.org/issue/44296: the --versions flag should not affect +# the version reported by 'go list' in case of retractions. + +env FMT='{{.Path}}{{with .Error}}: {{printf "%q" .Err}}{{end}} {{printf "%q" .Version}}{{with .Versions}} {{.}}{{end}}' + +go list -m -e -f $FMT example.com/retract/self/pseudo +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: not a known dependency" ""$' + +go list -m -e -f $FMT example.com/retract/self/pseudo@latest +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' + + + # BUG(#44296): Adding --versions should not cause a retracted version to be reported. +go list -m -e -f $FMT --versions example.com/retract/self/pseudo +stdout '^example.com/retract/self/pseudo "v1.9.0"$' + +go list -m -e -f $FMT --versions example.com/retract/self/pseudo@latest +stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' -- GitLab From 2a2f99eefb70a66ecb9560a61b5cf23a5ca02ecb Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 26 Feb 2021 17:40:18 -0500 Subject: [PATCH 0152/1298] cmd/go/internal/modload: do not resolve an arbitrary version for 'go list --versions' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we don't actually require the listed module, we previously implicitly resolved "latest", but also (erroneously) forgot to apply exclusions and retractions for it. But there is really no need to resolve "latest" in this case at all — now we omit the version from the reported module info entirely. Fixes #44296 Change-Id: Id595f52f597c7213bd65b73bf066a678d9e1d694 Reviewed-on: https://go-review.googlesource.com/c/go/+/297150 Trust: Bryan C. Mills Reviewed-by: Michael Matloob --- src/cmd/go/internal/modload/build.go | 6 +++++- src/cmd/go/internal/modload/list.go | 14 +++----------- src/cmd/go/testdata/script/mod_proxy_https.txt | 1 + .../go/testdata/script/mod_retract_versions.txt | 3 +-- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go index 8ad5f834de..5a151b4802 100644 --- a/src/cmd/go/internal/modload/build.go +++ b/src/cmd/go/internal/modload/build.go @@ -113,7 +113,11 @@ func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted boo if listRetracted { allowed = CheckExclusions } - m.Versions, _ = versions(ctx, m.Path, allowed) + var err error + m.Versions, err = versions(ctx, m.Path, allowed) + if err != nil && m.Error == nil { + m.Error = &modinfo.ModuleError{Err: err.Error()} + } } // addRetraction fills in m.Retracted if the module was retracted by its author. diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go index 3491f941cd..de16c2f786 100644 --- a/src/cmd/go/internal/modload/list.go +++ b/src/cmd/go/internal/modload/list.go @@ -136,17 +136,9 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted if listVersions { // Don't make the user provide an explicit '@latest' when they're // explicitly asking what the available versions are. - // Instead, resolve the module, even if it isn't an existing dependency. - info, err := Query(ctx, arg, "latest", "", nil) - if err == nil { - mod := moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false, listRetracted) - mods = append(mods, mod) - } else { - mods = append(mods, &modinfo.ModulePublic{ - Path: arg, - Error: modinfoError(arg, "", err), - }) - } + // Instead, return a modinfo without a version, + // to which we can attach the requested version list. + mods = append(mods, &modinfo.ModulePublic{Path: arg}) continue } if cfg.BuildMod == "vendor" { diff --git a/src/cmd/go/testdata/script/mod_proxy_https.txt b/src/cmd/go/testdata/script/mod_proxy_https.txt index a23090cd0a..a5e28dd0b9 100644 --- a/src/cmd/go/testdata/script/mod_proxy_https.txt +++ b/src/cmd/go/testdata/script/mod_proxy_https.txt @@ -10,6 +10,7 @@ stderr 'invalid proxy URL.*proxydir' # GOPROXY HTTPS paths may elide the "https://" prefix. # (See golang.org/issue/32191.) env GOPROXY=proxy.golang.org +env GOSUMDB= go list -versions -m golang.org/x/text -- go.mod -- diff --git a/src/cmd/go/testdata/script/mod_retract_versions.txt b/src/cmd/go/testdata/script/mod_retract_versions.txt index 93ce5926e3..961a0a1fa3 100644 --- a/src/cmd/go/testdata/script/mod_retract_versions.txt +++ b/src/cmd/go/testdata/script/mod_retract_versions.txt @@ -10,9 +10,8 @@ go list -m -e -f $FMT example.com/retract/self/pseudo@latest stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' - # BUG(#44296): Adding --versions should not cause a retracted version to be reported. go list -m -e -f $FMT --versions example.com/retract/self/pseudo -stdout '^example.com/retract/self/pseudo "v1.9.0"$' +stdout '^example.com/retract/self/pseudo ""$' go list -m -e -f $FMT --versions example.com/retract/self/pseudo@latest stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' -- GitLab From 312fd9937d6e8675a166fe60df77c1c24015a369 Mon Sep 17 00:00:00 2001 From: witchard Date: Tue, 2 Mar 2021 21:16:24 +0000 Subject: [PATCH 0153/1298] cmd/go: remove -insecure flag on go get Resolves #37519 Change-Id: Iba675a180b0e61b12835cdb6ecd4c6dc61e0605c GitHub-Last-Rev: aa018af6f8fc7f0b829820e831ad96734adcb8d0 GitHub-Pull-Request: golang/go#44724 Reviewed-on: https://go-review.googlesource.com/c/go/+/297709 Trust: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- doc/go1.17.html | 12 ++++++-- src/cmd/go/alldocs.go | 26 ++++------------ src/cmd/go/internal/cfg/cfg.go | 2 -- src/cmd/go/internal/get/get.go | 27 +++++++---------- src/cmd/go/internal/help/helpdoc.go | 7 ++--- src/cmd/go/internal/modfetch/insecure.go | 16 ---------- src/cmd/go/internal/modfetch/repo.go | 4 +-- src/cmd/go/internal/modfetch/sumdb.go | 2 +- src/cmd/go/internal/modget/get.go | 30 +++++++------------ src/cmd/go/internal/web/http.go | 2 +- src/cmd/go/testdata/script/get_404_meta.txt | 5 ++-- src/cmd/go/testdata/script/get_insecure.txt | 20 ++++++++----- .../script/get_insecure_custom_domain.txt | 4 ++- .../script/get_insecure_deprecated.txt | 21 ------------- .../get_insecure_no_longer_supported.txt | 13 ++++++++ .../testdata/script/get_insecure_redirect.txt | 5 ++-- .../testdata/script/get_insecure_update.txt | 8 +++-- .../script/mod_get_insecure_redirect.txt | 4 +-- .../go/testdata/script/mod_sumdb_cache.txt | 7 ----- 19 files changed, 83 insertions(+), 132 deletions(-) delete mode 100644 src/cmd/go/internal/modfetch/insecure.go delete mode 100644 src/cmd/go/testdata/script/get_insecure_deprecated.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt diff --git a/doc/go1.17.html b/doc/go1.17.html index 79cd4f7b61..a07290714f 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -43,8 +43,16 @@ Do not send CLs removing the interior tags from such phrases.

    Go command

    -

    - TODO: complete this section, or delete if not needed +

    go get

    + +

    + The go get -insecure flag is + deprecated and has been removed. To permit the use of insecure schemes + when fetching dependencies, please use the GOINSECURE + environment variable. The -insecure flag also bypassed module + sum validation, use GOPRIVATE or GONOSUMDB if + you need that functionality. See go help + environment for details.

    Runtime

    diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index db3f281ef3..a125e94cea 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -596,7 +596,7 @@ // // Usage: // -// go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages] +// go get [-d] [-t] [-u] [-v] [build flags] [packages] // // Get resolves its command-line arguments to packages at specific module versions, // updates go.mod to require those versions, downloads source code into the @@ -641,14 +641,6 @@ // When the -t and -u flags are used together, get will update // test dependencies as well. // -// The -insecure flag permits fetching from repositories and resolving -// custom domains using insecure schemes such as HTTP, and also bypassess -// module sum validation using the checksum database. Use with caution. -// This flag is deprecated and will be removed in a future version of go. -// To permit the use of insecure schemes, use the GOINSECURE environment -// variable instead. To bypass module sum validation, use GOPRIVATE or -// GONOSUMDB. See 'go help environment' for details. -// // The -d flag instructs get not to build or install packages. get will only // update go.mod and download source code needed to build packages. // @@ -1783,9 +1775,8 @@ // Comma-separated list of glob patterns (in the syntax of Go's path.Match) // of module path prefixes that should always be fetched in an insecure // manner. Only applies to dependencies that are being fetched directly. -// Unlike the -insecure flag on 'go get', GOINSECURE does not disable -// checksum database validation. GOPRIVATE or GONOSUMDB may be used -// to achieve that. +// GOINSECURE does not disable checksum database validation. GOPRIVATE or +// GONOSUMDB may be used to achieve that. // GOOS // The operating system for which to compile code. // Examples are linux, darwin, windows, netbsd. @@ -2135,7 +2126,7 @@ // This help text, accessible as 'go help gopath-get' even in module-aware mode, // describes 'go get' as it operates in legacy GOPATH mode. // -// Usage: go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages] +// Usage: go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages] // // Get downloads the packages named by the import paths, along with their // dependencies. It then installs the named packages, like 'go install'. @@ -2151,13 +2142,6 @@ // The -fix flag instructs get to run the fix tool on the downloaded packages // before resolving dependencies or building the code. // -// The -insecure flag permits fetching from repositories and resolving -// custom domains using insecure schemes such as HTTP. Use with caution. -// This flag is deprecated and will be removed in a future version of go. -// The GOINSECURE environment variable should be used instead, since it -// provides control over which packages may be retrieved using an insecure -// scheme. See 'go help environment' for details. -// // The -t flag instructs get to also download the packages required to build // the tests for the specified packages. // @@ -2342,7 +2326,7 @@ // will result in the following requests: // // https://example.org/pkg/foo?go-get=1 (preferred) -// http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) +// http://example.org/pkg/foo?go-get=1 (fallback, only with use of correctly set GOINSECURE) // // If that page contains the meta tag // diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index 322247962f..810189c15d 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -51,8 +51,6 @@ var ( ModCacheRW bool // -modcacherw flag ModFile string // -modfile flag - Insecure bool // -insecure flag - CmdName string // "build", "install", "list", "mod tidy", etc. DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable) diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 329a2f5eda..10eda1275e 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -26,7 +26,7 @@ import ( ) var CmdGet = &base.Command{ - UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]", + UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` Get downloads the packages named by the import paths, along with their @@ -43,13 +43,6 @@ of the original. The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. -The -insecure flag permits fetching from repositories and resolving -custom domains using insecure schemes such as HTTP. Use with caution. -This flag is deprecated and will be removed in a future version of go. -The GOINSECURE environment variable should be used instead, since it -provides control over which packages may be retrieved using an insecure -scheme. See 'go help environment' for details. - The -t flag instructs get to also download the packages required to build the tests for the specified packages. @@ -105,17 +98,17 @@ Usage: ` + CmdGet.UsageLine + ` } var ( - getD = CmdGet.Flag.Bool("d", false, "") - getF = CmdGet.Flag.Bool("f", false, "") - getT = CmdGet.Flag.Bool("t", false, "") - getU = CmdGet.Flag.Bool("u", false, "") - getFix = CmdGet.Flag.Bool("fix", false, "") + getD = CmdGet.Flag.Bool("d", false, "") + getF = CmdGet.Flag.Bool("f", false, "") + getT = CmdGet.Flag.Bool("t", false, "") + getU = CmdGet.Flag.Bool("u", false, "") + getFix = CmdGet.Flag.Bool("fix", false, "") + getInsecure = CmdGet.Flag.Bool("insecure", false, "") ) func init() { work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags) CmdGet.Run = runGet // break init loop - CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "") } func runGet(ctx context.Context, cmd *base.Command, args []string) { @@ -129,8 +122,8 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { if *getF && !*getU { base.Fatalf("go get: cannot use -f flag without -u") } - if cfg.Insecure { - fmt.Fprintf(os.Stderr, "go get: -insecure flag is deprecated; see 'go help get' for details\n") + if *getInsecure { + base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead") } // Disable any prompting for passwords by Git. @@ -435,7 +428,7 @@ func downloadPackage(p *load.Package) error { return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) } security := web.SecureOnly - if cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) { + if module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) { security = web.Insecure } diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 57cee4ff96..2f86e4195d 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -251,7 +251,7 @@ For example, will result in the following requests: https://example.org/pkg/foo?go-get=1 (preferred) - http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) + http://example.org/pkg/foo?go-get=1 (fallback, only with use of correctly set GOINSECURE) If that page contains the meta tag @@ -517,9 +517,8 @@ General-purpose environment variables: Comma-separated list of glob patterns (in the syntax of Go's path.Match) of module path prefixes that should always be fetched in an insecure manner. Only applies to dependencies that are being fetched directly. - Unlike the -insecure flag on 'go get', GOINSECURE does not disable - checksum database validation. GOPRIVATE or GONOSUMDB may be used - to achieve that. + GOINSECURE does not disable checksum database validation. GOPRIVATE or + GONOSUMDB may be used to achieve that. GOOS The operating system for which to compile code. Examples are linux, darwin, windows, netbsd. diff --git a/src/cmd/go/internal/modfetch/insecure.go b/src/cmd/go/internal/modfetch/insecure.go deleted file mode 100644 index 012d05f29d..0000000000 --- a/src/cmd/go/internal/modfetch/insecure.go +++ /dev/null @@ -1,16 +0,0 @@ -// 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 modfetch - -import ( - "cmd/go/internal/cfg" - - "golang.org/x/mod/module" -) - -// allowInsecure reports whether we are allowed to fetch this path in an insecure manner. -func allowInsecure(path string) bool { - return cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, path) -} diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go index af9e24cefd..ed9a52267a 100644 --- a/src/cmd/go/internal/modfetch/repo.go +++ b/src/cmd/go/internal/modfetch/repo.go @@ -267,7 +267,7 @@ var ( func lookupDirect(path string) (Repo, error) { security := web.SecureOnly - if allowInsecure(path) { + if module.MatchPrefixPatterns(cfg.GOINSECURE, path) { security = web.Insecure } rr, err := vcs.RepoRootForImportPath(path, vcs.PreferMod, security) @@ -312,7 +312,7 @@ func ImportRepoRev(path, rev string) (Repo, *RevInfo, error) { // version control system, we ignore meta tags about modules // and use only direct source control entries (get.IgnoreMod). security := web.SecureOnly - if allowInsecure(path) { + if module.MatchPrefixPatterns(cfg.GOINSECURE, path) { security = web.Insecure } rr, err := vcs.RepoRootForImportPath(path, vcs.IgnoreMod, security) diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index fbe2bda2e5..118bb3d2d0 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -34,7 +34,7 @@ import ( // useSumDB reports whether to use the Go checksum database for the given module. func useSumDB(mod module.Version) bool { - return cfg.GOSUMDB != "off" && !cfg.Insecure && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path) + return cfg.GOSUMDB != "off" && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path) } // lookupSumDB returns the Go checksum database's go.sum lines for the given module, diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index b875a46d81..9340a582e5 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -37,7 +37,6 @@ import ( "sync" "cmd/go/internal/base" - "cmd/go/internal/cfg" "cmd/go/internal/imports" "cmd/go/internal/load" "cmd/go/internal/modload" @@ -53,7 +52,7 @@ import ( var CmdGet = &base.Command{ // Note: -d -u are listed explicitly because they are the most common get flags. // Do not send CLs removing them because they're covered by [get flags]. - UsageLine: "go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]", + UsageLine: "go get [-d] [-t] [-u] [-v] [build flags] [packages]", Short: "add dependencies to current module and install them", Long: ` Get resolves its command-line arguments to packages at specific module versions, @@ -99,14 +98,6 @@ but changes the default to select patch releases. When the -t and -u flags are used together, get will update test dependencies as well. -The -insecure flag permits fetching from repositories and resolving -custom domains using insecure schemes such as HTTP, and also bypassess -module sum validation using the checksum database. Use with caution. -This flag is deprecated and will be removed in a future version of go. -To permit the use of insecure schemes, use the GOINSECURE environment -variable instead. To bypass module sum validation, use GOPRIVATE or -GONOSUMDB. See 'go help environment' for details. - The -d flag instructs get not to build or install packages. get will only update go.mod and download source code needed to build packages. @@ -227,13 +218,13 @@ variable for future go command invocations. } var ( - getD = CmdGet.Flag.Bool("d", false, "") - getF = CmdGet.Flag.Bool("f", false, "") - getFix = CmdGet.Flag.Bool("fix", false, "") - getM = CmdGet.Flag.Bool("m", false, "") - getT = CmdGet.Flag.Bool("t", false, "") - getU upgradeFlag - // -insecure is cfg.Insecure + getD = CmdGet.Flag.Bool("d", false, "") + getF = CmdGet.Flag.Bool("f", false, "") + getFix = CmdGet.Flag.Bool("fix", false, "") + getM = CmdGet.Flag.Bool("m", false, "") + getT = CmdGet.Flag.Bool("t", false, "") + getU upgradeFlag + getInsecure = CmdGet.Flag.Bool("insecure", false, "") // -v is cfg.BuildV ) @@ -264,7 +255,6 @@ func (v *upgradeFlag) String() string { return "" } func init() { work.AddBuildFlags(CmdGet, work.OmitModFlag) CmdGet.Run = runGet // break init loop - CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "") CmdGet.Flag.Var(&getU, "u", "") } @@ -284,8 +274,8 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { if *getM { base.Fatalf("go get: -m flag is no longer supported; consider -d to skip building packages") } - if cfg.Insecure { - fmt.Fprintf(os.Stderr, "go get: -insecure flag is deprecated; see 'go help get' for details\n") + if *getInsecure { + base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead") } load.ModResolveTests = *getT diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go index a77e0f9317..f177278eba 100644 --- a/src/cmd/go/internal/web/http.go +++ b/src/cmd/go/internal/web/http.go @@ -28,7 +28,7 @@ import ( "cmd/internal/browser" ) -// impatientInsecureHTTPClient is used in -insecure mode, +// impatientInsecureHTTPClient is used with GOINSECURE, // when we're connecting to https servers that might not be there // or might be using self-signed certificates. var impatientInsecureHTTPClient = &http.Client{ diff --git a/src/cmd/go/testdata/script/get_404_meta.txt b/src/cmd/go/testdata/script/get_404_meta.txt index b71cc7fe01..ec4f8d3243 100644 --- a/src/cmd/go/testdata/script/get_404_meta.txt +++ b/src/cmd/go/testdata/script/get_404_meta.txt @@ -3,9 +3,10 @@ [!net] skip [!exec:git] skip +env GONOSUMDB=bazil.org,github.com,golang.org env GO111MODULE=off -go get -d -insecure bazil.org/fuse/fs/fstestutil +go get -d bazil.org/fuse/fs/fstestutil env GO111MODULE=on env GOPROXY=direct -go get -d -insecure bazil.org/fuse/fs/fstestutil +go get -d bazil.org/fuse/fs/fstestutil diff --git a/src/cmd/go/testdata/script/get_insecure.txt b/src/cmd/go/testdata/script/get_insecure.txt index 36ad2c05b7..69930f7107 100644 --- a/src/cmd/go/testdata/script/get_insecure.txt +++ b/src/cmd/go/testdata/script/get_insecure.txt @@ -12,10 +12,12 @@ env GO111MODULE=off # GOPATH: Try go get -d of HTTP-only repo (should fail). ! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p -# GOPATH: Try again with -insecure (should succeed). -go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p +# GOPATH: Try again with GOINSECURE (should succeed). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com +go get -d insecure.go-get-issue-15410.appspot.com/pkg/p -# GOPATH: Try updating without -insecure (should fail). +# GOPATH: Try updating without GOINSECURE (should fail). +env GOINSECURE='' ! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p # Modules: Set up @@ -29,10 +31,14 @@ env GOPROXY='' # Modules: Try go get -d of HTTP-only repo (should fail). ! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p -# Modules: Try again with -insecure (should succeed). -go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p +# Modules: Try again with GOINSECURE (should succeed). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com +env GONOSUMDB=insecure.go-get-issue-15410.appspot.com +go get -d insecure.go-get-issue-15410.appspot.com/pkg/p -# Modules: Try updating without -insecure (should fail). +# Modules: Try updating without GOINSECURE (should fail). +env GOINSECURE='' +env GONOSUMDB='' ! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p go list -m ... @@ -48,4 +54,4 @@ func main() { os.Exit(1) } -- module_file -- -module m \ No newline at end of file +module m diff --git a/src/cmd/go/testdata/script/get_insecure_custom_domain.txt b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt index a4a6fd428f..7eba42e873 100644 --- a/src/cmd/go/testdata/script/get_insecure_custom_domain.txt +++ b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt @@ -3,4 +3,6 @@ env GO111MODULE=off ! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p -go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p + +env GOINSECURE=insecure.go-get-issue-15410.appspot.com +go get -d insecure.go-get-issue-15410.appspot.com/pkg/p diff --git a/src/cmd/go/testdata/script/get_insecure_deprecated.txt b/src/cmd/go/testdata/script/get_insecure_deprecated.txt deleted file mode 100644 index 7f5f5c7877..0000000000 --- a/src/cmd/go/testdata/script/get_insecure_deprecated.txt +++ /dev/null @@ -1,21 +0,0 @@ -# GOPATH: Set up -env GO111MODULE=off - -# GOPATH: Fetch without insecure, no warning -! go get test -! stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' - -# GOPATH: Fetch with insecure, should warn -! go get -insecure test -stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' - -# Modules: Set up -env GO111MODULE=on - -# Modules: Fetch without insecure, no warning -! go get test -! stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' - -# Modules: Fetch with insecure, should warn -! go get -insecure test -stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' diff --git a/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt b/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt new file mode 100644 index 0000000000..2517664dd0 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt @@ -0,0 +1,13 @@ +# GOPATH: Set up +env GO111MODULE=off + +# GOPATH: Fetch with insecure, should error +! go get -insecure test +stderr 'go get: -insecure flag is no longer supported; use GOINSECURE instead' + +# Modules: Set up +env GO111MODULE=on + +# Modules: Fetch with insecure, should error +! go get -insecure test +stderr 'go get: -insecure flag is no longer supported; use GOINSECURE instead' diff --git a/src/cmd/go/testdata/script/get_insecure_redirect.txt b/src/cmd/go/testdata/script/get_insecure_redirect.txt index 0478d1f75d..fb5f26951c 100644 --- a/src/cmd/go/testdata/script/get_insecure_redirect.txt +++ b/src/cmd/go/testdata/script/get_insecure_redirect.txt @@ -1,4 +1,4 @@ -# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure (now replaced by GOINSECURE). # golang.org/issue/34049: 'go get' would panic in case of an insecure redirect in GOPATH mode [!net] skip @@ -9,4 +9,5 @@ env GO111MODULE=off ! go get -d vcs-test.golang.org/insecure/go/insecure stderr 'redirected .* to insecure URL' -go get -d -insecure vcs-test.golang.org/insecure/go/insecure +env GOINSECURE=vcs-test.golang.org/insecure/go/insecure +go get -d vcs-test.golang.org/insecure/go/insecure diff --git a/src/cmd/go/testdata/script/get_insecure_update.txt b/src/cmd/go/testdata/script/get_insecure_update.txt index 4511c98c56..e1a1a23d47 100644 --- a/src/cmd/go/testdata/script/get_insecure_update.txt +++ b/src/cmd/go/testdata/script/get_insecure_update.txt @@ -5,8 +5,10 @@ env GO111MODULE=off # Clone the repo via HTTP manually. exec git clone -q http://github.com/golang/example github.com/golang/example -# Update without -insecure should fail. -# Update with -insecure should succeed. +# Update without GOINSECURE should fail. # We need -f to ignore import comments. ! go get -d -u -f github.com/golang/example/hello -go get -d -u -f -insecure github.com/golang/example/hello + +# Update with GOINSECURE should succeed. +env GOINSECURE=github.com/golang/example/hello +go get -d -u -f github.com/golang/example/hello diff --git a/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt index 3755f17633..2e12834495 100644 --- a/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt +++ b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt @@ -1,4 +1,4 @@ -# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure (now replaced by GOINSECURE). [!net] skip [!exec:git] skip @@ -10,8 +10,6 @@ env GOSUMDB=off ! go get -d vcs-test.golang.org/insecure/go/insecure stderr 'redirected .* to insecure URL' -go get -d -insecure vcs-test.golang.org/insecure/go/insecure - # insecure host env GOINSECURE=vcs-test.golang.org go clean -modcache diff --git a/src/cmd/go/testdata/script/mod_sumdb_cache.txt b/src/cmd/go/testdata/script/mod_sumdb_cache.txt index 2937b2e4dc..1b38475fb5 100644 --- a/src/cmd/go/testdata/script/mod_sumdb_cache.txt +++ b/src/cmd/go/testdata/script/mod_sumdb_cache.txt @@ -43,12 +43,5 @@ env GOPROXY=$proxy/sumdb-504 ! go get -d rsc.io/quote@v1.5.2 stderr 504 -# but -insecure bypasses the checksum lookup entirely -env GOINSECURE= -go get -d -insecure rsc.io/quote@v1.5.2 - -# and then it is in go.sum again -go get -d rsc.io/quote@v1.5.2 - -- go.mod.orig -- module m -- GitLab From aea1259a7288d71736273b494e60bd424ea1946c Mon Sep 17 00:00:00 2001 From: David Chase Date: Sun, 28 Feb 2021 21:48:20 -0500 Subject: [PATCH 0154/1298] cmd/link: disable flaky Darwin "symbols" test About one run out of 3 it fails on my laptop, and I am tired of having to be a nanny for my tests just because of this one flaky test. This has been a problem for months. Updates #32218. Change-Id: I2871d4c6f47e9432d189ed7bdcda8f9c0871cfc5 Reviewed-on: https://go-review.googlesource.com/c/go/+/297469 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/link/dwarf_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go index db710bed6a..d0284ad4f5 100644 --- a/src/cmd/link/dwarf_test.go +++ b/src/cmd/link/dwarf_test.go @@ -91,7 +91,8 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) exe = filepath.Join(tmpDir, "go.o") } - if runtime.GOOS == "darwin" { + darwinSymbolTestIsTooFlaky := true // Turn this off, it is too flaky -- See #32218 + if runtime.GOOS == "darwin" && !darwinSymbolTestIsTooFlaky { if _, err = exec.LookPath("symbols"); err == nil { // Ensure Apple's tooling can parse our object for symbols. out, err = exec.Command("symbols", exe).CombinedOutput() -- GitLab From 77973863c351b162d68723439fc56fb054e917b2 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 9 Feb 2021 15:14:43 -0500 Subject: [PATCH 0155/1298] cmd/compile: use abiutils for all rcvr/in/out frame offsets. types thought it knew how to do this, but that's a lie, because types doesn't know what the ABI is. includes extra checking to help prevent things from accidentally working if they need to be changed but aren't. For #40724. Change-Id: I166cd948f262344b7bebde6a2c25e7a7f878bbfb Reviewed-on: https://go-review.googlesource.com/c/go/+/293393 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 33 ++++++++---- src/cmd/compile/internal/ir/expr.go | 8 +-- src/cmd/compile/internal/ssa/expand_calls.go | 31 ++++++++--- src/cmd/compile/internal/ssa/op.go | 40 +++------------ src/cmd/compile/internal/ssagen/ssa.go | 51 ++++++++++--------- .../compile/internal/typecheck/typecheck.go | 2 +- src/cmd/compile/internal/types/size.go | 6 ++- src/cmd/compile/internal/types/type.go | 16 +++++- src/cmd/compile/internal/walk/assign.go | 2 +- 9 files changed, 107 insertions(+), 82 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index a5c85a89fb..8549c0325d 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -151,6 +151,13 @@ func (a *ABIConfig) Copy() *ABIConfig { return &b } +// LocalsOffset returns the architecture-dependent offset from SP for args and results. +// In theory this is only used for debugging; it ought to already be incorporated into +// results from the ABI-related methods +func (a *ABIConfig) LocalsOffset() int64 { + return a.offsetForLocals +} + // NumParamRegs returns the number of parameter registers used for a given type, // without regard for the number available. func (a *ABIConfig) NumParamRegs(t *types.Type) int { @@ -237,23 +244,22 @@ func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Ty return result } -// ABIAnalyze takes a function type 't' and an ABI rules description +// ABIAnalyzeFuncType takes a function type 'ft' and an ABI rules description // 'config' and analyzes the function to determine how its parameters // and results will be passed (in registers or on the stack), returning // an ABIParamResultInfo object that holds the results of the analysis. -func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { +func (config *ABIConfig) ABIAnalyzeFuncType(ft *types.Func) *ABIParamResultInfo { setup() s := assignState{ stackOffset: config.offsetForLocals, rTotal: config.regAmounts, } result := &ABIParamResultInfo{config: config} - ft := t.FuncType() - result.preAllocateParams(t.NumRecvs() != 0, ft.Params.NumFields(), ft.Results.NumFields()) + result.preAllocateParams(ft.Receiver != nil, ft.Params.NumFields(), ft.Results.NumFields()) // Receiver // TODO(register args) ? seems like "struct" and "fields" is not right anymore for describing function parameters - if t.NumRecvs() != 0 { + if ft.Receiver != nil && ft.Receiver.NumFields() != 0 { r := ft.Receiver.FieldSlice()[0] result.inparams = append(result.inparams, s.assignParamOrReturn(r.Type, r.Nname, false)) @@ -279,7 +285,14 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize) result.spillAreaSize = alignTo(s.spillOffset, types.RegSize) result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs + return result +} +// ABIAnalyze returns the same result as ABIAnalyzeFuncType, but also +// updates the offsets of all the receiver, input, and output fields. +func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { + ft := t.FuncType() + result := config.ABIAnalyzeFuncType(ft) // Fill in the frame offsets for receiver, inputs, results k := 0 if t.NumRecvs() != 0 { @@ -296,13 +309,11 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { } func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) { + // Everything except return values in registers has either a frame home (if not in a register) or a frame spill location. if !isReturn || len(a.Registers) == 0 { - // TODO in next CL, assign - if f.Offset+config.offsetForLocals != a.FrameOffset(result) { - if config.regAmounts.intRegs == 0 && config.regAmounts.floatRegs == 0 { - panic(fmt.Errorf("Expected node offset %d != abi offset %d", f.Offset, a.FrameOffset(result))) - } - } + // The type frame offset DOES NOT show effects of minimum frame size. + // Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set + f.Offset = a.FrameOffset(result)-config.LocalsOffset() } } diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index d68bcfe60c..65ed3cff66 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -447,14 +447,14 @@ func (n *ParenExpr) SetOTYPE(t *types.Type) { t.SetNod(n) } -// A ResultExpr represents a direct access to a result slot on the stack frame. +// A ResultExpr represents a direct access to a result. type ResultExpr struct { miniExpr - Offset int64 + Index int64 // index of the result expr. } -func NewResultExpr(pos src.XPos, typ *types.Type, offset int64) *ResultExpr { - n := &ResultExpr{Offset: offset} +func NewResultExpr(pos src.XPos, typ *types.Type, index int64) *ResultExpr { + n := &ResultExpr{Index: index} n.pos = pos n.op = ORESULT n.typ = typ diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 292b0b41ce..741d59258b 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -32,6 +32,10 @@ func isBlockMultiValueExit(b *Block) bool { return (b.Kind == BlockRet || b.Kind == BlockRetJmp) && len(b.Controls) > 0 && b.Controls[0].Op == OpMakeResult } +func badVal(s string, v *Value) error { + return fmt.Errorf("%s %s", s, v.LongString()) +} + // removeTrivialWrapperTypes unwraps layers of // struct { singleField SomeType } and [1]SomeType // until a non-wrapper type is reached. This is useful @@ -231,6 +235,9 @@ func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *t // prAssignForArg returns the ABIParamAssignment for v, assumed to be an OpArg. func (x *expandState) prAssignForArg(v *Value) abi.ABIParamAssignment { + if v.Op != OpArg { + panic(badVal("Wanted OpArg, instead saw", v)) + } name := v.Aux.(*ir.Name) fPri := x.f.OwnAux.abiInfo for _, a := range fPri.InParams() { @@ -275,9 +282,6 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, } switch selector.Op { case OpArg: - paramAssignment := x.prAssignForArg(selector) - _ = paramAssignment - // TODO(register args) if !x.isAlreadyExpandedAggregateType(selector.Type) { if leafType == selector.Type { // OpIData leads us here, sometimes. leaf.copyOf(selector) @@ -364,7 +368,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, // StaticCall selector will address last element of Result. // TODO do this for all the other call types eventually. if aux.abiInfo == nil { - panic(fmt.Errorf("aux.abiInfo nil for call %s", call.LongString())) + panic(badVal("aux.abiInfo nil for call", call)) } if existing := x.memForCall[call.ID]; existing == nil { selector.AuxInt = int64(aux.abiInfo.OutRegistersUsed()) @@ -566,9 +570,6 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m // pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - paramAssignment := x.prAssignForArg(source) - _ = paramAssignment - // TODO(register args) w := x.common[selKey{source, offArg, t.Width, t}] if w == nil { w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux) @@ -1198,10 +1199,24 @@ func expandCalls(f *Func) { deleteNamedVals(f, toDelete) - // Step 4: rewrite the calls themselves, correcting the type + // Step 4: rewrite the calls themselves, correcting the type. for _, b := range f.Blocks { for _, v := range b.Values { switch v.Op { + case OpArg: + pa := x.prAssignForArg(v) + switch len(pa.Registers) { + case 0: + frameOff := v.Aux.(*ir.Name).FrameOffset() + if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) { + panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s\n", + pa.Offset(), frameOff, v.LongString())) + } + case 1: + default: + panic(badVal("Saw unexpeanded OpArg", v)) + } + case OpStaticLECall: v.Op = OpStaticCall // TODO need to insert all the register types. diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 6d2ca96293..506c745f7c 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -86,63 +86,39 @@ type AuxCall struct { abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information. } -// ResultForOffsetAndType returns the index of a t-typed result at *A* particular offset among the results. -// An arbitrary number of zero-width-typed results may reside at the same offset with a single not-zero-width -// typed result, but the ones with the same type are all indistinguishable so it doesn't matter "which one" -// is obtained. -// This does not include the mem result for the call opcode. -func (a *AuxCall) ResultForOffsetAndType(offset int64, t *types.Type) int64 { - which := int64(-1) - for i := int64(0); i < a.NResults(); i++ { // note aux NResults does not include mem result. - if a.OffsetOfResult(i) == offset && a.TypeOfResult(i) == t { - which = i - break - } - } - return which -} - // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { - o := int64(a.results[which].Offset) n := int64(a.abiInfo.OutParam(int(which)).Offset()) - if o != n { - panic(fmt.Errorf("Result old=%d, new=%d, auxcall=%s, oparams=%v", o, n, a, a.abiInfo.OutParams())) - } - return int64(a.abiInfo.OutParam(int(which)).Offset()) + return n } // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) OffsetOfArg(which int64) int64 { - o := int64(a.args[which].Offset) n := int64(a.abiInfo.InParam(int(which)).Offset()) - if o != n { - panic(fmt.Errorf("Arg old=%d, new=%d, auxcall=%s, iparams=%v", o, n, a, a.abiInfo.InParams())) - } - return int64(a.abiInfo.InParam(int(which)).Offset()) + return n } // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc). func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex { - return a.results[which].Reg + return a.abiInfo.OutParam(int(which)).Registers } // RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex { - return a.args[which].Reg + return a.abiInfo.InParam(int(which)).Registers } // TypeOfResult returns the type of result which (indexed 0, 1, etc). func (a *AuxCall) TypeOfResult(which int64) *types.Type { - return a.results[which].Type + return a.abiInfo.OutParam(int(which)).Type } // TypeOfArg returns the type of argument which (indexed 0, 1, etc). // If the call is to a method, the receiver is the first argument (i.e., index 0) func (a *AuxCall) TypeOfArg(which int64) *types.Type { - return a.args[which].Type + return a.abiInfo.InParam(int(which)).Type } // SizeOfResult returns the size of result which (indexed 0, 1, etc). @@ -158,7 +134,7 @@ func (a *AuxCall) SizeOfArg(which int64) int64 { // NResults returns the number of results func (a *AuxCall) NResults() int64 { - return int64(len(a.results)) + return int64(len(a.abiInfo.OutParams())) } // LateExpansionResultType returns the result type (including trailing mem) @@ -174,7 +150,7 @@ func (a *AuxCall) LateExpansionResultType() *types.Type { // NArgs returns the number of arguments (including receiver, if there is one). func (a *AuxCall) NArgs() int64 { - return int64(len(a.args)) + return int64(len(a.abiInfo.InParams())) } // String returns diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 938c1e8b62..210150d872 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -301,7 +301,7 @@ func (s *state) emitOpenDeferInfo() { var maxargsize int64 for i := len(s.openDefers) - 1; i >= 0; i-- { r := s.openDefers[i] - argsize := r.n.X.Type().ArgWidth() + argsize := r.n.X.Type().ArgWidth() // TODO register args: but maybe use of abi0 will make this easy if argsize > maxargsize { maxargsize = argsize } @@ -324,19 +324,30 @@ func (s *state) emitOpenDeferInfo() { } off = dvarint(x, off, int64(numArgs)) if r.rcvrNode != nil { - off = dvarint(x, off, -r.rcvrNode.FrameOffset()) + off = dvarint(x, off, -okOffset(r.rcvrNode.FrameOffset())) off = dvarint(x, off, s.config.PtrSize) - off = dvarint(x, off, 0) + off = dvarint(x, off, 0) // This is okay because defer records use ABI0 (for now) } + + // TODO(register args) assume abi0 for this? + ab := s.f.ABI0 + pri := ab.ABIAnalyzeFuncType(r.n.X.Type().FuncType()) for j, arg := range r.argNodes { f := getParam(r.n, j) - off = dvarint(x, off, -arg.FrameOffset()) + off = dvarint(x, off, -okOffset(arg.FrameOffset())) off = dvarint(x, off, f.Type.Size()) - off = dvarint(x, off, f.Offset) + off = dvarint(x, off, okOffset(pri.InParam(j).FrameOffset(pri))-ab.LocalsOffset()) // defer does not want the fixed frame adjustment } } } +func okOffset(offset int64) int64 { + if offset >= types.BOGUS_FUNARG_OFFSET { + panic(fmt.Errorf("Bogus offset %d", offset)) + } + return offset +} + // buildssa builds an SSA function for fn. // worker indicates which of the backend workers is doing the processing. func buildssa(fn *ir.Func, worker int) *ssa.Func { @@ -528,7 +539,13 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { // Populate SSAable arguments. for _, n := range fn.Dcl { if n.Class == ir.PPARAM && s.canSSA(n) { - v := s.newValue0A(ssa.OpArg, n.Type(), n) + var v *ssa.Value + if n.Sym().Name == ".fp" { + // Race-detector's get-caller-pc incantation is NOT a real Arg. + v = s.newValue0(ssa.OpGetCallerPC, n.Type()) + } else { + v = s.newValue0A(ssa.OpArg, n.Type(), n) + } s.vars[n] = v s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself. } @@ -2917,15 +2934,11 @@ func (s *state) expr(n ir.Node) *ssa.Value { case ir.ORESULT: n := n.(*ir.ResultExpr) if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall { - // Do the old thing - addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset) - return s.rawLoad(n.Type(), addr) + panic("Expected to see a previous call") } - which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffsetAndType(n.Offset, n.Type()) + which := n.Index if which == -1 { - // Do the old thing // TODO: Panic instead. - addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset) - return s.rawLoad(n.Type(), addr) + panic(fmt.Errorf("ORESULT %v does not match call %s", n, s.prevCall)) } if TypeOK(n.Type()) { return s.newValue1I(ssa.OpSelectN, n.Type(), which, s.prevCall) @@ -4889,7 +4902,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // Then, store all the arguments of the defer call. ft := fn.Type() - off := t.FieldOff(12) + off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset. args := n.Args // Set receiver (for interface calls). Always a pointer. @@ -5131,15 +5144,7 @@ func (s *state) addr(n ir.Node) *ssa.Value { case ir.ORESULT: // load return from callee n := n.(*ir.ResultExpr) - if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall { - return s.constOffPtrSP(t, n.Offset) - } - which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffsetAndType(n.Offset, n.Type()) - if which == -1 { - // Do the old thing // TODO: Panic instead. - return s.constOffPtrSP(t, n.Offset) - } - x := s.newValue1I(ssa.OpSelectNAddr, t, which, s.prevCall) + x := s.newValue1I(ssa.OpSelectNAddr, t, n.Index, s.prevCall) return x case ir.OINDEX: diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index cb434578dd..5a3446b358 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1175,7 +1175,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field { base.Errorf("%v is both field and method", n.Sel) } if f1.Offset == types.BADWIDTH { - base.Fatalf("lookdot badwidth %v %p", f1, f1) + base.Fatalf("lookdot badwidth t=%v, f1=%v@%p", t, f1, f1) } n.Selection = f1 n.SetType(f1.Type) diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index 799cf3a1f6..4c7378560c 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -141,6 +141,8 @@ func expandiface(t *Type) { } func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 { + // flag is 0 (receiver), 1 (actual struct), or RegSize (in/out parameters) + isStruct := flag == 1 starto := o maxalign := int32(flag) if maxalign < 1 { @@ -161,7 +163,9 @@ func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 { if f.Type.Align > 0 { o = Rnd(o, int64(f.Type.Align)) } - f.Offset = o + if isStruct { // For receiver/args/results, depends on ABI + f.Offset = o + } if f.Nname != nil { // addrescapes has similar code to update these offsets. // Usually addrescapes runs after calcStructOffset, diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 9fb6d68994..b0516a8259 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -411,7 +411,8 @@ type Field struct { Nname Object // Offset in bytes of this field or method within its enclosing struct - // or interface Type. + // or interface Type. Exception: if field is function receiver, arg or + // result, then this is BOGUS_FUNARG_OFFSET; types does not know the Abi. Offset int64 } @@ -1719,6 +1720,14 @@ func NewTypeParam(pkg *Pkg, constraint *Type) *Type { return t } +const BOGUS_FUNARG_OFFSET = 1000000000 + +func unzeroFieldOffsets(f []*Field) { + for i := range f { + f[i].Offset = BOGUS_FUNARG_OFFSET // This will cause an explosion if it is not corrected + } +} + // NewSignature returns a new function type for the given receiver, // parametes, results, and type parameters, any of which may be nil. func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Type { @@ -1739,6 +1748,11 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ return s } + if recv != nil { + recv.Offset = BOGUS_FUNARG_OFFSET + } + unzeroFieldOffsets(params) + unzeroFieldOffsets(results) ft.Receiver = funargs(recvs, FunargRcvr) ft.TParams = funargs(tparams, FunargTparams) ft.Params = funargs(params, FunargParams) diff --git a/src/cmd/compile/internal/walk/assign.go b/src/cmd/compile/internal/walk/assign.go index 230b544148..44622c741d 100644 --- a/src/cmd/compile/internal/walk/assign.go +++ b/src/cmd/compile/internal/walk/assign.go @@ -270,7 +270,7 @@ func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node { } res := ir.NewResultExpr(base.Pos, nil, types.BADWIDTH) - res.Offset = base.Ctxt.FixedFrameSize() + r.Offset + res.Index = int64(i) res.SetType(r.Type) res.SetTypecheck(1) -- GitLab From 84ca4949a71554265b3c8a99359a5fad6ca0cab1 Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 2 Mar 2021 06:08:51 +0000 Subject: [PATCH 0156/1298] cmd/compile: remove 8-byte alignment requirement of stack slot on mips64 This CL applies CL 267999 to mips64. Updates #42385 Change-Id: Ideab21be0d8c1a36b3be7411b24adac70a3d16e0 Reviewed-on: https://go-review.googlesource.com/c/go/+/297771 Reviewed-by: eric fang Reviewed-by: Keith Randall Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot --- src/cmd/compile/internal/ssagen/pgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 25b09e1f5d..717f1118f6 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -138,7 +138,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { + if Arch.LinkArch.InFamily(sys.MIPS, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) } n.SetFrameOffset(-s.stksize) -- GitLab From 06c72f3627ea749d8579d0d590fd715b2d5e512f Mon Sep 17 00:00:00 2001 From: Baokun Lee Date: Mon, 14 Dec 2020 19:39:02 +0800 Subject: [PATCH 0157/1298] A+C: change email address for Baokun Lee Change-Id: Ib82e1c8c549c91e20c5aff5e50736617c6831f8c Reviewed-on: https://go-review.googlesource.com/c/go/+/277792 Run-TryBot: Baokun Lee Reviewed-by: Ian Lance Taylor TryBot-Result: Go Bot Trust: Alberto Donizetti --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4828ba36cc..eb05706811 100644 --- a/AUTHORS +++ b/AUTHORS @@ -195,7 +195,7 @@ Ayanamist Yang Aymerick Jéhanne Azat Kaumov Baiju Muthukadan -Baokun Lee +Baokun Lee Bartosz Grzybowski Bastian Ike Ben Burkert diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ccbe4627f3..b176a03328 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -321,7 +321,7 @@ Azat Kaumov Baiju Muthukadan Balaram Makam Balazs Lecz -Baokun Lee +Baokun Lee Barnaby Keene Bartosz Grzybowski Bartosz Oler -- GitLab From f2df1e3c34ceb2225d0df5c9ec92d5dc9e9ba919 Mon Sep 17 00:00:00 2001 From: David Chase Date: Sat, 13 Feb 2021 10:49:37 -0500 Subject: [PATCH 0158/1298] cmd/compile: retrieve Args from registers in progress; doesn't fully work until they are also passed on register on the caller side. For #40724. Change-Id: I29a6680e60bdbe9d132782530214f2a2b51fb8f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/293394 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 7 ++++++ src/cmd/compile/internal/amd64/ssa.go | 2 ++ src/cmd/compile/internal/ssa/expand_calls.go | 24 ++++++++++++++++---- src/cmd/compile/internal/ssa/lower.go | 6 ++++- src/cmd/compile/internal/ssa/regalloc.go | 23 +++++++++++++++---- src/cmd/compile/internal/ssa/rewrite.go | 2 -- src/cmd/compile/internal/ssa/schedule.go | 2 +- src/cmd/compile/internal/ssagen/ssa.go | 12 +++++++++- 8 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 8549c0325d..903cc5205d 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -158,6 +158,13 @@ func (a *ABIConfig) LocalsOffset() int64 { return a.offsetForLocals } +// FloatIndexFor translates r into an index in the floating point parameter +// registers. If the result is negative, the input index was actually for the +// integer parameter registers. +func (a *ABIConfig) FloatIndexFor(r RegIndex) int64 { + return int64(r) - int64(a.regAmounts.intRegs) +} + // NumParamRegs returns the number of parameter registers used for a given type, // without regard for the number available. func (a *ABIConfig) NumParamRegs(t *types.Type) int { diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index d83d78f080..3c43a1d41b 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -980,6 +980,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() + case ssa.OpArgIntReg, ssa.OpArgFloatReg: + ssagen.CheckArgReg(v) case ssa.OpAMD64LoweredGetClosurePtr: // Closure pointer is DX. ssagen.CheckLoweredGetClosurePtr(v) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 741d59258b..68fb0581f6 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -808,9 +808,9 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { } auxI := int64(i - firstArg) aRegs := aux.RegsOfArg(auxI) - aOffset := aux.OffsetOfArg(auxI) aType := aux.TypeOfArg(auxI) if a.Op == OpDereference { + aOffset := aux.OffsetOfArg(auxI) if a.MemoryArg() != m0 { x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString()) } @@ -821,13 +821,16 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { // TODO(register args) this will be more complicated with registers in the picture. mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos) } else { - if x.debug { - fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) - } var rc registerCursor var result *[]*Value + var aOffset int64 if len(aRegs) > 0 { result = &allResults + } else { + aOffset = aux.OffsetOfArg(auxI) + } + if x.debug { + fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) } rc.init(aRegs, aux.abiInfo, result) mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc) @@ -1213,8 +1216,19 @@ func expandCalls(f *Func) { pa.Offset(), frameOff, v.LongString())) } case 1: + r := pa.Registers[0] + i := f.ABISelf.FloatIndexFor(r) + // TODO seems like this has implications for debugging. How does this affect the location? + if i >= 0 { // float PR + v.Op = OpArgFloatReg + } else { + v.Op = OpArgIntReg + i = int64(r) + } + v.AuxInt = i + default: - panic(badVal("Saw unexpeanded OpArg", v)) + panic(badVal("Saw unexpanded OpArg", v)) } case OpStaticLECall: diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index f6b2bf86a9..bbb80a7a30 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,8 +21,12 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark: + case OpSP, OpSB, OpInitMem, OpArg, OpArgIntReg, OpArgFloatReg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark: continue // ok not to lower + case OpMakeResult: + if len(b.Controls) == 1 && b.Controls[0] == v { + continue + } case OpGetG: if f.Config.hasGReg { // has hardware g register, regalloc takes care of it diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 99e101281b..74dd70c3d9 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -800,7 +800,8 @@ func (s *regAllocState) compatRegs(t *types.Type) regMask { } // regspec returns the regInfo for operation op. -func (s *regAllocState) regspec(op Op) regInfo { +func (s *regAllocState) regspec(v *Value) regInfo { + op := v.Op if op == OpConvert { // OpConvert is a generic op, so it doesn't have a // register set in the static table. It can use any @@ -808,6 +809,20 @@ func (s *regAllocState) regspec(op Op) regInfo { m := s.allocatable & s.f.Config.gpRegMask return regInfo{inputs: []inputInfo{{regs: m}}, outputs: []outputInfo{{regs: m}}} } + if op == OpArgIntReg { + reg := v.Block.Func.Config.intParamRegs[v.AuxInt8()] + return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}} + } + if op == OpArgFloatReg { + reg := v.Block.Func.Config.floatParamRegs[v.AuxInt8()] + return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}} + } + if op.IsCall() { + // TODO Panic if not okay + if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil { + return *ac.reg + } + } return opcodeTable[op].reg } @@ -1163,7 +1178,7 @@ func (s *regAllocState) regalloc(f *Func) { for i := len(oldSched) - 1; i >= 0; i-- { v := oldSched[i] prefs := desired.remove(v.ID) - regspec := s.regspec(v.Op) + regspec := s.regspec(v) desired.clobber(regspec.clobbers) for _, j := range regspec.inputs { if countRegs(j.regs) != 1 { @@ -1193,7 +1208,7 @@ func (s *regAllocState) regalloc(f *Func) { if s.f.pass.debug > regDebug { fmt.Printf(" processing %s\n", v.LongString()) } - regspec := s.regspec(v.Op) + regspec := s.regspec(v) if v.Op == OpPhi { f.Fatalf("phi %s not at start of block", v) } @@ -2447,7 +2462,7 @@ func (s *regAllocState) computeLive() { // desired registers back though phi nodes. continue } - regspec := s.regspec(v.Op) + regspec := s.regspec(v) // Cancel desired registers if they get clobbered. desired.clobber(regspec.clobbers) // Update desired registers if there are any fixed register inputs. diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 19b97a3ed1..9243000cef 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -795,8 +795,6 @@ func devirtLECall(v *Value, sym *obj.LSym) *Value { v.Op = OpStaticLECall auxcall := v.Aux.(*AuxCall) auxcall.Fn = sym - // TODO(register args) this should not be necessary when fully transition to the new register ABI. - auxcall.abiInfo = v.Block.Func.ABIDefault.ABIAnalyzeTypes(nil, ACParamsToTypes(auxcall.args), ACParamsToTypes(auxcall.results)) v.RemoveArg(0) return v } diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index 6b34310db7..c987647131 100644 --- a/src/cmd/compile/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go @@ -137,7 +137,7 @@ func schedule(f *Func) { case v.Op == OpVarDef: // We want all the vardefs next. score[v.ID] = ScoreVarDef - case v.Op == OpArg: + case v.Op == OpArg || v.Op == OpArgIntReg || v.Op == OpArgFloatReg: // We want all the args as early as possible, for better debugging. score[v.ID] = ScoreArg case v.Type.IsMemory(): diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 210150d872..9088ce333b 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -485,7 +485,8 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false) } - params := s.f.ABISelf.ABIAnalyze(fn.Type()) + var params *abi.ABIParamResultInfo + params = s.f.ABISelf.ABIAnalyze(fn.Type()) // Generate addresses of local declarations s.decladdrs = map[*ir.Name]*ssa.Value{} @@ -7019,11 +7020,20 @@ func CheckLoweredPhi(v *ssa.Value) { // That register contains the closure pointer on closure entry. func CheckLoweredGetClosurePtr(v *ssa.Value) { entry := v.Block.Func.Entry + // TODO register args: not all the register-producing ops can come first. if entry != v.Block || entry.Values[0] != v { base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v) } } +// CheckArgReg ensures that v is in the function's entry block. +func CheckArgReg(v *ssa.Value) { + entry := v.Block.Func.Entry + if entry != v.Block { + base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v) + } +} + func AddrAuto(a *obj.Addr, v *ssa.Value) { n, off := ssa.AutoVar(v) a.Type = obj.TYPE_MEM -- GitLab From 00cb841b83ad157bc21d36daf0626bbcd4af0d57 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Tue, 7 May 2019 17:56:49 +1000 Subject: [PATCH 0159/1298] syscall: implement rawVforkSyscall for remaining linux platforms This allows the use of CLONE_VFORK and CLONE_VM for fork/exec, preventing 'fork/exec ...: cannot allocate memory' failures from occuring when attempting to execute commands from a Go process that has a large memory footprint. Additionally, this should reduce the latency of fork/exec on these platforms. Fixes #31936 Change-Id: I4e28cf0763173145cacaa5340680dca9ff449305 Reviewed-on: https://go-review.googlesource.com/c/go/+/295849 Trust: Joel Sing Run-TryBot: Joel Sing Reviewed-by: Cherry Zhang --- src/syscall/asm_linux_386.s | 20 ++++++++++++++++++++ src/syscall/asm_linux_amd64.s | 2 +- src/syscall/asm_linux_arm.s | 21 +++++++++++++++++++++ src/syscall/asm_linux_arm64.s | 1 - src/syscall/asm_linux_mips64x.s | 20 ++++++++++++++++++++ src/syscall/asm_linux_mipsx.s | 17 +++++++++++++++++ src/syscall/exec_linux.go | 8 +------- src/syscall/syscall_linux_386.go | 4 +--- src/syscall/syscall_linux_arm.go | 4 +--- src/syscall/syscall_linux_mips64x.go | 4 +--- src/syscall/syscall_linux_mipsx.go | 4 +--- 11 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s index 4201f367ba..1c69083118 100644 --- a/src/syscall/asm_linux_386.s +++ b/src/syscall/asm_linux_386.s @@ -110,6 +110,26 @@ ok2: MOVL $0, err+36(FP) RET +// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr) +TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-16 + MOVL trap+0(FP), AX // syscall entry + MOVL a1+4(FP), BX + MOVL $0, CX + MOVL $0, DX + POPL SI // preserve return address + INVOKE_SYSCALL + PUSHL SI + CMPL AX, $0xfffff001 + JLS ok + MOVL $-1, r1+8(FP) + NEGL AX + MOVL AX, err+12(FP) + RET +ok: + MOVL AX, r1+8(FP) + MOVL $0, err+12(FP) + RET + // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr); TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-24 MOVL trap+0(FP), AX // syscall entry diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s index ba22179dc2..a9af68d51d 100644 --- a/src/syscall/asm_linux_amd64.s +++ b/src/syscall/asm_linux_amd64.s @@ -108,7 +108,7 @@ ok2: RET // func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr) -TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-32 +TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-32 MOVQ a1+8(FP), DI MOVQ $0, SI MOVQ $0, DX diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s index 458e9cce79..6bb4df81a0 100644 --- a/src/syscall/asm_linux_arm.s +++ b/src/syscall/asm_linux_arm.s @@ -154,6 +154,27 @@ ok1: MOVW R0, err+24(FP) RET +// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr) +TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-16 + MOVW trap+0(FP), R7 // syscall entry + MOVW a1+4(FP), R0 + MOVW $0, R1 + MOVW $0, R2 + SWI $0 + MOVW $0xfffff001, R1 + CMP R1, R0 + BLS ok + MOVW $-1, R1 + MOVW R1, r1+8(FP) + RSB $0, R0, R0 + MOVW R0, err+12(FP) + RET +ok: + MOVW R0, r1+8(FP) + MOVW $0, R0 + MOVW R0, err+12(FP) + RET + // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr); TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-24 MOVW trap+0(FP), R7 // syscall entry diff --git a/src/syscall/asm_linux_arm64.s b/src/syscall/asm_linux_arm64.s index fb22f8d547..a30e4d87d4 100644 --- a/src/syscall/asm_linux_arm64.s +++ b/src/syscall/asm_linux_arm64.s @@ -125,7 +125,6 @@ ok: MOVD ZR, err+24(FP) // errno RET - // func rawSyscallNoError(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr); TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48 MOVD a1+8(FP), R0 diff --git a/src/syscall/asm_linux_mips64x.s b/src/syscall/asm_linux_mips64x.s index d0b0e5a0a8..b3ae59023d 100644 --- a/src/syscall/asm_linux_mips64x.s +++ b/src/syscall/asm_linux_mips64x.s @@ -102,6 +102,26 @@ ok2: MOVV R0, err+72(FP) // errno RET +// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr) +TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-32 + MOVV a1+8(FP), R4 + MOVV R0, R5 + MOVV R0, R6 + MOVV R0, R7 + MOVV R0, R8 + MOVV R0, R9 + MOVV trap+0(FP), R2 // syscall entry + SYSCALL + BEQ R7, ok + MOVV $-1, R1 + MOVV R1, r1+16(FP) // r1 + MOVV R2, err+24(FP) // errno + RET +ok: + MOVV R2, r1+16(FP) // r1 + MOVV R0, err+24(FP) // errno + RET + TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48 MOVV a1+8(FP), R4 MOVV a2+16(FP), R5 diff --git a/src/syscall/asm_linux_mipsx.s b/src/syscall/asm_linux_mipsx.s index 5727e4d41d..ee436490b2 100644 --- a/src/syscall/asm_linux_mipsx.s +++ b/src/syscall/asm_linux_mipsx.s @@ -139,6 +139,23 @@ ok2: MOVW R0, err+36(FP) // errno RET +// func rawVforkSyscall(trap, a1 uintptr) (r1, err uintptr) +TEXT ·rawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-16 + MOVW a1+4(FP), R4 + MOVW R0, R5 + MOVW R0, R6 + MOVW trap+0(FP), R2 // syscall entry + SYSCALL + BEQ R7, ok + MOVW $-1, R1 + MOVW R1, r1+8(FP) // r1 + MOVW R2, err+12(FP) // errno + RET +ok: + MOVW R2, r1+8(FP) // r1 + MOVW R0, err+12(FP) // errno + RET + TEXT ·rawSyscallNoError(SB),NOSPLIT,$20-24 MOVW a1+4(FP), R4 MOVW a2+8(FP), R5 diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index b0099cb4b0..6353da4048 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -208,18 +208,12 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att } } - var hasRawVforkSyscall bool - switch runtime.GOARCH { - case "amd64", "arm64", "ppc64", "riscv64", "s390x": - hasRawVforkSyscall = true - } - // About to call fork. // No more allocation or calls of non-assembly functions. runtime_BeforeFork() locked = true switch { - case hasRawVforkSyscall && (sys.Cloneflags&CLONE_NEWUSER == 0 && sys.Unshareflags&CLONE_NEWUSER == 0): + case sys.Cloneflags&CLONE_NEWUSER == 0 && sys.Unshareflags&CLONE_NEWUSER == 0: r1, err1 = rawVforkSyscall(SYS_CLONE, uintptr(SIGCHLD|CLONE_VFORK|CLONE_VM)|sys.Cloneflags) case runtime.GOARCH == "s390x": r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0) diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go index ed52647403..0db037470d 100644 --- a/src/syscall/syscall_linux_386.go +++ b/src/syscall/syscall_linux_386.go @@ -387,6 +387,4 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) { - panic("not implemented") -} +func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go index 4a3729f898..e887cf788f 100644 --- a/src/syscall/syscall_linux_arm.go +++ b/src/syscall/syscall_linux_arm.go @@ -236,6 +236,4 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) { - panic("not implemented") -} +func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go index dd51f3d00a..5feb03e915 100644 --- a/src/syscall/syscall_linux_mips64x.go +++ b/src/syscall/syscall_linux_mips64x.go @@ -214,6 +214,4 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } -func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) { - panic("not implemented") -} +func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go index 7894bdd465..39104d71d8 100644 --- a/src/syscall/syscall_linux_mipsx.go +++ b/src/syscall/syscall_linux_mipsx.go @@ -224,6 +224,4 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } -func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) { - panic("not implemented") -} +func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) -- GitLab From 497feff168b44bdcb645ab0c2a956b0033d6100d Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 27 Feb 2021 19:07:32 +1100 Subject: [PATCH 0160/1298] cmd/compile: intrinsify runtime/internal/atomic.{And,Or}{8,} on RISCV64 The 32 bit versions are easily implement with a single instruction, while the 8 bit versions require a bit more effort but use the same atomic instructions via rewrite rules. Change-Id: I42e8d457b239c8f75e39a8e282fc88c1bb292a99 Reviewed-on: https://go-review.googlesource.com/c/go/+/268098 Trust: Joel Sing Run-TryBot: Joel Sing TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/riscv64/ssa.go | 8 ++ .../compile/internal/ssa/gen/RISCV64.rules | 16 ++++ .../compile/internal/ssa/gen/RISCV64Ops.go | 8 +- src/cmd/compile/internal/ssa/opGen.go | 28 +++++++ .../compile/internal/ssa/rewriteRISCV64.go | 75 +++++++++++++++++++ 5 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/riscv64/ssa.go b/src/cmd/compile/internal/riscv64/ssa.go index 0a3064323a..5576dd4e48 100644 --- a/src/cmd/compile/internal/riscv64/ssa.go +++ b/src/cmd/compile/internal/riscv64/ssa.go @@ -510,6 +510,14 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p6 := s.Prog(obj.ANOP) p2.To.SetTarget(p6) + case ssa.OpRISCV64LoweredAtomicAnd32, ssa.OpRISCV64LoweredAtomicOr32: + p := s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_REG + p.From.Reg = v.Args[1].Reg() + p.To.Type = obj.TYPE_MEM + p.To.Reg = v.Args[0].Reg() + p.RegTo2 = riscv.REG_ZERO + case ssa.OpRISCV64LoweredZero: mov, sz := largestMove(v.AuxInt) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules index a11d1e6624..d7efef039e 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules @@ -564,12 +564,28 @@ (AtomicAdd32 ...) => (LoweredAtomicAdd32 ...) (AtomicAdd64 ...) => (LoweredAtomicAdd64 ...) +// AtomicAnd8(ptr,val) => LoweredAtomicAnd32(ptr&^3, ^((uint8(val) ^ 0xff) << ((ptr & 3) * 8))) +(AtomicAnd8 ptr val mem) => + (LoweredAtomicAnd32 (ANDI [^3] ptr) + (NOT (SLL (XORI [0xff] (ZeroExt8to32 val)) + (SLLI [3] (ANDI [3] ptr)))) mem) + +(AtomicAnd32 ...) => (LoweredAtomicAnd32 ...) + (AtomicCompareAndSwap32 ...) => (LoweredAtomicCas32 ...) (AtomicCompareAndSwap64 ...) => (LoweredAtomicCas64 ...) (AtomicExchange32 ...) => (LoweredAtomicExchange32 ...) (AtomicExchange64 ...) => (LoweredAtomicExchange64 ...) +// AtomicOr8(ptr,val) => LoweredAtomicOr32(ptr&^3, uint32(val)<<((ptr&3)*8)) +(AtomicOr8 ptr val mem) => + (LoweredAtomicOr32 (ANDI [^3] ptr) + (SLL (ZeroExt8to32 val) + (SLLI [3] (ANDI [3] ptr))) mem) + +(AtomicOr32 ...) => (LoweredAtomicOr32 ...) + // Conditional branches (If cond yes no) => (BNEZ cond yes no) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go index f64319230b..92a0c3c84c 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go @@ -126,6 +126,7 @@ func init() { gp11sb = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}} gpxchg = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}} gpcas = regInfo{inputs: []regMask{gpspsbgMask, gpgMask, gpgMask}, outputs: []regMask{gpMask}} + gpatomic = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}} fp11 = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}} fp21 = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}} @@ -335,7 +336,7 @@ func init() { {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true}, // Atomic stores. - // store arg1 to arg0. arg2=mem. returns memory. + // store arg1 to *arg0. arg2=mem. returns memory. {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, @@ -367,6 +368,11 @@ func init() { {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + // Atomic 32 bit AND/OR. + // *arg0 &= (|=) arg1. arg2=mem. returns nil. + {name: "LoweredAtomicAnd32", argLength: 3, reg: gpatomic, asm: "AMOANDW", faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicOr32", argLength: 3, reg: gpatomic, asm: "AMOORW", faultOnNilArg0: true, hasSideEffects: true}, + // Lowering pass-throughs {name: "LoweredNilCheck", argLength: 2, faultOnNilArg0: true, nilCheck: true, reg: regInfo{inputs: []regMask{gpspMask}}}, // arg0=ptr,arg1=mem, returns void. Faults if ptr is nil. {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{regCtxt}}}, // scheduler ensures only at beginning of entry block diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index bd9741fe3e..a26eec680f 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -2149,6 +2149,8 @@ const ( OpRISCV64LoweredAtomicAdd64 OpRISCV64LoweredAtomicCas32 OpRISCV64LoweredAtomicCas64 + OpRISCV64LoweredAtomicAnd32 + OpRISCV64LoweredAtomicOr32 OpRISCV64LoweredNilCheck OpRISCV64LoweredGetClosurePtr OpRISCV64LoweredGetCallerSP @@ -28722,6 +28724,32 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "LoweredAtomicAnd32", + argLen: 3, + faultOnNilArg0: true, + hasSideEffects: true, + asm: riscv.AAMOANDW, + reg: regInfo{ + inputs: []inputInfo{ + {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 + {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB + }, + }, + }, + { + name: "LoweredAtomicOr32", + argLen: 3, + faultOnNilArg0: true, + hasSideEffects: true, + asm: riscv.AAMOORW, + reg: regInfo{ + inputs: []inputInfo{ + {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 + {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB + }, + }, + }, { name: "LoweredNilCheck", argLen: 2, diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index 36e152bd99..7f77477da7 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -52,6 +52,11 @@ func rewriteValueRISCV64(v *Value) bool { case OpAtomicAdd64: v.Op = OpRISCV64LoweredAtomicAdd64 return true + case OpAtomicAnd32: + v.Op = OpRISCV64LoweredAtomicAnd32 + return true + case OpAtomicAnd8: + return rewriteValueRISCV64_OpAtomicAnd8(v) case OpAtomicCompareAndSwap32: v.Op = OpRISCV64LoweredAtomicCas32 return true @@ -76,6 +81,11 @@ func rewriteValueRISCV64(v *Value) bool { case OpAtomicLoadPtr: v.Op = OpRISCV64LoweredAtomicLoad64 return true + case OpAtomicOr32: + v.Op = OpRISCV64LoweredAtomicOr32 + return true + case OpAtomicOr8: + return rewriteValueRISCV64_OpAtomicOr8(v) case OpAtomicStore32: v.Op = OpRISCV64LoweredAtomicStore32 return true @@ -681,6 +691,71 @@ func rewriteValueRISCV64_OpAddr(v *Value) bool { return true } } +func rewriteValueRISCV64_OpAtomicAnd8(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (AtomicAnd8 ptr val mem) + // result: (LoweredAtomicAnd32 (ANDI [^3] ptr) (NOT (SLL (XORI [0xff] (ZeroExt8to32 val)) (SLLI [3] (ANDI [3] ptr)))) mem) + for { + ptr := v_0 + val := v_1 + mem := v_2 + v.reset(OpRISCV64LoweredAtomicAnd32) + v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Uintptr) + v0.AuxInt = int64ToAuxInt(^3) + v0.AddArg(ptr) + v1 := b.NewValue0(v.Pos, OpRISCV64NOT, typ.UInt32) + v2 := b.NewValue0(v.Pos, OpRISCV64SLL, typ.UInt32) + v3 := b.NewValue0(v.Pos, OpRISCV64XORI, typ.UInt32) + v3.AuxInt = int64ToAuxInt(0xff) + v4 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32) + v4.AddArg(val) + v3.AddArg(v4) + v5 := b.NewValue0(v.Pos, OpRISCV64SLLI, typ.UInt64) + v5.AuxInt = int64ToAuxInt(3) + v6 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.UInt64) + v6.AuxInt = int64ToAuxInt(3) + v6.AddArg(ptr) + v5.AddArg(v6) + v2.AddArg2(v3, v5) + v1.AddArg(v2) + v.AddArg3(v0, v1, mem) + return true + } +} +func rewriteValueRISCV64_OpAtomicOr8(v *Value) bool { + v_2 := v.Args[2] + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types + // match: (AtomicOr8 ptr val mem) + // result: (LoweredAtomicOr32 (ANDI [^3] ptr) (SLL (ZeroExt8to32 val) (SLLI [3] (ANDI [3] ptr))) mem) + for { + ptr := v_0 + val := v_1 + mem := v_2 + v.reset(OpRISCV64LoweredAtomicOr32) + v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Uintptr) + v0.AuxInt = int64ToAuxInt(^3) + v0.AddArg(ptr) + v1 := b.NewValue0(v.Pos, OpRISCV64SLL, typ.UInt32) + v2 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32) + v2.AddArg(val) + v3 := b.NewValue0(v.Pos, OpRISCV64SLLI, typ.UInt64) + v3.AuxInt = int64ToAuxInt(3) + v4 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.UInt64) + v4.AuxInt = int64ToAuxInt(3) + v4.AddArg(ptr) + v3.AddArg(v4) + v1.AddArg2(v2, v3) + v.AddArg3(v0, v1, mem) + return true + } +} func rewriteValueRISCV64_OpAvg64u(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] -- GitLab From 85f62b09413ea043623f7f6905a4d1426908e6a2 Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 2 Mar 2021 05:53:49 +0000 Subject: [PATCH 0161/1298] cmd/compile: remove 8-byte alignment requirement of stack slot on mips This CL applies CL 267999 to mips. Updates #42385 Change-Id: I8096e16c1b4def767b0c20c16add36fa2406bcab Reviewed-on: https://go-review.googlesource.com/c/go/+/297772 Reviewed-by: Keith Randall Trust: eric fang --- src/cmd/compile/internal/ssagen/pgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 717f1118f6..9b81d14f7e 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -138,7 +138,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.MIPS, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { + if Arch.LinkArch.InFamily(sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) } n.SetFrameOffset(-s.stksize) -- GitLab From c4e3f6c4c78f52060d409a549b83b72644069137 Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 2 Mar 2021 06:10:58 +0000 Subject: [PATCH 0162/1298] cmd/compile: remove 8-byte alignment requirement of stack slot on s390x This CL applies CL 267999 to s390x. Updates #42385 Change-Id: Ie8e69ad1b3f7ddc2c8f05125f4af617aeac035ec Reviewed-on: https://go-review.googlesource.com/c/go/+/297769 Reviewed-by: Keith Randall Trust: eric fang --- src/cmd/compile/internal/ssagen/pgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 9b81d14f7e..b675d1c876 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -138,7 +138,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { + if Arch.LinkArch.InFamily(sys.ARM, sys.ARM64, sys.PPC64) { s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) } n.SetFrameOffset(-s.stksize) -- GitLab From 9f33dc3ca1b7b6bdb1a8e83c24d490f579bbbdc8 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 17 Feb 2021 10:38:03 -0500 Subject: [PATCH 0163/1298] cmd/compile: handle aggregate OpArg in registers Also handles case where OpArg does not escape but has its address taken. May have exposed a lurking bug in 1.16 expandCalls, if e.g., loading len(someArrayOfstructThing[0].secondStringField) from a local. Maybe. For #40724. Change-Id: I0298c4ad5d652b5e3d7ed6a62095d59e2d8819c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/293396 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/amd64/ssa.go | 2 - src/cmd/compile/internal/ssa/expand_calls.go | 250 +++++++++++++------ src/cmd/compile/internal/ssa/op.go | 10 + src/cmd/compile/internal/ssa/regalloc.go | 3 + src/cmd/compile/internal/ssa/stackalloc.go | 15 +- src/cmd/compile/internal/ssa/tighten.go | 2 +- src/cmd/compile/internal/ssagen/ssa.go | 36 ++- 7 files changed, 225 insertions(+), 93 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 3c43a1d41b..d83d78f080 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -980,8 +980,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpArgIntReg, ssa.OpArgFloatReg: - ssagen.CheckArgReg(v) case ssa.OpAMD64LoweredGetClosurePtr: // Closure pointer is DX. ssagen.CheckLoweredGetClosurePtr(v) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 68fb0581f6..87b8a02b25 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -158,23 +158,24 @@ func (c *registerCursor) hasRegs() bool { } type expandState struct { - f *Func - abi1 *abi.ABIConfig - debug bool - canSSAType func(*types.Type) bool - regSize int64 - sp *Value - typs *Types - ptrSize int64 - hiOffset int64 - lowOffset int64 - hiRo Abi1RO - loRo Abi1RO - namedSelects map[*Value][]namedVal - sdom SparseTree - common map[selKey]*Value - offsets map[offsetKey]*Value - memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. + f *Func + abi1 *abi.ABIConfig + debug bool + canSSAType func(*types.Type) bool + regSize int64 + sp *Value + typs *Types + ptrSize int64 + hiOffset int64 + lowOffset int64 + hiRo Abi1RO + loRo Abi1RO + namedSelects map[*Value][]namedVal + sdom SparseTree + commonSelectors map[selKey]*Value // used to de-dupe selectors + commonArgs map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg + offsets map[offsetKey]*Value + memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. } // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target @@ -238,14 +239,20 @@ func (x *expandState) prAssignForArg(v *Value) abi.ABIParamAssignment { if v.Op != OpArg { panic(badVal("Wanted OpArg, instead saw", v)) } - name := v.Aux.(*ir.Name) - fPri := x.f.OwnAux.abiInfo - for _, a := range fPri.InParams() { + return ParamAssignmentForArgName(x.f, v.Aux.(*ir.Name)) +} + +// ParamAssignmentForArgName returns the ABIParamAssignment for f's arg with matching name. +func ParamAssignmentForArgName(f *Func, name *ir.Name) abi.ABIParamAssignment { + abiInfo := f.OwnAux.abiInfo + // This is unfortunate, but apparently the only way. + // TODO after register args stabilize, find a better way + for _, a := range abiInfo.InParams() { if a.Name == name { return a } } - panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, fPri.InParams())) + panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, abiInfo.InParams())) } // Calls that need lowering have some number of inputs, including a memory input, @@ -284,7 +291,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, case OpArg: if !x.isAlreadyExpandedAggregateType(selector.Type) { if leafType == selector.Type { // OpIData leads us here, sometimes. - leaf.copyOf(selector) + x.newArgToMemOrRegs(selector, leaf, offset, regOffset, leafType, leaf.Pos) } else { x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString()) } @@ -297,20 +304,8 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, case OpIData, OpStructSelect, OpArraySelect: leafType = removeTrivialWrapperTypes(leaf.Type) } - aux := selector.Aux - auxInt := selector.AuxInt + offset - if leaf.Block == selector.Block { - leaf.reset(OpArg) - leaf.Aux = aux - leaf.AuxInt = auxInt - leaf.Type = leafType - } else { - w := selector.Block.NewValue0IA(leaf.Pos, OpArg, leafType, auxInt, aux) - leaf.copyOf(w) - if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) - } - } + x.newArgToMemOrRegs(selector, leaf, offset, regOffset, leafType, leaf.Pos) + for _, s := range x.namedSelects[selector] { locs = append(locs, x.f.Names[s.locIndex]) } @@ -519,8 +514,23 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, // decomposeArgOrLoad is a helper for storeArgOrLoad. // It decomposes a Load or an Arg into smaller parts, parameterized by the decomposeOne and decomposeTwo functions -// passed to it, and returns the new mem. If the type does not match one of the expected aggregate types, it returns nil instead. +// passed to it, and returns the new mem. +// If the type does not match one of the expected aggregate types, it returns nil instead. +// Parameters: +// pos -- the location of any generated code. +// b -- the block into which any generated code should normally be placed +// base -- for the stores that will ultimately be generated, the base to which the offset is applied. (Note this disappears in a future CL, folded into storeRc) +// source -- the value, possibly an aggregate, to be stored. +// mem -- the mem flowing into this decomposition (loads depend on it, stores updated it) +// t -- the type of the value to be stored +// offset -- if the value is stored in memory, it is stored at base + offset +// loadRegOffset -- regarding source as a value in registers, the register offset in ABI1. Meaningful only if source is OpArg. +// storeRc -- storeRC; if the value is stored in registers, this specifies the registers. StoreRc also identifies whether the target is registers or memory. +// +// TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates. func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor, + // For decompose One and Two, the additional offArg provides the offset from the beginning of "source", if it is in memory. + // offStore is combined to base to obtain a store destionation, like "offset" of decomposeArgOrLoad decomposeOne func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value, decomposeTwo func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value { u := source.Type @@ -530,7 +540,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m elemRO := x.regWidth(elem) for i := int64(0); i < u.NumElem(); i++ { elemOff := i * elem.Size() - mem = decomposeOne(x, pos, b, base, source, mem, elem, source.AuxInt+elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) + mem = decomposeOne(x, pos, b, base, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) loadRegOffset += elemRO pos = pos.WithNotStmt() } @@ -538,7 +548,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m case types.TSTRUCT: for i := 0; i < u.NumFields(); i++ { fld := u.Field(i) - mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, source.AuxInt+fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -548,20 +558,20 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m break } tHi, tLo := x.intPairTypes(t.Kind()) - mem = decomposeOne(x, pos, b, base, source, mem, tHi, source.AuxInt+x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = decomposeOne(x, pos, b, base, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() - return decomposeOne(x, pos, b, base, source, mem, tLo, source.AuxInt+x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) + return decomposeOne(x, pos, b, base, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) case types.TINTER: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, source.AuxInt, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) case types.TSTRING: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, source.AuxInt, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX64: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, source.AuxInt, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX128: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, source.AuxInt, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) case types.TSLICE: - mem = decomposeOne(x, pos, b, base, source, mem, x.typs.BytePtr, source.AuxInt, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Int, x.typs.Int, source.AuxInt+x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) + mem = decomposeOne(x, pos, b, base, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return decomposeTwo(x, pos, b, base, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) } return nil } @@ -570,10 +580,11 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m // pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - w := x.common[selKey{source, offArg, t.Width, t}] + w := x.commonArgs[selKey{source, offArg, t.Width, t}] if w == nil { - w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux) - x.common[selKey{source, offArg, t.Width, t}] = w + // w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux) + w = x.newArgToMemOrRegs(source, w, offArg, loadRegOffset, t, pos) + // x.commonArgs[selKey{source, offArg, t.Width, t}] = w } return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc) } @@ -867,7 +878,7 @@ func expandCalls(f *Func) { ptrSize: f.Config.PtrSize, namedSelects: make(map[*Value][]namedVal), sdom: f.Sdom(), - common: make(map[selKey]*Value), + commonArgs: make(map[selKey]*Value), offsets: make(map[offsetKey]*Value), memForCall: make(map[ID]*Value), } @@ -1110,7 +1121,7 @@ func expandCalls(f *Func) { } } - x.common = make(map[selKey]*Value) + x.commonSelectors = make(map[selKey]*Value) // Rewrite duplicate selectors as copies where possible. for i := len(allOrdered) - 1; i >= 0; i-- { v := allOrdered[i] @@ -1153,15 +1164,15 @@ func expandCalls(f *Func) { offset = size } sk := selKey{from: w, size: size, offset: offset, typ: typ} - dupe := x.common[sk] + dupe := x.commonSelectors[sk] if dupe == nil { - x.common[sk] = v + x.commonSelectors[sk] = v } else if x.sdom.IsAncestorEq(dupe.Block, v.Block) { v.copyOf(dupe) } else { // Because values are processed in dominator order, the old common[s] will never dominate after a miss is seen. // Installing the new value might match some future values. - x.common[sk] = v + x.commonSelectors[sk] = v } } @@ -1207,30 +1218,7 @@ func expandCalls(f *Func) { for _, v := range b.Values { switch v.Op { case OpArg: - pa := x.prAssignForArg(v) - switch len(pa.Registers) { - case 0: - frameOff := v.Aux.(*ir.Name).FrameOffset() - if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) { - panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s\n", - pa.Offset(), frameOff, v.LongString())) - } - case 1: - r := pa.Registers[0] - i := f.ABISelf.FloatIndexFor(r) - // TODO seems like this has implications for debugging. How does this affect the location? - if i >= 0 { // float PR - v.Op = OpArgFloatReg - } else { - v.Op = OpArgIntReg - i = int64(r) - } - v.AuxInt = i - - default: - panic(badVal("Saw unexpanded OpArg", v)) - } - + x.rewriteArgToMemOrRegs(v) case OpStaticLECall: v.Op = OpStaticCall // TODO need to insert all the register types. @@ -1263,3 +1251,107 @@ func expandCalls(f *Func) { } } } + +// rewriteArgToMemOrRegs converts OpArg v in-place into the register version of v, +// if that is appropriate. +func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value { + pa := x.prAssignForArg(v) + switch len(pa.Registers) { + case 0: + frameOff := v.Aux.(*ir.Name).FrameOffset() + if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) { + panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s", + pa.Offset(), frameOff, v.LongString())) + } + case 1: + r := pa.Registers[0] + i := x.f.ABISelf.FloatIndexFor(r) + // TODO seems like this has implications for debugging. How does this affect the location? + if i >= 0 { // float PR + v.Op = OpArgFloatReg + } else { + v.Op = OpArgIntReg + i = int64(r) + } + v.Aux = &AuxNameOffset{v.Aux.(*ir.Name), 0} + v.AuxInt = i + + default: + panic(badVal("Saw unexpanded OpArg", v)) + } + return v +} + +// newArgToMemOrRegs either rewrites toReplace into an OpArg referencing memory or into an OpArgXXXReg to a register, +// or rewrites it into a copy of the appropriate OpArgXXX. The actual OpArgXXX is determined by combining baseArg (an OpArg) +// with offset, regOffset, and t to determine which portion of it reference (either all or a part, in memory or in registers). +func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value { + key := selKey{baseArg, offset, t.Width, t} + w := x.commonArgs[key] + if w != nil { + if toReplace != nil { + toReplace.copyOf(w) + } + return w + } + + pa := x.prAssignForArg(baseArg) + switch len(pa.Registers) { + case 0: + frameOff := baseArg.Aux.(*ir.Name).FrameOffset() + if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) { + panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s", + pa.Offset(), frameOff, baseArg.LongString())) + } + + aux := baseArg.Aux + auxInt := baseArg.AuxInt + offset + if toReplace != nil && toReplace.Block == baseArg.Block { + toReplace.reset(OpArg) + toReplace.Aux = aux + toReplace.AuxInt = auxInt + toReplace.Type = t + x.commonArgs[key] = toReplace + return toReplace + } else { + w := baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux) + x.commonArgs[key] = w + if x.debug { + fmt.Printf("\tnew %s\n", w.LongString()) + } + if toReplace != nil { + toReplace.copyOf(w) + } + return w + } + + default: + r := pa.Registers[regOffset] + auxInt := x.f.ABISelf.FloatIndexFor(r) + op := OpArgFloatReg + // TODO seems like this has implications for debugging. How does this affect the location? + if auxInt < 0 { // int (not float) parameter register + op = OpArgIntReg + auxInt = int64(r) + } + aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset} + if toReplace != nil && toReplace.Block == baseArg.Block { + toReplace.reset(op) + toReplace.Aux = aux + toReplace.AuxInt = auxInt + toReplace.Type = t + x.commonArgs[key] = toReplace + return toReplace + } else { + w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) + if x.debug { + fmt.Printf("\tnew %s\n", w.LongString()) + } + x.commonArgs[key] = w + if toReplace != nil { + toReplace.copyOf(w) + } + return w + } + } +} diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 506c745f7c..f704848425 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -77,6 +77,16 @@ type Param struct { Name *ir.Name // For OwnAux, need to prepend stores with Vardefs } +type AuxNameOffset struct { + Name *ir.Name + Offset int64 +} + +func (a *AuxNameOffset) CanBeAnSSAAux() {} +func (a *AuxNameOffset) String() string { + return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset) +} + type AuxCall struct { // TODO(register args) this information is largely redundant with ../abi information, needs cleanup once new ABI is in place. Fn *obj.LSym diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 74dd70c3d9..c11138bf4e 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1517,6 +1517,9 @@ func (s *regAllocState) regalloc(f *Func) { } s.f.setHome(v, outLocs) // Note that subsequent SelectX instructions will do the assignReg calls. + } else if v.Type.IsResults() { + // TODO register arguments need to make this work + panic("Oops, implement this.") } else { if r := outRegs[0]; r != noRegister { s.assignReg(r, v, v) diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 68a6f08a2a..041e7855f6 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -151,13 +151,24 @@ func (s *stackAllocState) stackalloc() { // Allocate args to their assigned locations. for _, v := range f.Entry.Values { - if v.Op != OpArg { + if v.Op != OpArg { // && v.Op != OpArgFReg && v.Op != OpArgIReg { continue } if v.Aux == nil { f.Fatalf("%s has nil Aux\n", v.LongString()) } - loc := LocalSlot{N: v.Aux.(*ir.Name), Type: v.Type, Off: v.AuxInt} + var loc LocalSlot + var name *ir.Name + var offset int64 + if v.Op == OpArg { + name = v.Aux.(*ir.Name) + offset = v.AuxInt + } else { + nameOff := v.Aux.(*AuxNameOffset) + name = nameOff.Name + offset = nameOff.Offset + } + loc = LocalSlot{N: name, Type: v.Type, Off: offset} if f.pass.debug > stackDebug { fmt.Printf("stackalloc %s to %s\n", v, loc) } diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index bd08334a5f..214bf628bd 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -18,7 +18,7 @@ func tighten(f *Func) { continue } switch v.Op { - case OpPhi, OpArg, OpSelect0, OpSelect1, OpSelectN: + case OpPhi, OpArg, OpArgIntReg, OpArgFloatReg, OpSelect0, OpSelect1, OpSelectN: // Phis need to stay in their block. // Arg must stay in the entry block. // Tuple selectors must stay with the tuple generator. diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 9088ce333b..f4da71fef4 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -539,16 +539,32 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { // Populate SSAable arguments. for _, n := range fn.Dcl { - if n.Class == ir.PPARAM && s.canSSA(n) { - var v *ssa.Value - if n.Sym().Name == ".fp" { - // Race-detector's get-caller-pc incantation is NOT a real Arg. - v = s.newValue0(ssa.OpGetCallerPC, n.Type()) - } else { - v = s.newValue0A(ssa.OpArg, n.Type(), n) + if n.Class == ir.PPARAM { + if s.canSSA(n) { + var v *ssa.Value + if n.Sym().Name == ".fp" { + // Race-detector's get-caller-pc incantation is NOT a real Arg. + v = s.newValue0(ssa.OpGetCallerPC, n.Type()) + } else { + v = s.newValue0A(ssa.OpArg, n.Type(), n) + } + s.vars[n] = v + s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself. + } else if !s.canSSAName(n) { // I.e., the address was taken. The type may or may not be okay. + // If the value will arrive in registers, + // AND if it can be SSA'd (if it cannot, panic for now), + // THEN + // (1) receive it as an OpArg (but do not store its name in the var table) + // (2) store it to its spill location, which is its address as well. + paramAssignment := ssa.ParamAssignmentForArgName(s.f, n) + if len(paramAssignment.Registers) > 0 { + if !TypeOK(n.Type()) { // TODO register args -- if v is not an SSA-able type, must decompose, here. + panic(fmt.Errorf("Arg in registers is too big to be SSA'd, need to implement decomposition, type=%v, n=%v", n.Type(), n)) + } + v := s.newValue0A(ssa.OpArg, n.Type(), n) + s.store(n.Type(), s.decladdrs[n], v) + } } - s.vars[n] = v - s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself. } } @@ -6545,6 +6561,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) { // memory arg needs no code case ssa.OpArg: // input args need no code + case ssa.OpArgIntReg, ssa.OpArgFloatReg: + CheckArgReg(v) case ssa.OpSP, ssa.OpSB: // nothing to do case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN: -- GitLab From 3e524ee65addd8a30bbfb4fd69508d429fda6d4f Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 1 Mar 2021 11:02:48 -0500 Subject: [PATCH 0164/1298] cmd/compile: make modified Aux type for OpArgXXXX pass ssa/check For #40724. Change-Id: I7d1e76139d187cd15a6e0df9d19542b7200589f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/297911 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/check.go | 6 +++ .../compile/internal/ssa/gen/genericOps.go | 4 +- src/cmd/compile/internal/ssa/op.go | 41 ++++++++++--------- src/cmd/compile/internal/ssa/opGen.go | 4 +- src/cmd/compile/internal/ssa/value.go | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 9e4aa6cd79..969fd96dbf 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -182,6 +182,12 @@ func checkFunc(f *Func) { f.Fatalf("value %v has Aux type %T, want *AuxCall", v, v.Aux) } canHaveAux = true + case auxNameOffsetInt8: + if _, ok := v.Aux.(*AuxNameOffset); !ok { + f.Fatalf("value %v has Aux type %T, want *AuxNameOffset", v, v.Aux) + } + canHaveAux = true + canHaveAuxInt = true case auxSym, auxTyp: canHaveAux = true case auxSymOff, auxSymValAndOff, auxTypSize: diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index b730c436cf..ee85156a42 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -336,8 +336,8 @@ var genericOps = []opData{ // Like Arg, these are generic ops that survive lowering. AuxInt is a register index, and the actual output register for each index is defined by the architecture. // AuxInt = integer argument index (not a register number). ABI-specified spill loc obtained from function - {name: "ArgIntReg", aux: "Int8", zeroWidth: true}, // argument to the function in an int reg. - {name: "ArgFloatReg", aux: "Int8", zeroWidth: true}, // argument to the function in a float reg. + {name: "ArgIntReg", aux: "NameOffsetInt8", zeroWidth: true}, // argument to the function in an int reg. + {name: "ArgFloatReg", aux: "NameOffsetInt8", zeroWidth: true}, // argument to the function in a float reg. // The address of a variable. arg0 is the base pointer. // If the variable is a global, the base pointer will be SB and diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index f704848425..0bc7b0ca0d 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -240,26 +240,27 @@ func OwnAuxCall(fn *obj.LSym, args []Param, results []Param, paramResultInfo *ab } const ( - auxNone auxType = iota - auxBool // auxInt is 0/1 for false/true - auxInt8 // auxInt is an 8-bit integer - auxInt16 // auxInt is a 16-bit integer - auxInt32 // auxInt is a 32-bit integer - auxInt64 // auxInt is a 64-bit integer - auxInt128 // auxInt represents a 128-bit integer. Always 0. - auxUInt8 // auxInt is an 8-bit unsigned integer - auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) - auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) - auxFlagConstant // auxInt is a flagConstant - auxString // aux is a string - auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none) - auxSymOff // aux is a symbol, auxInt is an offset - auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff - auxTyp // aux is a type - auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt - auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) - auxCall // aux is a *ssa.AuxCall - auxCallOff // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size + auxNone auxType = iota + auxBool // auxInt is 0/1 for false/true + auxInt8 // auxInt is an 8-bit integer + auxInt16 // auxInt is a 16-bit integer + auxInt32 // auxInt is a 32-bit integer + auxInt64 // auxInt is a 64-bit integer + auxInt128 // auxInt represents a 128-bit integer. Always 0. + auxUInt8 // auxInt is an 8-bit unsigned integer + auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) + auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) + auxFlagConstant // auxInt is a flagConstant + auxNameOffsetInt8 // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array + auxString // aux is a string + auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none) + auxSymOff // aux is a symbol, auxInt is an offset + auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff + auxTyp // aux is a type + auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt + auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) + auxCall // aux is a *ssa.AuxCall + auxCallOff // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size // architecture specific aux types auxARM64BitField // aux is an arm64 bitfield lsb and width packed into auxInt diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index a26eec680f..a9565ffe4b 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -35445,14 +35445,14 @@ var opcodeTable = [...]opInfo{ }, { name: "ArgIntReg", - auxType: auxInt8, + auxType: auxNameOffsetInt8, argLen: 0, zeroWidth: true, generic: true, }, { name: "ArgFloatReg", - auxType: auxInt8, + auxType: auxNameOffsetInt8, argLen: 0, zeroWidth: true, generic: true, diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 55e4b684c1..127e4ce641 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -78,7 +78,7 @@ func (v *Value) String() string { } func (v *Value) AuxInt8() int8 { - if opcodeTable[v.Op].auxType != auxInt8 { + if opcodeTable[v.Op].auxType != auxInt8 && opcodeTable[v.Op].auxType != auxNameOffsetInt8 { v.Fatalf("op %s doesn't have an int8 aux field", v.Op) } return int8(v.AuxInt) -- GitLab From d6f6ef6358f15d6e49d949749869f199d99d5047 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 2 Mar 2021 23:39:12 -0500 Subject: [PATCH 0165/1298] cmd/compile: remove races introduced in abiutils field update This fix uses mutex around the problematic store and subsequent access; if this causes performance problems later a better fix is to do all the ABI binding in gc/walk where it is single-threaded. Change-Id: I488f28ab75beb8351c856fd50b0095cab463642e Reviewed-on: https://go-review.googlesource.com/c/go/+/298109 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/cmd/compile/internal/abi/abiutils.go | 21 ++++++++++++++++++++- src/cmd/compile/internal/ssagen/ssa.go | 12 ++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 903cc5205d..3eab4b8d8b 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -315,12 +315,31 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo { return result } +// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields) +var parameterUpdateMu sync.Mutex + +// FieldOffsetOf returns a concurency-safe version of f.Offset +func FieldOffsetOf(f *types.Field) int64 { + parameterUpdateMu.Lock() + defer parameterUpdateMu.Unlock() + return f.Offset +} + func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) { // Everything except return values in registers has either a frame home (if not in a register) or a frame spill location. if !isReturn || len(a.Registers) == 0 { // The type frame offset DOES NOT show effects of minimum frame size. // Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set - f.Offset = a.FrameOffset(result)-config.LocalsOffset() + parameterUpdateMu.Lock() + defer parameterUpdateMu.Unlock() + off := a.FrameOffset(result) - config.LocalsOffset() + fOffset := f.Offset + if fOffset == types.BOGUS_FUNARG_OFFSET { + // Set the Offset the first time. After that, we may recompute it, but it should never change. + f.Offset = off + } else if fOffset != off { + panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off)) + } } } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f4da71fef4..05dd0c62a9 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1240,7 +1240,7 @@ func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrument if f.Sym.IsBlank() { continue } - offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr) + offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr) s.instrumentFields(f.Type, offptr, kind) } } @@ -4759,7 +4759,7 @@ func (s *state) openDeferExit() { } for j, argAddrVal := range r.argVals { f := getParam(r.n, j) - ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + f.Offset)}) + ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + abi.FieldOffsetOf(f))}) var a *ssa.Value if !TypeOK(f.Type) { a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem()) @@ -4867,12 +4867,12 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val types.CalcSize(fn.Type()) stksize := fn.Type().ArgWidth() // includes receiver, args, and results - abi := s.f.ABI1 + callABI := s.f.ABI1 if !inRegisters { - abi = s.f.ABI0 + callABI = s.f.ABI0 } - params := abi.ABIAnalyze(n.X.Type()) + params := callABI.ABIAnalyze(n.X.Type()) res := n.X.Type().Results() if k == callNormal { @@ -4933,7 +4933,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } // Set other args. for _, f := range ft.Params().Fields().Slice() { - s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset) + s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f)) args = args[1:] } -- GitLab From 6db80d74200675e20c562684c0bcc6d12a5631eb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 2 Mar 2021 21:52:09 -0800 Subject: [PATCH 0166/1298] cmd/compile/internal/types2: use correct recv for parameterized embedded methods Methods of generic types are instantiated lazily (upon use). Thus, when we encounter a method of such a type, we need to instantiate the method signature with the receiver type arguments. We infer those type arguments from the method receiver. If the method is embedded, we must use the actual embedded receiver type, otherwise the receiver type declared with the method doesn't match up and inference will fail. (Note that there's no type inference in the source code here, it's only the implementation which uses the existing inference mechanism to easily identify the actual type arguments. If the implementation is correct, the inference will always succeed.) Updates #44688. Change-Id: Ie35b62bebaeaf42037f2ca00cf8bd34fec2ddd9c Reviewed-on: https://go-review.googlesource.com/c/go/+/298129 Trust: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 33 +++++--- .../internal/types2/fixedbugs/issue44688.go2 | 83 +++++++++++++++++++ src/cmd/compile/internal/types2/selection.go | 4 +- 3 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 3f40a99b07..320e12d4d6 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -597,34 +597,43 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { if m, _ := obj.(*Func); m != nil { // check.dump("### found method %s", m) check.objDecl(m, nil) - // If m has a parameterized receiver type, infer the type parameter - // values from the actual receiver provided and then substitute the - // type parameters in the signature accordingly. + // If m has a parameterized receiver type, infer the type arguments + // from the actual receiver provided and then substitute the type + // parameters accordingly. // TODO(gri) factor this code out sig := m.typ.(*Signature) if len(sig.rparams) > 0 { - //check.dump("### recv typ = %s", x.typ) + // For inference to work, we must use the receiver type + // matching the receiver in the actual method declaration. + // If the method is embedded, the matching receiver is the + // embedded struct or interface that declared the method. + // Traverse the embedding to find that type (issue #44688). + recv := x.typ + for i := 0; i < len(index)-1; i++ { + // The embedded type is always a struct or a pointer to + // a struct except for the last one (which we don't need). + recv = asStruct(derefStructPtr(recv)).Field(index[i]).typ + } + //check.dump("### recv = %s", recv) //check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams) // The method may have a pointer receiver, but the actually provided receiver // may be a (hopefully addressable) non-pointer value, or vice versa. Here we // only care about inferring receiver type parameters; to make the inference // work, match up pointer-ness of receiver and argument. - arg := x - if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) { - copy := *arg + if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(recv) { if ptrRecv { - copy.typ = NewPointer(arg.typ) + recv = NewPointer(recv) } else { - copy.typ = arg.typ.(*Pointer).base + recv = recv.(*Pointer).base } - arg = © } - targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg}) + arg := operand{mode: variable, expr: x.expr, typ: recv} + targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{&arg}) //check.dump("### inferred targs = %s", targs) if failed >= 0 { // We may reach here if there were other errors (see issue #40056). // check.infer will report a follow-up error. - // TODO(gri) avoid the follow-up error or provide better explanation. + // TODO(gri) avoid the follow-up error as it is confusing (there's no inference in the source code) goto Error } // Don't modify m. Instead - for now - make a copy of m and use that instead. diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 new file mode 100644 index 0000000000..512bfcc922 --- /dev/null +++ b/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 @@ -0,0 +1,83 @@ +// Copyright 2021 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 P + +type A1[T any] struct{} + +func (*A1[T]) m1(T) {} + +type A2[T any] interface { + m2(T) +} + +type B1[T any] struct { + filler int + *A1[T] + A2[T] +} + +type B2[T any] interface { + A2[T] +} + +type C[T any] struct { + filler1 int + filler2 int + B1[T] +} + +type D[T any] struct { + filler1 int + filler2 int + filler3 int + C[T] +} + +func _() { + // calling embedded methods + var b1 B1[string] + + b1.A1.m1("") + b1.m1("") + + b1.A2.m2("") + b1.m2("") + + var b2 B2[string] + b2.m2("") + + // a deeper nesting + var d D[string] + d.m1("") + d.m2("") + + // calling method expressions + m1x := B1[string].m1 + m1x(b1, "") + m2x := B2[string].m2 + m2x(b2, "") + + // calling method values + m1v := b1.m1 + m1v("") + m2v := b1.m2 + m2v("") + b2v := b2.m2 + b2v("") +} + +// actual test case from issue + +type A[T any] struct{} + +func (*A[T]) f(T) {} + +type B[T any] struct{ A[T] } + +func _() { + var b B[string] + b.A.f("") + b.f("") +} diff --git a/src/cmd/compile/internal/types2/selection.go b/src/cmd/compile/internal/types2/selection.go index 67d1aa7e1d..02c0fc6902 100644 --- a/src/cmd/compile/internal/types2/selection.go +++ b/src/cmd/compile/internal/types2/selection.go @@ -51,8 +51,8 @@ func (s *Selection) Kind() SelectionKind { return s.kind } // Recv returns the type of x in x.f. func (s *Selection) Recv() Type { return s.recv } -// Work-around for bug where a (*instance) shows up in a final type. -// TODO(gri): fix this bug. +// Work-around for a compiler issue where an (*instance) escapes. +// TODO(gri): Is this still needed? func (s *Selection) TArgs() []Type { r := s.recv if p := asPointer(r); p != nil { -- GitLab From 12bb256cb30a76b540dbbc1cac38d7044facfa29 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 3 Mar 2021 13:33:24 -0500 Subject: [PATCH 0167/1298] go/types: use correct recv for parameterized embedded methods This is a direct port of CL 298129 to go/types. Fixes #44688 Change-Id: I950992ea7beea5b9c8bea0c296b5ce03b2aa9b12 Reviewed-on: https://go-review.googlesource.com/c/go/+/298349 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/call.go | 33 +++++++---- src/go/types/fixedbugs/issue44688.go2 | 83 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 src/go/types/fixedbugs/issue44688.go2 diff --git a/src/go/types/call.go b/src/go/types/call.go index f23ca02e1d..ae0a245b2b 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -592,31 +592,42 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { // methods may not have a fully set up signature yet if m, _ := obj.(*Func); m != nil { check.objDecl(m, nil) - // If m has a parameterized receiver type, infer the type parameter - // values from the actual receiver provided and then substitute the - // type parameters in the signature accordingly. + // If m has a parameterized receiver type, infer the type arguments from + // the actual receiver provided and then substitute the type parameters in + // the signature accordingly. // TODO(gri) factor this code out sig := m.typ.(*Signature) if len(sig.rparams) > 0 { + // For inference to work, we must use the receiver type + // matching the receiver in the actual method declaration. + // If the method is embedded, the matching receiver is the + // embedded struct or interface that declared the method. + // Traverse the embedding to find that type (issue #44688). + recv := x.typ + for i := 0; i < len(index)-1; i++ { + // The embedded type is either a struct or a pointer to + // a struct except for the last one (which we don't need). + recv = asStruct(derefStructPtr(recv)).Field(index[i]).typ + } + // The method may have a pointer receiver, but the actually provided receiver // may be a (hopefully addressable) non-pointer value, or vice versa. Here we // only care about inferring receiver type parameters; to make the inference // work, match up pointer-ness of receiver and argument. - arg := x - if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) { - copy := *arg + if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(recv) { if ptrRecv { - copy.typ = NewPointer(arg.typ) + recv = NewPointer(recv) } else { - copy.typ = arg.typ.(*Pointer).base + recv = recv.(*Pointer).base } - arg = © } - targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg}) + arg := operand{mode: variable, expr: x.expr, typ: recv} + targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{&arg}) if failed >= 0 { // We may reach here if there were other errors (see issue #40056). // check.infer will report a follow-up error. - // TODO(gri) avoid the follow-up error or provide better explanation. + // TODO(gri) avoid the follow-up error as it is confusing + // (there's no inference in the source code) goto Error } // Don't modify m. Instead - for now - make a copy of m and use that instead. diff --git a/src/go/types/fixedbugs/issue44688.go2 b/src/go/types/fixedbugs/issue44688.go2 new file mode 100644 index 0000000000..512bfcc922 --- /dev/null +++ b/src/go/types/fixedbugs/issue44688.go2 @@ -0,0 +1,83 @@ +// Copyright 2021 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 P + +type A1[T any] struct{} + +func (*A1[T]) m1(T) {} + +type A2[T any] interface { + m2(T) +} + +type B1[T any] struct { + filler int + *A1[T] + A2[T] +} + +type B2[T any] interface { + A2[T] +} + +type C[T any] struct { + filler1 int + filler2 int + B1[T] +} + +type D[T any] struct { + filler1 int + filler2 int + filler3 int + C[T] +} + +func _() { + // calling embedded methods + var b1 B1[string] + + b1.A1.m1("") + b1.m1("") + + b1.A2.m2("") + b1.m2("") + + var b2 B2[string] + b2.m2("") + + // a deeper nesting + var d D[string] + d.m1("") + d.m2("") + + // calling method expressions + m1x := B1[string].m1 + m1x(b1, "") + m2x := B2[string].m2 + m2x(b2, "") + + // calling method values + m1v := b1.m1 + m1v("") + m2v := b1.m2 + m2v("") + b2v := b2.m2 + b2v("") +} + +// actual test case from issue + +type A[T any] struct{} + +func (*A[T]) f(T) {} + +type B[T any] struct{ A[T] } + +func _() { + var b B[string] + b.A.f("") + b.f("") +} -- GitLab From 79beddc773ecca50c283dde6aad7c80929da0554 Mon Sep 17 00:00:00 2001 From: eric fang Date: Mon, 23 Nov 2020 10:59:33 +0000 Subject: [PATCH 0168/1298] cmd/asm: add 128-bit FLDPQ and FSTPQ instructions for arm64 This CL adds assembly support for 128-bit FLDPQ and FSTPQ instructions. This CL also deletes some wrong pre/post-indexed LDP and STP instructions, such as {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, because when the offset type is C_UAUTO4K, pre and post don't work. Change-Id: Ifd901d4440eb06eb9e86c9dd17518749fdf32848 Reviewed-on: https://go-review.googlesource.com/c/go/+/273668 Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot Reviewed-by: eric fang Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/asm/testdata/arm64.s | 48 +++ .../asm/internal/asm/testdata/arm64error.s | 3 + src/cmd/internal/obj/arm64/a.out.go | 16 +- src/cmd/internal/obj/arm64/anames.go | 2 + src/cmd/internal/obj/arm64/anames7.go | 12 + src/cmd/internal/obj/arm64/asm7.go | 335 ++++++++++++------ 6 files changed, 297 insertions(+), 119 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 91e3a0ca0a..1e6cde7a46 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -982,6 +982,54 @@ again: FSTPS (F3, F4), x(SB) FSTPS (F3, F4), x+8(SB) +// FLDPQ/FSTPQ + FLDPQ -4000(R0), (F1, F2) // 1b803ed1610b40ad + FLDPQ -1024(R0), (F1, F2) // 010860ad + FLDPQ (R0), (F1, F2) // 010840ad + FLDPQ 16(R0), (F1, F2) // 018840ad + FLDPQ -16(R0), (F1, F2) // 01887fad + FLDPQ.W 32(R0), (F1, F2) // 0108c1ad + FLDPQ.P 32(R0), (F1, F2) // 0108c1ac + FLDPQ 11(R0), (F1, F2) // 1b2c0091610b40ad + FLDPQ 1024(R0), (F1, F2) // 1b001091610b40ad + FLDPQ 4104(R0), (F1, F2) + FLDPQ -4000(RSP), (F1, F2) // fb833ed1610b40ad + FLDPQ -1024(RSP), (F1, F2) // e10b60ad + FLDPQ (RSP), (F1, F2) // e10b40ad + FLDPQ 16(RSP), (F1, F2) // e18b40ad + FLDPQ -16(RSP), (F1, F2) // e18b7fad + FLDPQ.W 32(RSP), (F1, F2) // e10bc1ad + FLDPQ.P 32(RSP), (F1, F2) // e10bc1ac + FLDPQ 11(RSP), (F1, F2) // fb2f0091610b40ad + FLDPQ 1024(RSP), (F1, F2) // fb031091610b40ad + FLDPQ 4104(RSP), (F1, F2) + FLDPQ -31(R0), (F1, F2) // 1b7c00d1610b40ad + FLDPQ -4(R0), (F1, F2) // 1b1000d1610b40ad + FLDPQ x(SB), (F1, F2) + FLDPQ x+8(SB), (F1, F2) + FSTPQ (F3, F4), -4000(R5) // bb803ed1631300ad + FSTPQ (F3, F4), -1024(R5) // a31020ad + FSTPQ (F3, F4), (R5) // a31000ad + FSTPQ (F3, F4), 16(R5) // a39000ad + FSTPQ (F3, F4), -16(R5) // a3903fad + FSTPQ.W (F3, F4), 32(R5) // a31081ad + FSTPQ.P (F3, F4), 32(R5) // a31081ac + FSTPQ (F3, F4), 11(R5) // bb2c0091631300ad + FSTPQ (F3, F4), 1024(R5) // bb001091631300ad + FSTPQ (F3, F4), 4104(R5) + FSTPQ (F3, F4), -4000(RSP) // fb833ed1631300ad + FSTPQ (F3, F4), -1024(RSP) // e31320ad + FSTPQ (F3, F4), (RSP) // e31300ad + FSTPQ (F3, F4), 16(RSP) // e39300ad + FSTPQ (F3, F4), -16(RSP) // e3933fad + FSTPQ.W (F3, F4), 32(RSP) // e31381ad + FSTPQ.P (F3, F4), 32(RSP) // e31381ac + FSTPQ (F3, F4), 11(RSP) // fb2f0091631300ad + FSTPQ (F3, F4), 1024(RSP) // fb031091631300ad + FSTPQ (F3, F4), 4104(RSP) + FSTPQ (F3, F4), x(SB) + FSTPQ (F3, F4), x+8(SB) + // System Register MSR $1, SPSel // bf4100d5 MSR $9, DAIFSet // df4903d5 diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index e579f20836..9b4f42a8ff 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -109,6 +109,9 @@ TEXT errors(SB),$0 VREV16 V1.D1, V2.D1 // ERROR "invalid arrangement" VREV16 V1.B8, V2.B16 // ERROR "invalid arrangement" VREV16 V1.H4, V2.H4 // ERROR "invalid arrangement" + FLDPQ (R0), (R1, R2) // ERROR "invalid register pair" + FLDPQ (R1), (F2, F2) // ERROR "constrained unpredictable behavior" + FSTPQ (R1, R2), (R0) // ERROR "invalid register pair" FLDPD (R0), (R1, R2) // ERROR "invalid register pair" FLDPD (R1), (F2, F2) // ERROR "constrained unpredictable behavior" FLDPS (R2), (F3, F3) // ERROR "constrained unpredictable behavior" diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index 7ab9c1475f..ed07f18691 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -420,16 +420,21 @@ const ( C_LBRA C_ZAUTO // 0(RSP) + C_NSAUTO_16 // -256 <= x < 0, 0 mod 16 C_NSAUTO_8 // -256 <= x < 0, 0 mod 8 C_NSAUTO_4 // -256 <= x < 0, 0 mod 4 C_NSAUTO // -256 <= x < 0 + C_NPAUTO_16 // -512 <= x < 0, 0 mod 16 C_NPAUTO // -512 <= x < 0, 0 mod 8 + C_NQAUTO_16 // -1024 <= x < 0, 0 mod 16 C_NAUTO4K // -4095 <= x < 0 + C_PSAUTO_16 // 0 to 255, 0 mod 16 C_PSAUTO_8 // 0 to 255, 0 mod 8 C_PSAUTO_4 // 0 to 255, 0 mod 4 C_PSAUTO // 0 to 255 C_PPAUTO_16 // 0 to 504, 0 mod 16 C_PPAUTO // 0 to 504, 0 mod 8 + C_PQAUTO_16 // 0 to 1008, 0 mod 16 C_UAUTO4K_16 // 0 to 4095, 0 mod 16 C_UAUTO4K_8 // 0 to 4095, 0 mod 8 C_UAUTO4K_4 // 0 to 4095, 0 mod 4 @@ -454,17 +459,22 @@ const ( C_SEXT16 // 0 to 65520 C_LEXT - C_ZOREG // 0(R) - C_NSOREG_8 // must mirror C_NSAUTO_8, etc + C_ZOREG // 0(R) + C_NSOREG_16 // must mirror C_NSAUTO_16, etc + C_NSOREG_8 C_NSOREG_4 C_NSOREG + C_NPOREG_16 C_NPOREG + C_NQOREG_16 C_NOREG4K + C_PSOREG_16 C_PSOREG_8 C_PSOREG_4 C_PSOREG C_PPOREG_16 C_PPOREG + C_PQOREG_16 C_UOREG4K_16 C_UOREG4K_8 C_UOREG4K_4 @@ -898,6 +908,7 @@ const ( AFDIVD AFDIVS AFLDPD + AFLDPQ AFLDPS AFMOVQ AFMOVD @@ -912,6 +923,7 @@ const ( AFSQRTD AFSQRTS AFSTPD + AFSTPQ AFSTPS AFSUBD AFSUBS diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index a98f8c7ed5..0fb28536c4 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -392,6 +392,7 @@ var Anames = []string{ "FDIVD", "FDIVS", "FLDPD", + "FLDPQ", "FLDPS", "FMOVQ", "FMOVD", @@ -406,6 +407,7 @@ var Anames = []string{ "FSQRTD", "FSQRTS", "FSTPD", + "FSTPQ", "FSTPS", "FSUBD", "FSUBS", diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go index f7e99517ce..2ecd8164b6 100644 --- a/src/cmd/internal/obj/arm64/anames7.go +++ b/src/cmd/internal/obj/arm64/anames7.go @@ -42,15 +42,21 @@ var cnames7 = []string{ "SBRA", "LBRA", "ZAUTO", + "NSAUTO_16", "NSAUTO_8", "NSAUTO_4", "NSAUTO", + "NPAUTO_16", "NPAUTO", + "NQAUTO_16", "NAUTO4K", + "PSAUTO_16", "PSAUTO_8", "PSAUTO_4", "PSAUTO", + "PPAUTO_16", "PPAUTO", + "PQAUTO_16", "UAUTO4K_16", "UAUTO4K_8", "UAUTO4K_4", @@ -74,15 +80,21 @@ var cnames7 = []string{ "SEXT16", "LEXT", "ZOREG", + "NSOREG_16", "NSOREG_8", "NSOREG_4", "NSOREG", + "NPOREG_16", "NPOREG", + "NQOREG_16", "NOREG4K", + "PSOREG_16", "PSOREG_8", "PSOREG_4", "PSOREG", + "PPOREG_16", "PPOREG", + "PQOREG_16", "UOREG4K_16", "UOREG4K_8", "UOREG4K_4", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 70072cfba4..5937ebd732 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -689,6 +689,46 @@ var optab = []Optab{ /* pre/post-indexed/signed-offset load/store register pair (unscaled, signed 10-bit quad-aligned and long offset) */ + {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, + {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, + {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, + {AFLDPQ, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {AFLDPQ, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, + {AFLDPQ, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0}, + {AFLDPQ, C_NQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {AFLDPQ, C_NQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {AFLDPQ, C_NQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {AFLDPQ, C_PQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, + {AFLDPQ, C_PQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {AFLDPQ, C_PQOREG_16, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {AFLDPQ, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {AFLDPQ, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, + {AFLDPQ, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0}, + {AFLDPQ, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0}, + + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, C_XPRE}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, C_XPOST}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, C_XPRE}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, C_XPOST}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQOREG_16, 67, 4, 0, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQOREG_16, 67, 4, 0, 0, C_XPRE}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQOREG_16, 67, 4, 0, 0, C_XPOST}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQOREG_16, 67, 4, 0, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQOREG_16, 67, 4, 0, 0, C_XPRE}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQOREG_16, 67, 4, 0, 0, C_XPOST}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0}, + {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0}, + {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0}, {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, @@ -696,14 +736,8 @@ var optab = []Optab{ {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, - {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, - {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, - {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, - {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0}, - {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE}, - {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST}, {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, @@ -711,14 +745,8 @@ var optab = []Optab{ {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, - {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, - {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, - {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, - {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0}, - {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE}, - {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST}, {ALDP, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, 0}, @@ -728,14 +756,8 @@ var optab = []Optab{ {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPRE}, {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, 0}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPRE}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPOST}, @@ -743,14 +765,8 @@ var optab = []Optab{ {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPRE}, {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE}, - {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST}, {ASTP, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0}, // differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4 @@ -761,14 +777,8 @@ var optab = []Optab{ {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE}, {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST}, {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, - {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, - {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0}, - {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE}, - {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST}, {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0}, - {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE}, - {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST}, {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0}, {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, @@ -776,14 +786,8 @@ var optab = []Optab{ {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, - {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, - {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0}, - {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE}, - {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST}, {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0}, - {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE}, - {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST}, {ALDPW, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0}, @@ -793,14 +797,8 @@ var optab = []Optab{ {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, 0}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPRE}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPOST}, @@ -808,14 +806,8 @@ var optab = []Optab{ {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPRE}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE}, - {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST}, {ASTPW, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0}, {ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG @@ -1276,12 +1268,27 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) { case C_ADDCON: fallthrough - case C_ZAUTO, - C_PSAUTO, + case C_ADDCON2, + C_LCON, + C_VCON, + C_LACON, + + C_ZAUTO, + C_NSAUTO_16, + C_NSAUTO_8, + C_NSAUTO_4, + C_NSAUTO, + C_NPAUTO_16, + C_NPAUTO, + C_NQAUTO_16, + C_NAUTO4K, + C_PSAUTO_16, C_PSAUTO_8, C_PSAUTO_4, + C_PSAUTO, C_PPAUTO_16, C_PPAUTO, + C_PQAUTO_16, C_UAUTO4K_16, C_UAUTO4K_8, C_UAUTO4K_4, @@ -1297,17 +1304,24 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) { C_UAUTO32K_16, C_UAUTO32K, C_UAUTO64K, - C_NSAUTO_8, - C_NSAUTO_4, - C_NSAUTO, - C_NPAUTO, - C_NAUTO4K, C_LAUTO, - C_PSOREG, + + C_ZOREG, + C_NSOREG_16, + C_NSOREG_8, + C_NSOREG_4, + C_NSOREG, + C_NPOREG_16, + C_NPOREG, + C_NQOREG_16, + C_NOREG4K, + C_PSOREG_16, C_PSOREG_8, C_PSOREG_4, + C_PSOREG, C_PPOREG_16, C_PPOREG, + C_PQOREG_16, C_UOREG4K_16, C_UOREG4K_8, C_UOREG4K_4, @@ -1323,16 +1337,7 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) { C_UOREG32K_16, C_UOREG32K, C_UOREG64K, - C_NSOREG_8, - C_NSOREG_4, - C_NSOREG, - C_NPOREG, - C_NOREG4K, - C_LOREG, - C_LACON, - C_ADDCON2, - C_LCON, - C_VCON: + C_LOREG: if a.Name == obj.NAME_EXTERN { fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p) } @@ -1590,6 +1595,9 @@ func autoclass(l int64) int { } if l < 0 { + if l >= -256 && (l&15) == 0 { + return C_NSAUTO_16 + } if l >= -256 && (l&7) == 0 { return C_NSAUTO_8 } @@ -1599,9 +1607,15 @@ func autoclass(l int64) int { if l >= -256 { return C_NSAUTO } + if l >= -512 && (l&15) == 0 { + return C_NPAUTO_16 + } if l >= -512 && (l&7) == 0 { return C_NPAUTO } + if l >= -1024 && (l&15) == 0 { + return C_NQAUTO_16 + } if l >= -4095 { return C_NAUTO4K } @@ -1609,6 +1623,9 @@ func autoclass(l int64) int { } if l <= 255 { + if (l & 15) == 0 { + return C_PSAUTO_16 + } if (l & 7) == 0 { return C_PSAUTO_8 } @@ -1625,6 +1642,11 @@ func autoclass(l int64) int { return C_PPAUTO } } + if l <= 1008 { + if l&15 == 0 { + return C_PQAUTO_16 + } + } if l <= 4095 { if l&15 == 0 { return C_UAUTO4K_16 @@ -2193,64 +2215,99 @@ func cmp(a int, b int) bool { return true } + case C_NSAUTO_8: + if b == C_NSAUTO_16 { + return true + } + case C_NSAUTO_4: - if b == C_NSAUTO_8 { + if b == C_NSAUTO_16 || b == C_NSAUTO_8 { return true } case C_NSAUTO: switch b { - case C_NSAUTO_4, C_NSAUTO_8: + case C_NSAUTO_4, C_NSAUTO_8, C_NSAUTO_16: + return true + } + + case C_NPAUTO_16: + switch b { + case C_NSAUTO_16: return true } case C_NPAUTO: switch b { - case C_NSAUTO_8: + case C_NSAUTO_16, C_NSAUTO_8, C_NPAUTO_16: + return true + } + + case C_NQAUTO_16: + switch b { + case C_NSAUTO_16, C_NPAUTO_16: return true } case C_NAUTO4K: switch b { - case C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO: + case C_NSAUTO_16, C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO_16, + C_NPAUTO, C_NQAUTO_16: return true } - case C_PSAUTO_8: + case C_PSAUTO_16: if b == C_ZAUTO { return true } + case C_PSAUTO_8: + if b == C_ZAUTO || b == C_PSAUTO_16 { + return true + } + case C_PSAUTO_4: switch b { - case C_ZAUTO, C_PSAUTO_8: + case C_ZAUTO, C_PSAUTO_16, C_PSAUTO_8: return true } case C_PSAUTO: switch b { - case C_ZAUTO, C_PSAUTO_8, C_PSAUTO_4: + case C_ZAUTO, C_PSAUTO_16, C_PSAUTO_8, C_PSAUTO_4: + return true + } + + case C_PPAUTO_16: + switch b { + case C_ZAUTO, C_PSAUTO_16: return true } case C_PPAUTO: switch b { - case C_ZAUTO, C_PSAUTO_8, C_PPAUTO_16: + case C_ZAUTO, C_PSAUTO_16, C_PSAUTO_8, C_PPAUTO_16: + return true + } + + case C_PQAUTO_16: + switch b { + case C_ZAUTO, C_PSAUTO_16, C_PPAUTO_16: return true } case C_UAUTO4K: switch b { - case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO, C_PPAUTO_16, + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO, C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16: return true } case C_UAUTO8K: switch b { - case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO, C_PPAUTO_16, + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO, C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16: return true @@ -2258,8 +2315,8 @@ func cmp(a int, b int) bool { case C_UAUTO16K: switch b { - case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO, C_PPAUTO_16, + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO, C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16, C_UAUTO16K_8, C_UAUTO16K_16: @@ -2268,8 +2325,8 @@ func cmp(a int, b int) bool { case C_UAUTO32K: switch b { - case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO, C_PPAUTO_16, + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO, C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K_8, C_UAUTO4K_16, C_UAUTO8K_8, C_UAUTO8K_16, C_UAUTO16K_8, C_UAUTO16K_16, @@ -2279,17 +2336,17 @@ func cmp(a int, b int) bool { case C_UAUTO64K: switch b { - case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO_16, C_UAUTO4K_16, C_UAUTO8K_16, C_UAUTO16K_16, + case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K_16, C_UAUTO8K_16, C_UAUTO16K_16, C_UAUTO32K_16: return true } case C_LAUTO: switch b { - case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO, C_NAUTO4K, - C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, - C_PPAUTO, C_PPAUTO_16, + case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NSAUTO_16, C_NPAUTO_16, C_NPAUTO, C_NQAUTO_16, C_NAUTO4K, + C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PSAUTO_16, + C_PPAUTO, C_PPAUTO_16, C_PQAUTO_16, C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16, C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16, C_UAUTO16K, C_UAUTO16K_8, C_UAUTO16K_16, @@ -2298,64 +2355,98 @@ func cmp(a int, b int) bool { return true } + case C_NSOREG_8: + if b == C_NSOREG_16 { + return true + } + case C_NSOREG_4: - if b == C_NSOREG_8 { + if b == C_NSOREG_8 || b == C_NSOREG_16 { return true } case C_NSOREG: switch b { - case C_NSOREG_4, C_NSOREG_8: + case C_NSOREG_4, C_NSOREG_8, C_NSOREG_16: + return true + } + + case C_NPOREG_16: + switch b { + case C_NSOREG_16: return true } case C_NPOREG: switch b { - case C_NSOREG_8: + case C_NSOREG_16, C_NSOREG_8, C_NPOREG_16: + return true + } + + case C_NQOREG_16: + switch b { + case C_NSOREG_16, C_NPOREG_16: return true } case C_NOREG4K: switch b { - case C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG: + case C_NSOREG_16, C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG_16, C_NPOREG, C_NQOREG_16: return true } - case C_PSOREG_8: + case C_PSOREG_16: if b == C_ZOREG { return true } + case C_PSOREG_8: + if b == C_ZOREG || b == C_PSOREG_16 { + return true + } + case C_PSOREG_4: switch b { - case C_ZOREG, C_PSOREG_8: + case C_ZOREG, C_PSOREG_16, C_PSOREG_8: return true } case C_PSOREG: switch b { - case C_ZOREG, C_PSOREG_8, C_PSOREG_4: + case C_ZOREG, C_PSOREG_16, C_PSOREG_8, C_PSOREG_4: + return true + } + + case C_PPOREG_16: + switch b { + case C_ZOREG, C_PSOREG_16: return true } case C_PPOREG: switch b { - case C_ZOREG, C_PSOREG_8, C_PPOREG_16: + case C_ZOREG, C_PSOREG_16, C_PSOREG_8, C_PPOREG_16: + return true + } + + case C_PQOREG_16: + switch b { + case C_ZOREG, C_PSOREG_16, C_PPOREG_16: return true } case C_UOREG4K: switch b { - case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG, C_PPOREG_16, + case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG, C_PPOREG_16, C_PQOREG_16, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16: return true } case C_UOREG8K: switch b { - case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG, C_PPOREG_16, + case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG, C_PPOREG_16, C_PQOREG_16, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16, C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16: return true @@ -2363,8 +2454,8 @@ func cmp(a int, b int) bool { case C_UOREG16K: switch b { - case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG, C_PPOREG_16, + case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG, C_PPOREG_16, C_PQOREG_16, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16, C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16, C_UOREG16K_8, C_UOREG16K_16: @@ -2373,8 +2464,8 @@ func cmp(a int, b int) bool { case C_UOREG32K: switch b { - case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG, C_PPOREG_16, + case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG, C_PPOREG_16, C_PQOREG_16, C_UOREG4K_8, C_UOREG4K_16, C_UOREG8K_8, C_UOREG8K_16, C_UOREG16K_8, C_UOREG16K_16, @@ -2384,17 +2475,17 @@ func cmp(a int, b int) bool { case C_UOREG64K: switch b { - case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG_16, C_UOREG4K_16, C_UOREG8K_16, C_UOREG16K_16, + case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG_16, C_PQOREG_16, C_UOREG4K_16, C_UOREG8K_16, C_UOREG16K_16, C_UOREG32K_16: return true } case C_LOREG: switch b { - case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG, C_NOREG4K, - C_PSOREG, C_PSOREG_4, C_PSOREG_8, - C_PPOREG, C_PPOREG_16, + case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NSOREG_16, C_NPOREG, C_NPOREG_16, C_NQOREG_16, C_NOREG4K, + C_PSOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG_16, + C_PPOREG, C_PPOREG_16, C_PQOREG_16, C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16, C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16, C_UOREG16K, C_UOREG16K_8, C_UOREG16K_16, @@ -2722,6 +2813,10 @@ func buildop(ctxt *obj.Link) { obj.ATEXT: break + case AFLDPQ: + break + case AFSTPQ: + break case ALDP: oprangeset(AFLDPD, t) @@ -7192,7 +7287,7 @@ func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) u return o } -/* genrate instruction encoding for LDP/LDPW/LDPSW/STP/STPW */ +/* genrate instruction encoding for ldp and stp series */ func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uint32) uint32 { wback := false if o.scond == C_XPOST || o.scond == C_XPRE { @@ -7205,30 +7300,36 @@ func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uin if wback == true { c.checkUnpredictable(p, false, true, p.To.Reg, p.From.Reg, int16(p.From.Offset)) } - case AFLDPD, AFLDPS: + case AFLDPD, AFLDPQ, AFLDPS: c.checkUnpredictable(p, true, false, p.From.Reg, p.To.Reg, int16(p.To.Offset)) } var ret uint32 // check offset switch p.As { - case AFLDPD, AFSTPD: - if vo < -512 || vo > 504 || vo%8 != 0 { + case AFLDPQ, AFSTPQ: + if vo < -1024 || vo > 1008 || vo%16 != 0 { c.ctxt.Diag("invalid offset %v\n", p) } - vo /= 8 - ret = 1<<30 | 1<<26 - case ALDP, ASTP: + vo /= 16 + ret = 2<<30 | 1<<26 + case AFLDPD, AFSTPD: if vo < -512 || vo > 504 || vo%8 != 0 { c.ctxt.Diag("invalid offset %v\n", p) } vo /= 8 - ret = 2 << 30 + ret = 1<<30 | 1<<26 case AFLDPS, AFSTPS: if vo < -256 || vo > 252 || vo%4 != 0 { c.ctxt.Diag("invalid offset %v\n", p) } vo /= 4 ret = 1 << 26 + case ALDP, ASTP: + if vo < -512 || vo > 504 || vo%8 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 8 + ret = 2 << 30 case ALDPW, ASTPW: if vo < -256 || vo > 252 || vo%4 != 0 { c.ctxt.Diag("invalid offset %v\n", p) @@ -7246,7 +7347,7 @@ func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uin } // check register pair switch p.As { - case AFLDPD, AFLDPS, AFSTPD, AFSTPS: + case AFLDPQ, AFLDPD, AFLDPS, AFSTPQ, AFSTPD, AFSTPS: if rl < REG_F0 || REG_F31 < rl || rh < REG_F0 || REG_F31 < rh { c.ctxt.Diag("invalid register pair %v\n", p) } -- GitLab From 726d704c32acf99a9ed44d81c99adb22d4759241 Mon Sep 17 00:00:00 2001 From: eric fang Date: Thu, 19 Nov 2020 07:18:41 +0000 Subject: [PATCH 0169/1298] cmd/asm: add arm64 instructions VUMAX and VUMIN This CL adds support for arm64 fp&simd instructions VUMAX and VUMIN. Fixes #42326 Change-Id: I3757ba165dc31ce1ce70f3b06a9e5b94c14d2ab9 Reviewed-on: https://go-review.googlesource.com/c/go/+/271497 Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot Reviewed-by: fannie zhang Reviewed-by: eric fang Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/asm/testdata/arm64.s | 12 ++++++++++++ src/cmd/asm/internal/asm/testdata/arm64error.s | 4 ++++ src/cmd/internal/obj/arm64/a.out.go | 2 ++ src/cmd/internal/obj/arm64/anames.go | 2 ++ src/cmd/internal/obj/arm64/asm7.go | 12 ++++++++++++ 5 files changed, 32 insertions(+) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 1e6cde7a46..c1385a13ab 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -207,6 +207,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 VUADDW2 V9.B16, V12.H8, V14.H8 // 8e11296e VUADDW2 V13.H8, V20.S4, V30.S4 // 9e126d6e VUADDW2 V21.S4, V24.D2, V29.D2 // 1d13b56e + VUMAX V3.B8, V2.B8, V1.B8 // 4164232e + VUMAX V3.B16, V2.B16, V1.B16 // 4164236e + VUMAX V3.H4, V2.H4, V1.H4 // 4164632e + VUMAX V3.H8, V2.H8, V1.H8 // 4164636e + VUMAX V3.S2, V2.S2, V1.S2 // 4164a32e + VUMAX V3.S4, V2.S4, V1.S4 // 4164a36e + VUMIN V3.B8, V2.B8, V1.B8 // 416c232e + VUMIN V3.B16, V2.B16, V1.B16 // 416c236e + VUMIN V3.H4, V2.H4, V1.H4 // 416c632e + VUMIN V3.H8, V2.H8, V1.H8 // 416c636e + VUMIN V3.S2, V2.S2, V1.S2 // 416ca32e + VUMIN V3.S4, V2.S4, V1.S4 // 416ca36e FCCMPS LT, F1, F2, $1 // 41b4211e FMADDS F1, F3, F2, F4 // 440c011f FMADDD F4, F5, F4, F4 // 8414441f diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 9b4f42a8ff..1c8eaa1752 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -358,6 +358,10 @@ TEXT errors(SB),$0 VBIF V0.D2, V1.D2, V2.D2 // ERROR "invalid arrangement" VUADDW V9.B8, V12.H8, V14.B8 // ERROR "invalid arrangement" VUADDW2 V9.B8, V12.S4, V14.S4 // ERROR "operand mismatch" + VUMAX V1.D2, V2.D2, V3.D2 // ERROR "invalid arrangement" + VUMIN V1.D2, V2.D2, V3.D2 // ERROR "invalid arrangement" + VUMAX V1.B8, V2.B8, V3.B16 // ERROR "operand mismatch" + VUMIN V1.H4, V2.S4, V3.H4 // ERROR "operand mismatch" VSLI $64, V7.D2, V8.D2 // ERROR "shift out of range" VUSRA $0, V7.D2, V8.D2 // ERROR "shift out of range" CASPD (R3, R4), (R2), (R8, R9) // ERROR "source register pair must start from even register" diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index ed07f18691..bf75bb4a89 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -1031,6 +1031,8 @@ const ( AVEXT AVRBIT AVRAX1 + AVUMAX + AVUMIN AVUSHR AVUSHLL AVUSHLL2 diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index 0fb28536c4..9cc5871648 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -515,6 +515,8 @@ var Anames = []string{ "VEXT", "VRBIT", "VRAX1", + "VUMAX", + "VUMIN", "VUSHR", "VUSHLL", "VUSHLL2", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 5937ebd732..f7c0a48214 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -3017,6 +3017,8 @@ func buildop(ctxt *obj.Link) { oprangeset(AVBSL, t) oprangeset(AVBIT, t) oprangeset(AVCMTST, t) + oprangeset(AVUMAX, t) + oprangeset(AVUMIN, t) oprangeset(AVUZP1, t) oprangeset(AVUZP2, t) oprangeset(AVBIF, t) @@ -4529,6 +4531,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if af != ARNG_2D && af != ARNG_2S && af != ARNG_4S { c.ctxt.Diag("invalid arrangement: %v", p) } + case AVUMAX, AVUMIN: + if af == ARNG_2D { + c.ctxt.Diag("invalid arrangement: %v", p) + } } switch p.As { case AVAND, AVEOR: @@ -6205,6 +6211,12 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 { case AVCMTST: return 0xE<<24 | 1<<21 | 0x23<<10 + case AVUMAX: + return 1<<29 | 7<<25 | 1<<21 | 0x19<<10 + + case AVUMIN: + return 1<<29 | 7<<25 | 1<<21 | 0x1b<<10 + case AVUZP1: return 7<<25 | 3<<11 -- GitLab From 355c3a037edd8107bc4f1918d7a84764039ac6d1 Mon Sep 17 00:00:00 2001 From: eric fang Date: Mon, 1 Feb 2021 07:47:06 +0000 Subject: [PATCH 0170/1298] cmd/internal/obj/asm64: add support for moving BITCON to RSP Constant of BITCON type can be moved into RSP by MOVD or MOVW instructions directly, this CL enables this format of these two instructions. For 32-bit ADDWop instructions with constant, rewrite the high 32-bit to be a repetition of the low 32-bit, just as ANDWop instructions do, so that we can optimize ADDW $bitcon, Rn, Rt as: MOVW $bitcon, Rtmp ADDW Rtmp, Rn, Rt The original code is: MOVZ $bitcon_low, Rtmp MOVK $bitcon_high,Rtmp ADDW Rtmp, Rn, Rt Change-Id: I30e71972bcfd6470a8b6e6ffbacaee79d523805a Reviewed-on: https://go-review.googlesource.com/c/go/+/289649 Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot Reviewed-by: eric fang Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/asm/testdata/arm64.s | 3 +++ src/cmd/internal/obj/arm64/asm7.go | 19 ++++++------------- src/cmd/internal/obj/arm64/obj7.go | 14 +++++++------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index c1385a13ab..17ecd9b2b8 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -364,6 +364,9 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVD $1, ZR MOVD $1, R1 MOVK $1, R1 + MOVD $0x1000100010001000, RSP // MOVD $1152939097061330944, RSP // ff8304b2 + MOVW $0x10001000, RSP // MOVW $268439552, RSP // ff830432 + ADDW $0x10001000, R1 // ADDW $268439552, R1 // fb83043221001b0b // move a large constant to a Vd. VMOVS $0x80402010, V11 // VMOVS $2151686160, V11 diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index f7c0a48214..3b0fa6fb53 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -404,8 +404,8 @@ var optab = []Optab{ /* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */ {AMOVW, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, {AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, - {AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, - {AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVW, C_BITCON, C_NONE, C_NONE, C_RSP, 32, 4, 0, 0, 0}, + {AMOVD, C_BITCON, C_NONE, C_NONE, C_RSP, 32, 4, 0, 0, 0}, {AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0}, {AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0}, {AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, NOTUSETMP, 0}, @@ -2060,9 +2060,10 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab { } a1 = a0 + 1 p.From.Class = int8(a1) - // more specific classification of 32-bit integers if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE { - if p.As == AMOVW || isADDWop(p.As) { + if p.As == AMOVW || isADDWop(p.As) || isANDWop(p.As) { + // For 32-bit instruction with constant, we need to + // treat its offset value as 32 bits to classify it. ra0 := c.con32class(&p.From) // do not break C_ADDCON2 when S bit is set if (p.As == AADDSW || p.As == ASUBSW) && ra0 == C_ADDCON2 { @@ -2071,16 +2072,8 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab { a1 = ra0 + 1 p.From.Class = int8(a1) } - if isANDWop(p.As) && a0 != C_BITCON { - // For 32-bit logical instruction with constant, - // the BITCON test is special in that it looks at - // the 64-bit which has the high 32-bit as a copy - // of the low 32-bit. We have handled that and - // don't pass it to con32class. - a1 = c.con32class(&p.From) + 1 - p.From.Class = int8(a1) - } if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) { + // more specific classification of 64-bit integers a1 = c.con64class(&p.From) + 1 p.From.Class = int8(a1) } diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index 8f7648e5d5..425cb88f7e 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -314,13 +314,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { } } - // For 32-bit logical instruction with constant, - // rewrite the high 32-bit to be a repetition of - // the low 32-bit, so that the BITCON test can be - // shared for both 32-bit and 64-bit. 32-bit ops - // will zero the high 32-bit of the destination - // register anyway. - if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST { + // For 32-bit instruction with constant, rewrite + // the high 32-bit to be a repetition of the low + // 32-bit, so that the BITCON test can be shared + // for both 32-bit and 64-bit. 32-bit ops will + // zero the high 32-bit of the destination register + // anyway. + if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW) && p.From.Type == obj.TYPE_CONST { v := p.From.Offset & 0xffffffff p.From.Offset = v | v<<32 } -- GitLab From 593f5bbad7727f57ce452c4aa93604e8dabbba7d Mon Sep 17 00:00:00 2001 From: eric fang Date: Wed, 4 Nov 2020 09:26:28 +0000 Subject: [PATCH 0171/1298] cmd/compile: adjust stack slot alignment requirements on arm64 Currently any variable that is spilled onto the stack will occupy at least 8 bytes, because the stack offset is required to be aligned with 8 bytes on linux/arm64. This CL removes this constraint by aligning the stack slot with its actual size. Updates #42385 Change-Id: Icbd63dc70cd19852802e43f134355f19ba7e1e29 Reviewed-on: https://go-review.googlesource.com/c/go/+/267999 Trust: eric fang Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssagen/pgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index b675d1c876..7e15f54299 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -138,7 +138,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.ARM, sys.ARM64, sys.PPC64) { + if Arch.LinkArch.InFamily(sys.ARM, sys.PPC64) { s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) } n.SetFrameOffset(-s.stksize) -- GitLab From 27dbc4551a37a48cf7c020db0aeac6f2841883dc Mon Sep 17 00:00:00 2001 From: eric fang Date: Thu, 4 Feb 2021 03:08:20 +0000 Subject: [PATCH 0172/1298] cmd/asm: disable scaled register format for arm64 Arm64 doesn't have scaled register format, such as (R1*2), (R1)(R2*3), but currently the assembler doesn't report an error for such kind of instruction operand format. This CL disables the scaled register operand format for arm64 and reports an error if this kind of instruction format is seen. With this CL, the assembler won't print (R1)(R2) as (R1)(R2*1), so that we can make the assembly test simpler. Change-Id: I6d7569065597215be4c767032a63648d2ad16fed Reviewed-on: https://go-review.googlesource.com/c/go/+/289589 Trust: eric fang Run-TryBot: eric fang TryBot-Result: Go Bot Reviewed-by: eric fang Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/asm/parse.go | 8 ++-- src/cmd/asm/internal/asm/testdata/arm64.s | 48 ++++++++++---------- src/cmd/asm/internal/asm/testdata/arm64enc.s | 44 +++++++++--------- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index f1d37bc2c8..2c7332877f 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -999,15 +999,17 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { p.errorf("unimplemented two-register form") } a.Index = r1 - if scale == 0 && p.arch.Family == sys.ARM64 { - // scale is 1 by default for ARM64 - a.Scale = 1 + if scale != 0 && p.arch.Family == sys.ARM64 { + p.errorf("arm64 doesn't support scaled register format") } else { a.Scale = int16(scale) } } p.get(')') } else if scale != 0 { + if p.arch.Family == sys.ARM64 { + p.errorf("arm64 doesn't support scaled register format") + } // First (R) was missing, all we have is (R*scale). a.Reg = 0 a.Index = r1 diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 17ecd9b2b8..8635708320 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -395,13 +395,13 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 // LD1/ST1 VLD1 (R8), [V1.B16, V2.B16] // 01a1404c VLD1.P (R3), [V31.H8, V0.H8] // 7fa4df4c - VLD1.P (R8)(R20), [V21.B16, V22.B16] // VLD1.P (R8)(R20*1), [V21.B16,V22.B16] // 15a1d44c + VLD1.P (R8)(R20), [V21.B16, V22.B16] // 15a1d44c VLD1.P 64(R1), [V5.B16, V6.B16, V7.B16, V8.B16] // 2520df4c VLD1.P 1(R0), V4.B[15] // 041cdf4d VLD1.P 2(R0), V4.H[7] // 0458df4d VLD1.P 4(R0), V4.S[3] // 0490df4d VLD1.P 8(R0), V4.D[1] // 0484df4d - VLD1.P (R0)(R1), V4.D[1] // VLD1.P (R0)(R1*1), V4.D[1] // 0484c14d + VLD1.P (R0)(R1), V4.D[1] // 0484c14d VLD1 (R0), V4.D[1] // 0484404d VST1.P [V4.S4, V5.S4], 32(R1) // 24a89f4c VST1 [V0.S4, V1.S4], (R0) // 00a8004c @@ -409,29 +409,29 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 VLD1.P 24(R30), [V3.S2,V4.S2,V5.S2] // c36bdf0c VLD2 (R29), [V23.H8, V24.H8] // b787404c VLD2.P 16(R0), [V18.B8, V19.B8] // 1280df0c - VLD2.P (R1)(R2), [V15.S2, V16.S2] // VLD2.P (R1)(R2*1), [V15.S2,V16.S2] // 2f88c20c + VLD2.P (R1)(R2), [V15.S2, V16.S2] // 2f88c20c VLD3 (R27), [V11.S4, V12.S4, V13.S4] // 6b4b404c VLD3.P 48(RSP), [V11.S4, V12.S4, V13.S4] // eb4bdf4c - VLD3.P (R30)(R2), [V14.D2, V15.D2, V16.D2] // VLD3.P (R30)(R2*1), [V14.D2,V15.D2,V16.D2] // ce4fc24c + VLD3.P (R30)(R2), [V14.D2, V15.D2, V16.D2] // ce4fc24c VLD4 (R15), [V10.H4, V11.H4, V12.H4, V13.H4] // ea05400c VLD4.P 32(R24), [V31.B8, V0.B8, V1.B8, V2.B8] // 1f03df0c - VLD4.P (R13)(R9), [V14.S2, V15.S2, V16.S2, V17.S2] // VLD4.P (R13)(R9*1), [V14.S2,V15.S2,V16.S2,V17.S2] // ae09c90c + VLD4.P (R13)(R9), [V14.S2, V15.S2, V16.S2, V17.S2] // ae09c90c VLD1R (R1), [V9.B8] // 29c0400d VLD1R.P (R1), [V9.B8] // 29c0df0d VLD1R.P 1(R1), [V2.B8] // 22c0df0d VLD1R.P 2(R1), [V2.H4] // 22c4df0d VLD1R (R0), [V0.B16] // 00c0404d VLD1R.P (R0), [V0.B16] // 00c0df4d - VLD1R.P (R15)(R1), [V15.H4] // VLD1R.P (R15)(R1*1), [V15.H4] // efc5c10d + VLD1R.P (R15)(R1), [V15.H4] // efc5c10d VLD2R (R15), [V15.H4, V16.H4] // efc5600d VLD2R.P 16(R0), [V0.D2, V1.D2] // 00ccff4d - VLD2R.P (R0)(R5), [V31.D1, V0.D1] // VLD2R.P (R0)(R5*1), [V31.D1, V0.D1] // 1fcce50d + VLD2R.P (R0)(R5), [V31.D1, V0.D1] // 1fcce50d VLD3R (RSP), [V31.S2, V0.S2, V1.S2] // ffeb400d VLD3R.P 6(R15), [V15.H4, V16.H4, V17.H4] // efe5df0d - VLD3R.P (R15)(R6), [V15.H8, V16.H8, V17.H8] // VLD3R.P (R15)(R6*1), [V15.H8, V16.H8, V17.H8] // efe5c64d + VLD3R.P (R15)(R6), [V15.H8, V16.H8, V17.H8] // efe5c64d VLD4R (R0), [V0.B8, V1.B8, V2.B8, V3.B8] // 00e0600d VLD4R.P 16(RSP), [V31.S4, V0.S4, V1.S4, V2.S4] // ffebff4d - VLD4R.P (R15)(R9), [V15.H4, V16.H4, V17.H4, V18.H4] // VLD4R.P (R15)(R9*1), [V15.H4, V16.H4, V17.H4, V18.H4] // efe5e90d + VLD4R.P (R15)(R9), [V15.H4, V16.H4, V17.H4, V18.H4] // efe5e90d VST1.P [V24.S2], 8(R2) // 58789f0c VST1 [V29.S2, V30.S2], (R29) // bdab000c VST1 [V14.H4, V15.H4, V16.H4], (R27) // 6e67000c @@ -439,17 +439,17 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 VST1.P V4.H[7], 2(R0) // 04589f4d VST1.P V4.S[3], 4(R0) // 04909f4d VST1.P V4.D[1], 8(R0) // 04849f4d - VST1.P V4.D[1], (R0)(R1) // VST1.P V4.D[1], (R0)(R1*1) // 0484814d + VST1.P V4.D[1], (R0)(R1) // 0484814d VST1 V4.D[1], (R0) // 0484004d VST2 [V22.H8, V23.H8], (R23) // f686004c VST2.P [V14.H4, V15.H4], 16(R17) // 2e869f0c - VST2.P [V14.H4, V15.H4], (R3)(R17) // VST2.P [V14.H4,V15.H4], (R3)(R17*1) // 6e84910c + VST2.P [V14.H4, V15.H4], (R3)(R17) // 6e84910c VST3 [V1.D2, V2.D2, V3.D2], (R11) // 614d004c VST3.P [V18.S4, V19.S4, V20.S4], 48(R25) // 324b9f4c - VST3.P [V19.B8, V20.B8, V21.B8], (R3)(R7) // VST3.P [V19.B8, V20.B8, V21.B8], (R3)(R7*1) // 7340870c + VST3.P [V19.B8, V20.B8, V21.B8], (R3)(R7) // 7340870c VST4 [V22.D2, V23.D2, V24.D2, V25.D2], (R3) // 760c004c VST4.P [V14.D2, V15.D2, V16.D2, V17.D2], 64(R15) // ee0d9f4c - VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23) // VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23*1) // 7800970c + VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23) // 7800970c // pre/post-indexed FMOVS.P F20, 4(R0) // 144400bc @@ -536,29 +536,29 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 // shifted or extended register offset. MOVD (R2)(R6.SXTW), R4 // 44c866f8 - MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8 - MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8 + MOVD (R3)(R6), R5 // 656866f8 + MOVD (R2)(R6), R4 // 446866f8 MOVWU (R19)(R20<<2), R20 // 747a74b8 MOVD (R2)(R6<<3), R4 // 447866f8 MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8 MOVWU (R5)(R4.UXTW), R10 // aa4864b8 MOVBU (R3)(R9.UXTW), R8 // 68486938 - MOVBU (R5)(R8), R10 // MOVBU (R5)(R8*1), R10 // aa686838 + MOVBU (R5)(R8), R10 // aa686838 MOVHU (R2)(R7.SXTW<<1), R11 // 4bd86778 MOVHU (R1)(R2<<1), R5 // 25786278 MOVB (R9)(R3.UXTW), R6 // 2649a338 - MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638 + MOVB (R10)(R6), R15 // 4f69a638 MOVB (R29)(R30<<0), R14 // ae7bbe38 - MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38 + MOVB (R29)(R30), R14 // ae6bbe38 MOVH (R5)(R7.SXTX<<1), R19 // b3f8a778 MOVH (R8)(R4<<1), R10 // 0a79a478 MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8 MOVW (R1)(R4.SXTX), R11 // 2be8a4b8 MOVW (R1)(R4.SXTX), ZR // 3fe8a4b8 - MOVW (R2)(R5), R12 // MOVW (R2)(R5*1), R12 // 4c68a5b8 - FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc + MOVW (R2)(R5), R12 // 4c68a5b8 + FMOVS (R2)(R6), F4 // 446866bc FMOVS (R2)(R6<<2), F4 // 447866bc - FMOVD (R2)(R6), F4 // FMOVD (R2)(R6*1), F4 // 446866fc + FMOVD (R2)(R6), F4 // 446866fc FMOVD (R2)(R6<<3), F4 // 447866fc MOVD R5, (R2)(R6<<3) // 457826f8 @@ -568,15 +568,15 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVW R7, (R3)(R4.SXTW) // 67c824b8 MOVB R4, (R2)(R6.SXTX) // 44e82638 MOVB R8, (R3)(R9.UXTW) // 68482938 - MOVB R10, (R5)(R8) // MOVB R10, (R5)(R8*1) // aa682838 + MOVB R10, (R5)(R8) // aa682838 MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778 MOVH R5, (R1)(R2<<1) // 25782278 MOVH R7, (R2)(R5.SXTX<<1) // 47f82578 MOVH R8, (R3)(R6.UXTW) // 68482678 MOVB R4, (R2)(R6.SXTX) // 44e82638 - FMOVS F4, (R2)(R6) // FMOVS F4, (R2)(R6*1) // 446826bc + FMOVS F4, (R2)(R6) // 446826bc FMOVS F4, (R2)(R6<<2) // 447826bc - FMOVD F4, (R2)(R6) // FMOVD F4, (R2)(R6*1) // 446826fc + FMOVD F4, (R2)(R6) // 446826fc FMOVD F4, (R2)(R6<<3) // 447826fc // vmov diff --git a/src/cmd/asm/internal/asm/testdata/arm64enc.s b/src/cmd/asm/internal/asm/testdata/arm64enc.s index e802ee76f5..f71f7b0484 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64enc.s +++ b/src/cmd/asm/internal/asm/testdata/arm64enc.s @@ -188,7 +188,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 MOVBU 2916(R24), R3 // 03936d39 MOVBU (R19)(R14<<0), R23 // 777a6e38 MOVBU (R2)(R8.SXTX), R19 // 53e86838 - MOVBU (R27)(R23), R14 // MOVBU (R27)(R23*1), R14 // 6e6b7738 + MOVBU (R27)(R23), R14 // 6e6b7738 MOVHU.P 107(R14), R13 // cdb54678 MOVHU.W 192(R3), R2 // 620c4c78 MOVHU 6844(R4), R19 // 93787579 @@ -201,9 +201,9 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 MOVB 997(R9), R23 // 37958f39 //TODO MOVBW (R2<<1)(R21), R15 // af7ae238 //TODO MOVBW (R26)(R0), R21 // 1568fa38 - MOVB (R5)(R15), R16 // MOVB (R5)(R15*1), R16 // b068af38 + MOVB (R5)(R15), R16 // b068af38 MOVB (R19)(R26.SXTW), R19 // 73caba38 - MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38 + MOVB (R29)(R30), R14 // ae6bbe38 //TODO MOVHW.P 218(R22), R25 // d9a6cd78 MOVH.P 179(R23), R5 // e5368b78 //TODO MOVHW.W 136(R2), R27 // 5b8cc878 @@ -357,12 +357,12 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 MOVD R25, -137(R17) // 397217f8 MOVW R4, (R12)(R22.UXTW<<2) // 845936b8 MOVD R27, (R5)(R15.UXTW<<3) // bb582ff8 - MOVB R2, (R10)(R16) // MOVB R2, (R10)(R16*1) // 42693038 - MOVB R2, (R29)(R26) // MOVB R2, (R29)(R26*1) // a26b3a38 + MOVB R2, (R10)(R16) // 42693038 + MOVB R2, (R29)(R26) // a26b3a38 MOVH R11, -80(R23) // eb021b78 MOVH R11, (R27)(R14.SXTW<<1) // 6bdb2e78 - MOVB R19, (R0)(R4) // MOVB R19, (R0)(R4*1) // 13682438 - MOVB R1, (R6)(R4) // MOVB R1, (R6)(R4*1) // c1682438 + MOVB R19, (R0)(R4) // 13682438 + MOVB R1, (R6)(R4) // c1682438 MOVH R3, (R11)(R13<<1) // 63792d78 //TODO STTR 55(R4), R29 // 9d7803b8 //TODO STTR 124(R5), R25 // b9c807f8 @@ -679,23 +679,23 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 VLD1 (R24), [V18.D1, V19.D1, V20.D1] // 126f400c VLD1 (R29), [V14.D1, V15.D1, V16.D1, V17.D1] // ae2f400c VLD1.P 16(R23), [V1.B16] // e172df4c - VLD1.P (R6)(R11), [V31.D1] // VLD1.P (R6)(R11*1), [V31.D1] // df7ccb0c + VLD1.P (R6)(R11), [V31.D1] // df7ccb0c VLD1.P 16(R7), [V31.D1, V0.D1] // ffacdf0c - VLD1.P (R19)(R4), [V24.B8, V25.B8] // VLD1.P (R19)(R4*1), [V24.B8, V25.B8] // 78a2c40c - VLD1.P (R20)(R8), [V7.H8, V8.H8, V9.H8] // VLD1.P (R20)(R8*1), [V7.H8, V8.H8, V9.H8] // 8766c84c + VLD1.P (R19)(R4), [V24.B8, V25.B8] // 78a2c40c + VLD1.P (R20)(R8), [V7.H8, V8.H8, V9.H8] // 8766c84c VLD1.P 32(R30), [V5.B8, V6.B8, V7.B8, V8.B8] // c523df0c VLD1 (R19), V14.B[15] // 6e1e404d VLD1 (R29), V0.H[1] // a04b400d VLD1 (R27), V2.S[0] // 6283400d VLD1 (R21), V5.D[1] // a586404d VLD1.P 1(R19), V10.B[14] // 6a1adf4d - VLD1.P (R3)(R14), V16.B[11] // VLD1.P (R3)(R14*1), V16.B[11] // 700cce4d + VLD1.P (R3)(R14), V16.B[11] // 700cce4d VLD1.P 2(R1), V28.H[2] // 3c50df0d - VLD1.P (R13)(R20), V9.H[2] // VLD1.P (R13)(R20*1), V9.H[2] // a951d40d + VLD1.P (R13)(R20), V9.H[2] // a951d40d VLD1.P 4(R17), V1.S[3] // 2192df4d - VLD1.P (R14)(R2), V17.S[2] // VLD1.P (R14)(R2*1), V17.S[2] // d181c24d + VLD1.P (R14)(R2), V17.S[2] // d181c24d VLD1.P 8(R5), V30.D[1] // be84df4d - VLD1.P (R27)(R13), V27.D[0] // VLD1.P (R27)(R13*1), V27.D[0] // 7b87cd0d + VLD1.P (R27)(R13), V27.D[0] // 7b87cd0d //TODO FMOVS.P -29(RSP), F8 // e8375ebc //TODO FMOVS.W 71(R29), F28 // bc7f44bc FMOVS 6160(R4), F23 // 971058bd @@ -732,25 +732,25 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 VSHL $7, V22.D2, V25.D2 // d956474f VST1 [V14.H4, V15.H4, V16.H4], (R27) // 6e67000c VST1 [V2.S4, V3.S4, V4.S4, V5.S4], (R14) // c229004c - VST1.P [V25.S4], (R7)(R29) // VST1.P [V25.S4], (R7)(R29*1) // f9789d4c + VST1.P [V25.S4], (R7)(R29) // f9789d4c VST1.P [V25.D2, V26.D2], 32(R7) // f9ac9f4c - VST1.P [V14.D1, V15.D1], (R7)(R23) // VST1.P [V14.D1, V15.D1], (R7)(R23*1) // eeac970c + VST1.P [V14.D1, V15.D1], (R7)(R23) // eeac970c VST1.P [V25.D2, V26.D2, V27.D2], 48(R27) // 796f9f4c - VST1.P [V13.H8, V14.H8, V15.H8], (R3)(R14) // VST1.P [V13.H8, V14.H8, V15.H8], (R3)(R14*1) // 6d648e4c + VST1.P [V13.H8, V14.H8, V15.H8], (R3)(R14) // 6d648e4c VST1.P [V16.S4, V17.S4, V18.S4, V19.S4], 64(R6) // d0289f4c - VST1.P [V19.H4, V20.H4, V21.H4, V22.H4], (R4)(R16) // VST1.P [V19.H4, V20.H4, V21.H4, V22.H4], (R4)(R16*1) // 9324900c + VST1.P [V19.H4, V20.H4, V21.H4, V22.H4], (R4)(R16) // 9324900c VST1 V12.B[3], (R1) // 2c0c000d VST1 V12.B[3], (R1) // 2c0c000d VST1 V25.S[2], (R20) // 9982004d VST1 V9.D[1], (RSP) // e987004d VST1.P V30.B[6], 1(R3) // 7e189f0d - VST1.P V8.B[0], (R3)(R21) // VST1.P V8.B[0], (R3)(R21*1) // 6800950d + VST1.P V8.B[0], (R3)(R21) // 6800950d VST1.P V15.H[5], 2(R10) // 4f499f4d - VST1.P V1.H[7], (R23)(R11) // VST1.P V1.H[7], (R23)(R11*1) // e15a8b4d + VST1.P V1.H[7], (R23)(R11) // e15a8b4d VST1.P V26.S[0], 4(R11) // 7a819f0d - VST1.P V9.S[1], (R16)(R21) // VST1.P V9.S[1], (R16)(R21*1) // 0992950d + VST1.P V9.S[1], (R16)(R21) // 0992950d VST1.P V16.D[0], 8(R9) // 30859f0d - VST1.P V23.D[1], (R21)(R16) // VST1.P V23.D[1], (R21)(R16*1) // b786904d + VST1.P V23.D[1], (R21)(R16) // b786904d VSUB V1, V12, V23 // 9785e17e VUADDLV V31.S4, V11 // eb3bb06e UCVTFWS R11, F19 // 7301231e -- GitLab From 775f11cda1d30f3f9778e737c2280cfe28ead1b4 Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 12 Jan 2021 02:45:46 +0000 Subject: [PATCH 0173/1298] cmd/internal/obj/arm64: remove unncessary class check in addpool The argument class check in addpool is unnecessary, remove it so that we don't need to list all the compatiable classes. Change-Id: I36f6594db35e25db22fe898273e024c2db4cb771 Reviewed-on: https://go-review.googlesource.com/c/go/+/283492 Trust: eric fang Reviewed-by: Cherry Zhang --- src/cmd/internal/obj/arm64/asm7.go | 97 +----------------------------- 1 file changed, 2 insertions(+), 95 deletions(-) diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 3b0fa6fb53..e9f18e1bf0 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -1251,101 +1251,8 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) { sz = 8 } - switch cls { - // TODO(aram): remove. - default: - if a.Name != obj.NAME_EXTERN { - fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(cls), p) - } - - t.To.Offset = a.Offset - t.To.Sym = a.Sym - t.To.Type = a.Type - t.To.Name = a.Name - - /* This is here because MOV uint12<<12, R is disabled in optab. - Because of this, we need to load the constant from memory. */ - case C_ADDCON: - fallthrough - - case C_ADDCON2, - C_LCON, - C_VCON, - C_LACON, - - C_ZAUTO, - C_NSAUTO_16, - C_NSAUTO_8, - C_NSAUTO_4, - C_NSAUTO, - C_NPAUTO_16, - C_NPAUTO, - C_NQAUTO_16, - C_NAUTO4K, - C_PSAUTO_16, - C_PSAUTO_8, - C_PSAUTO_4, - C_PSAUTO, - C_PPAUTO_16, - C_PPAUTO, - C_PQAUTO_16, - C_UAUTO4K_16, - C_UAUTO4K_8, - C_UAUTO4K_4, - C_UAUTO4K_2, - C_UAUTO4K, - C_UAUTO8K_16, - C_UAUTO8K_8, - C_UAUTO8K_4, - C_UAUTO8K, - C_UAUTO16K_16, - C_UAUTO16K_8, - C_UAUTO16K, - C_UAUTO32K_16, - C_UAUTO32K, - C_UAUTO64K, - C_LAUTO, - - C_ZOREG, - C_NSOREG_16, - C_NSOREG_8, - C_NSOREG_4, - C_NSOREG, - C_NPOREG_16, - C_NPOREG, - C_NQOREG_16, - C_NOREG4K, - C_PSOREG_16, - C_PSOREG_8, - C_PSOREG_4, - C_PSOREG, - C_PPOREG_16, - C_PPOREG, - C_PQOREG_16, - C_UOREG4K_16, - C_UOREG4K_8, - C_UOREG4K_4, - C_UOREG4K_2, - C_UOREG4K, - C_UOREG8K_16, - C_UOREG8K_8, - C_UOREG8K_4, - C_UOREG8K, - C_UOREG16K_16, - C_UOREG16K_8, - C_UOREG16K, - C_UOREG32K_16, - C_UOREG32K, - C_UOREG64K, - C_LOREG: - if a.Name == obj.NAME_EXTERN { - fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p) - } - - t.To.Type = obj.TYPE_CONST - t.To.Offset = lit - break - } + t.To.Type = obj.TYPE_CONST + t.To.Offset = lit for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ if q.To == t.To { -- GitLab From 04a4dca2ac3d4f963e3c740045ce7a2959bf0319 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 17 Feb 2021 12:17:25 -0500 Subject: [PATCH 0174/1298] cmd/compile: refactor out an almost-superfluous arg Moved all "target" information into "storeRC"; it was a register cursor, now it is a register cursor that also carries the store target with it if there are no registers. Also allows booby-trapping to ensure that the target is unambiguously one or the other. For #40724. Change-Id: I53ba4b91679e5fcc89c63b7d31225135299c6ec6 Reviewed-on: https://go-review.googlesource.com/c/go/+/293397 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 162 ++++++++++--------- 1 file changed, 90 insertions(+), 72 deletions(-) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 87b8a02b25..1868e3f073 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -62,12 +62,31 @@ func removeTrivialWrapperTypes(t *types.Type) *types.Type { // A registerCursor tracks which register is used for an Arg or regValues, or a piece of such. type registerCursor struct { // TODO(register args) convert this to a generalized target cursor. + storeDest *Value // if there are no register targets, then this is the base of the store. regsLen int // the number of registers available for this Arg/result (which is all in registers or not at all) nextSlice Abi1RO // the next register/register-slice offset config *abi.ABIConfig regValues *[]*Value // values assigned to registers accumulate here } +func (rc *registerCursor) String() string { + dest := "" + if rc.storeDest != nil { + dest = rc.storeDest.String() + } + regs := "" + if rc.regValues != nil { + regs = "" + for i, x := range *rc.regValues { + if i > 0 { + regs = regs + "; " + } + regs = regs + x.LongString() + } + } + return fmt.Sprintf("RCSR{storeDest=%v, regsLen=%d, nextSlice=%d, regValues=[%s], config=%v", dest, rc.regsLen, rc.nextSlice, regs, rc.config) +} + // next effectively post-increments the register cursor; the receiver is advanced, // the old value is returned. func (c *registerCursor) next(t *types.Type) registerCursor { @@ -139,10 +158,11 @@ func (c *registerCursor) at(t *types.Type, i int) registerCursor { panic("Haven't implemented this case yet, do I need to?") } -func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value) { +func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value, storeDest *Value) { c.regsLen = len(regs) c.nextSlice = 0 if len(regs) == 0 { + c.storeDest = storeDest // only save this if there are no registers, will explode if misused. return } c.config = info.Config() @@ -519,20 +539,20 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, // Parameters: // pos -- the location of any generated code. // b -- the block into which any generated code should normally be placed -// base -- for the stores that will ultimately be generated, the base to which the offset is applied. (Note this disappears in a future CL, folded into storeRc) // source -- the value, possibly an aggregate, to be stored. // mem -- the mem flowing into this decomposition (loads depend on it, stores updated it) // t -- the type of the value to be stored -// offset -- if the value is stored in memory, it is stored at base + offset +// offset -- if the value is stored in memory, it is stored at base (see storeRc) + offset // loadRegOffset -- regarding source as a value in registers, the register offset in ABI1. Meaningful only if source is OpArg. -// storeRc -- storeRC; if the value is stored in registers, this specifies the registers. StoreRc also identifies whether the target is registers or memory. +// storeRc -- storeRC; if the value is stored in registers, this specifies the registers. +// StoreRc also identifies whether the target is registers or memory, and has the base for the store operation. // // TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates. -func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor, +func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor, // For decompose One and Two, the additional offArg provides the offset from the beginning of "source", if it is in memory. // offStore is combined to base to obtain a store destionation, like "offset" of decomposeArgOrLoad - decomposeOne func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value, - decomposeTwo func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value { + decomposeOne func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value, + decomposeTwo func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value { u := source.Type switch u.Kind() { case types.TARRAY: @@ -540,7 +560,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m elemRO := x.regWidth(elem) for i := int64(0); i < u.NumElem(); i++ { elemOff := i * elem.Size() - mem = decomposeOne(x, pos, b, base, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) + mem = decomposeOne(x, pos, b, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) loadRegOffset += elemRO pos = pos.WithNotStmt() } @@ -548,7 +568,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m case types.TSTRUCT: for i := 0; i < u.NumFields(); i++ { fld := u.Field(i) - mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = decomposeOne(x, pos, b, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -558,80 +578,78 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m break } tHi, tLo := x.intPairTypes(t.Kind()) - mem = decomposeOne(x, pos, b, base, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = decomposeOne(x, pos, b, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() - return decomposeOne(x, pos, b, base, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) + return decomposeOne(x, pos, b, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) case types.TINTER: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) case types.TSTRING: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX64: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX128: - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) + return decomposeTwo(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) case types.TSLICE: - mem = decomposeOne(x, pos, b, base, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) - return decomposeTwo(x, pos, b, base, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) + mem = decomposeOne(x, pos, b, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return decomposeTwo(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) } return nil } // storeOneArg creates a decomposed (one step) arg that is then stored. -// pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input, +// pos and b locate the store instruction, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. -func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { w := x.commonArgs[selKey{source, offArg, t.Width, t}] if w == nil { - // w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux) w = x.newArgToMemOrRegs(source, w, offArg, loadRegOffset, t, pos) - // x.commonArgs[selKey{source, offArg, t.Width, t}] = w } - return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) } // storeOneLoad creates a decomposed (one step) load that is then stored. -func storeOneLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { from := x.offsetFrom(source.Args[0], offArg, types.NewPtr(t)) w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem) - return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) } -func storeTwoArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - mem = storeOneArg(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) +func storeTwoArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + mem = storeOneArg(x, pos, b, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) pos = pos.WithNotStmt() t1Size := t1.Size() - return storeOneArg(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) + return storeOneArg(x, pos, b, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) } // storeTwoLoad creates a pair of decomposed (one step) loads that are then stored. // the elements of the pair must not require any additional alignment. -func storeTwoLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - mem = storeOneLoad(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) +func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + mem = storeOneLoad(x, pos, b, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1)) pos = pos.WithNotStmt() t1Size := t1.Size() - return storeOneLoad(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) + return storeOneLoad(x, pos, b, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc) } // storeArgOrLoad converts stores of SSA-able potentially aggregatable arguments (passed to a call) into a series of primitive-typed // stores of non-aggregate types. It recursively walks up a chain of selectors until it reaches a Load or an Arg. // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering. -func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { if x.debug { - fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %s; %d)\n", base.LongString(), source.LongString(), mem.String(), t.String(), offset) + fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String()) } switch source.Op { case OpCopy: - return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc) case OpLoad: - ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad) + ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad) if ret != nil { return ret } case OpArg: - ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg) + ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg) if ret != nil { return ret } @@ -643,19 +661,19 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4: for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) - mem = x.storeArgOrLoad(pos, b, base, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type)) + mem = x.storeArgOrLoad(pos, b, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type)) pos = pos.WithNotStmt() } return mem case OpArrayMake1: - return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0)) + return x.storeArgOrLoad(pos, b, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0)) case OpInt64Make: tHi, tLo := x.intPairTypes(t.Kind()) - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc) case OpComplexMake: tPart := x.typs.Float32 @@ -663,25 +681,25 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * if wPart == 8 { tPart = x.typs.Float64 } - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tPart, offset+wPart, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, tPart, offset+wPart, 0, storeRc) case OpIMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc) case OpStringMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc) case OpSliceMake: - mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - mem = x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int)) - return x.storeArgOrLoad(pos, b, base, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc) + mem = x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int)) + return x.storeArgOrLoad(pos, b, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc) } // For nodes that cannot be taken apart -- OpSelectN, other structure selectors. @@ -691,12 +709,12 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == x.regSize { t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) } eltRO := x.regWidth(elt) for i := int64(0); i < t.NumElem(); i++ { sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0)) + mem = x.storeArgOrLoad(pos, b, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0)) loadRegOffset += eltRO pos = pos.WithNotStmt() } @@ -724,13 +742,13 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * // of a *uint8, which does not succeed. t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) } for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = x.storeArgOrLoad(pos, b, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -742,48 +760,48 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * } tHi, tLo := x.intPairTypes(t.Kind()) sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = x.storeArgOrLoad(pos, b, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo)) + return x.storeArgOrLoad(pos, b, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo)) case types.TINTER: sel := source.Block.NewValue1(pos, OpITab, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpIData, x.typs.BytePtr, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc) case types.TSTRING: sel := source.Block.NewValue1(pos, OpStringPtr, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpStringLen, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc) case types.TSLICE: et := types.NewPtr(t.Elem()) sel := source.Block.NewValue1(pos, OpSlicePtr, et, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, et, offset, loadRegOffset, storeRc.next(et)) + mem = x.storeArgOrLoad(pos, b, sel, mem, et, offset, loadRegOffset, storeRc.next(et)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpSliceLen, x.typs.Int, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int)) sel = source.Block.NewValue1(pos, OpSliceCap, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc) case types.TCOMPLEX64: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float32, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float32, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc) case types.TCOMPLEX128: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float64, source) - mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float64, source) - return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc) } s := mem @@ -791,7 +809,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem * // TODO(register args) storeRc.addArg(source) } else { - dst := x.offsetFrom(base, offset, types.NewPtr(t)) + dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t)) s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) } if x.debug { @@ -843,8 +861,8 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { if x.debug { fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) } - rc.init(aRegs, aux.abiInfo, result) - mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc) + rc.init(aRegs, aux.abiInfo, result, x.sp) + mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc) // TODO append mem to Result, update type } } @@ -959,9 +977,9 @@ func expandCalls(f *Func) { if len(aRegs) > 0 { result = &allResults } - rc.init(aRegs, aux.abiInfo, result) - // TODO(register args) - mem = x.storeArgOrLoad(v.Pos, b, auxBase, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc) + rc.init(aRegs, aux.abiInfo, result, auxBase) + // TODO REGISTER + mem = x.storeArgOrLoad(v.Pos, b, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc) // TODO append mem to Result, update type } } @@ -1005,7 +1023,7 @@ func expandCalls(f *Func) { fmt.Printf("Splitting store %s\n", v.LongString()) } dst, mem := v.Args[0], v.Args[2] - mem = x.storeArgOrLoad(v.Pos, b, dst, source, mem, t, 0, 0, registerCursor{}) + mem = x.storeArgOrLoad(v.Pos, b, source, mem, t, 0, 0, registerCursor{storeDest: dst}) v.copyOf(mem) } } -- GitLab From 95ff296a11606cec32fb697c74aee520f23498b0 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 17 Feb 2021 18:01:52 -0500 Subject: [PATCH 0175/1298] cmd/compile: pass arguments as register parameters to StaticCall. Additional register-parameter plumbing, not all the way to the end; if you test register parameter-passing, it fails mid-compilation. For #40724. Change-Id: Ibb675022c9156779a451726329890e52fca1cb33 Reviewed-on: https://go-review.googlesource.com/c/go/+/293398 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/ssa/expand_calls.go | 49 ++++++++++---------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 1868e3f073..ff16eac90f 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -806,7 +806,6 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, s := mem if storeRc.hasRegs() { - // TODO(register args) storeRc.addArg(source) } else { dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t)) @@ -821,21 +820,15 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, // rewriteArgs removes all the Args from a call and converts the call args into appropriate // stores (or later, register movement). Extra args for interface and closure calls are ignored, // but removed. -func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { +func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) { // Thread the stores on the memory arg aux := v.Aux.(*AuxCall) pos := v.Pos.WithNotStmt() m0 := v.MemoryArg() mem := m0 allResults := []*Value{} - for i, a := range v.Args { - if i < firstArg { - continue - } - if a == m0 { // mem is last. - break - } - auxI := int64(i - firstArg) + for i, a := range v.Args[firstArg : len(v.Args)-1] { // skip leading non-parameter SSA Args and trailing mem SSA Arg. + auxI := int64(i) aRegs := aux.RegsOfArg(auxI) aType := aux.TypeOfArg(auxI) if a.Op == OpDereference { @@ -863,11 +856,10 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value { } rc.init(aRegs, aux.abiInfo, result, x.sp) mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc) - // TODO append mem to Result, update type } } v.resetArgs() - return mem + return mem, allResults } // expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form @@ -921,17 +913,30 @@ func expandCalls(f *Func) { for _, v := range b.Values { switch v.Op { case OpStaticLECall: - mem := x.rewriteArgs(v, 0) - v.SetArgs1(mem) + mem, results := x.rewriteArgs(v, 0) + v.AddArgs(results...) + v.AddArg(mem) case OpClosureLECall: code := v.Args[0] context := v.Args[1] - mem := x.rewriteArgs(v, 2) - v.SetArgs3(code, context, mem) + mem, results := x.rewriteArgs(v, 2) + if len(results) == 0 { + v.SetArgs3(code, context, mem) + } else { + v.SetArgs2(code, context) + v.AddArgs(results...) + v.AddArg(mem) + } case OpInterLECall: code := v.Args[0] - mem := x.rewriteArgs(v, 1) - v.SetArgs2(code, mem) + mem, results := x.rewriteArgs(v, 1) + if len(results) == 0 { + v.SetArgs2(code, mem) + } else { + v.SetArgs1(code) + v.AddArgs(results...) + v.AddArg(mem) + } } } if isBlockMultiValueExit(b) { @@ -942,11 +947,8 @@ func expandCalls(f *Func) { aux := f.OwnAux pos := v.Pos.WithNotStmt() allResults := []*Value{} - for j, a := range v.Args { + for j, a := range v.Args[:len(v.Args)-1] { i := int64(j) - if a == m0 { - break - } auxType := aux.TypeOfResult(i) auxBase := b.NewValue2A(v.Pos, OpLocalAddr, types.NewPtr(auxType), aux.results[i].Name, x.sp, mem) auxOffset := int64(0) @@ -978,11 +980,10 @@ func expandCalls(f *Func) { result = &allResults } rc.init(aRegs, aux.abiInfo, result, auxBase) - // TODO REGISTER mem = x.storeArgOrLoad(v.Pos, b, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc) - // TODO append mem to Result, update type } } + // TODO REGISTER -- keep the Result for block control, splice in contents of AllResults b.SetControl(mem) v.reset(OpInvalid) // otherwise it can have a mem operand which will fail check(), even though it is dead. } -- GitLab From 4532467c1854fa16378063bd99defadc4a1e5fb1 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 18 Feb 2021 15:50:37 -0500 Subject: [PATCH 0176/1298] cmd/compile: pass register parameters to called function still needs morestack still needs results lots of corner cases also not dealt with. For #40724. Change-Id: I03abdf1e8363d75c52969560b427e488a48cd37a Reviewed-on: https://go-review.googlesource.com/c/go/+/293889 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 3 +- src/cmd/compile/internal/ssa/op.go | 54 +++++++++++++++++++- src/cmd/compile/internal/ssa/opGen.go | 2 +- src/cmd/compile/internal/ssa/regalloc.go | 27 ++++++++-- 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index fd2c2023e6..5f5ebaaa35 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -771,7 +771,8 @@ func init() { faultOnNilArg0: true, }, - {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem + // With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific registers. + {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 0bc7b0ca0d..4082e84c6a 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -96,6 +96,54 @@ type AuxCall struct { abiInfo *abi.ABIParamResultInfo // TODO remove fields above redundant with this information. } +// Reg returns the regInfo for a given call, combining the derived in/out register masks +// with the machine-specific register information in the input i. (The machine-specific +// regInfo is much handier at the call site than it is when the AuxCall is being constructed, +// therefore do this lazily). +// +// TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices +// of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs +// and outputs from calls, so that all integer registers come first, then all floating registers. +// At this point (active development of register ABI) that is very premature, +// but if this turns out to be a cost, we could do it. +func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo { + if a.reg.clobbers != 0 { + // Already updated + return a.reg + } + if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 { + // Shortcut for zero case, also handles old ABI. + a.reg = i + return a.reg + } + a.reg.inputs = append(a.reg.inputs, i.inputs...) + for _, p := range a.abiInfo.InParams() { + for _, r := range p.Registers { + m := archRegForAbiReg(r, c) + a.reg.inputs = append(a.reg.inputs, inputInfo{idx: len(a.reg.inputs), regs: (1 << m)}) + } + } + a.reg.outputs = append(a.reg.outputs, i.outputs...) + for _, p := range a.abiInfo.OutParams() { + for _, r := range p.Registers { + m := archRegForAbiReg(r, c) + a.reg.outputs = append(a.reg.outputs, outputInfo{idx: len(a.reg.outputs), regs: (1 << m)}) + } + } + a.reg.clobbers = i.clobbers + return a.reg +} + +func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 { + var m int8 + if int(r) < len(c.intParamRegs) { + m = c.intParamRegs[r] + } else { + m = c.floatParamRegs[int(r)-len(c.intParamRegs)] + } + return uint8(m) +} + // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { n := int64(a.abiInfo.OutParam(int(which)).Offset()) @@ -217,7 +265,11 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo if paramResultInfo == nil { panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym)) } - return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo} + var reg *regInfo + if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { + reg = ®Info{} + } + return &AuxCall{Fn: sym, args: args, results: results, abiInfo: paramResultInfo, reg: reg} } // InterfaceAuxCall returns an AuxCall for an interface call. diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index a9565ffe4b..34445cfbf1 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -13229,7 +13229,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLstatic", auxType: auxCallOff, - argLen: 1, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c11138bf4e..c2d0478e82 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -151,6 +151,14 @@ type register uint8 const noRegister register = 255 +// For bulk initializing +var noRegisters [32]register = [32]register{ + noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, + noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, + noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, + noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, +} + // A regMask encodes a set of machine registers. // TODO: regMask -> regSet? type regMask uint64 @@ -818,9 +826,8 @@ func (s *regAllocState) regspec(v *Value) regInfo { return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}} } if op.IsCall() { - // TODO Panic if not okay if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil { - return *ac.reg + return *ac.Reg(&opcodeTable[op].reg, s.f.Config) } } return opcodeTable[op].reg @@ -1456,7 +1463,8 @@ func (s *regAllocState) regalloc(f *Func) { // Pick registers for outputs. { - outRegs := [2]register{noRegister, noRegister} + outRegs := noRegisters // TODO if this is costly, hoist and clear incrementally below. + maxOutIdx := -1 var used regMask for _, out := range regspec.outputs { mask := out.regs & s.allocatable &^ used @@ -1502,6 +1510,9 @@ func (s *regAllocState) regalloc(f *Func) { mask &^= desired.avoid } r := s.allocReg(mask, v) + if out.idx > maxOutIdx { + maxOutIdx = out.idx + } outRegs[out.idx] = r used |= regMask(1) << r s.tmpused |= regMask(1) << r @@ -1518,8 +1529,14 @@ func (s *regAllocState) regalloc(f *Func) { s.f.setHome(v, outLocs) // Note that subsequent SelectX instructions will do the assignReg calls. } else if v.Type.IsResults() { - // TODO register arguments need to make this work - panic("Oops, implement this.") + // preallocate outLocs to the right size, which is maxOutIdx+1 + outLocs := make(LocResults, maxOutIdx+1, maxOutIdx+1) + for i := 0; i <= maxOutIdx; i++ { + if r := outRegs[i]; r != noRegister { + outLocs[i] = &s.registers[r] + } + } + s.f.setHome(v, outLocs) } else { if r := outRegs[0]; r != noRegister { s.assignReg(r, v, v) -- GitLab From b7f4307761c61d2d3f563c37b0c9ad0e64899d9f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 19 Feb 2021 12:42:57 +0700 Subject: [PATCH 0177/1298] cmd/compile: graceful handle error in noder LoadPackage When syntax.Parse returns error, noder.file will be nil. Currently, we continue accessing it regardlessly and depend on gc.hidePanic to hide the panic from user. Instead, we should gracefully handle the error in LoadPackage, then exit earlier if any error occurred. Updates #43311 Change-Id: I0a108ef360bd4f0cc9f481071b8967355e1513af Reviewed-on: https://go-review.googlesource.com/c/go/+/294030 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/noder.go | 3 +++ test/fixedbugs/bug050.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index d692bf97aa..8c456e4561 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -68,6 +68,9 @@ func LoadPackage(filenames []string) { for e := range p.err { p.errorAt(e.Pos, "%s", e.Msg) } + if p.file == nil { + base.ErrorExit() + } lines += p.file.EOF.Line() } base.Timer.AddEvent(int64(lines), "lines") diff --git a/test/fixedbugs/bug050.go b/test/fixedbugs/bug050.go index aba68b1dcb..1e299ed99a 100644 --- a/test/fixedbugs/bug050.go +++ b/test/fixedbugs/bug050.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- GitLab From 12a405b96aadc0174d3b63e61f593bcc28465af0 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 19 Feb 2021 13:54:28 +0700 Subject: [PATCH 0178/1298] cmd/compile: do not set type for OPACK That's an invalid operation and depend on gc.hidePanic to report error. Updates #43311 Change-Id: I78d615c40ab1e7887f612491e215c1c2bb758ef6 Reviewed-on: https://go-review.googlesource.com/c/go/+/294031 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 5a3446b358..278e64fc61 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -528,7 +528,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OPACK: n := n.(*ir.PkgName) base.Errorf("use of package %v without selector", n.Sym()) - n.SetType(nil) + n.SetDiag(true) return n // types (ODEREF is with exprs) -- GitLab From 8c22874e4e804e29ca040599ec63bb9e35233acd Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 19 Feb 2021 13:47:14 +0700 Subject: [PATCH 0179/1298] cmd/compile: skip diag error in checkassign if one was emitted While at it, also remove checkassignlist, which is not used. For #43311 Change-Id: Ie7ed81f68080d8881fca6035da64a9755f2cb555 Reviewed-on: https://go-review.googlesource.com/c/go/+/294032 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 278e64fc61..e7d4e81672 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1612,6 +1612,10 @@ func checkassign(stmt ir.Node, n ir.Node) { return } + defer n.SetType(nil) + if n.Diag() { + return + } switch { case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).X.Op() == ir.OINDEXMAP: base.Errorf("cannot assign to struct field %v in map", n) @@ -1622,13 +1626,6 @@ func checkassign(stmt ir.Node, n ir.Node) { default: base.Errorf("cannot assign to %v", n) } - n.SetType(nil) -} - -func checkassignlist(stmt ir.Node, l ir.Nodes) { - for _, n := range l { - checkassign(stmt, n) - } } func checkassignto(src *types.Type, dst ir.Node) { -- GitLab From 4b8b2c58647af6f1979d8c53d886c8cd71c99e4b Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 19 Feb 2021 13:50:42 +0700 Subject: [PATCH 0180/1298] cmd/compile: do not set type for OTYPE That's an invalid operation and depend on gc.hidePanic to report error. Updates #43311 Change-Id: Ib0761dcf4d9d2a23c41de7eff0376677a90b942e Reviewed-on: https://go-review.googlesource.com/c/go/+/294033 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index e7d4e81672..240f0409e7 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -433,8 +433,8 @@ func typecheck(n ir.Node, top int) (res ir.Node) { case top&ctxType == 0 && n.Op() == ir.OTYPE && t != nil: if !n.Type().Broke() { base.Errorf("type %v is not an expression", n.Type()) + n.SetDiag(true) } - n.SetType(nil) case top&(ctxStmt|ctxExpr) == ctxStmt && !isStmt && t != nil: if !n.Diag() { -- GitLab From 1d0256a9890b9179746551910a20cee97e653101 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 20 Feb 2021 02:40:35 +0700 Subject: [PATCH 0181/1298] cmd/compile: do not add invalid key to constSet After CL 272654, the compiler now use go/constant.Value to represent constant nodes. That makes ir.ConstantValue requires node type to correctly return value for untyped int node. But untyped int node can have nil type after typechecked, e.g: using int value as key for map[string]int, that makes the compiler crashes. To fix it, just don't add the invalid key to constSet, since when it's not important to report duplicated keys when they aren't valid. For #43311 Fixes #44432 Change-Id: I44d8f2b95f5cb339e77e8a705a94bcb16e62beb9 Reviewed-on: https://go-review.googlesource.com/c/go/+/294034 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/const.go | 2 +- test/fixedbugs/issue44432.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue44432.go diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index c60d36ba62..9b3a27b2d8 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -794,7 +794,7 @@ func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) { } } - if !ir.IsConstNode(n) { + if !ir.IsConstNode(n) || n.Type() == nil { return } if n.Type().IsUntyped() { diff --git a/test/fixedbugs/issue44432.go b/test/fixedbugs/issue44432.go new file mode 100644 index 0000000000..c5fb67e0d7 --- /dev/null +++ b/test/fixedbugs/issue44432.go @@ -0,0 +1,13 @@ +// errorcheck -G=0 -d=panic + +// Copyright 2021 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 p + +var m = map[string]int{ + "a": 1, + 1: 1, // ERROR "cannot use 1.*as type string in map key" + 2: 2, // ERROR "cannot use 2.*as type string in map key" +} -- GitLab From 868a110c568591d9085996ba05c94593809a437a Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 21 Feb 2021 22:27:19 +0700 Subject: [PATCH 0182/1298] cmd/compile: make check2 gracefully exit if it reported errors Otherwise, if -d=panic was set, check2 will treat already reported error as internal compiler error. For #43311 Fixes #44445 Change-Id: I5dbe06334666df21d9107396b9dcfdd905aa1e44 Reviewed-on: https://go-review.googlesource.com/c/go/+/294850 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/irgen.go | 2 +- test/fixedbugs/bug188.go | 8 ++++---- test/fixedbugs/bug358.go | 2 +- test/fixedbugs/bug397.go | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 28536cc1f7..da5b024b1a 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -68,10 +68,10 @@ func check2(noders []*noder) { } pkg, err := conf.Check(base.Ctxt.Pkgpath, files, &info) files = nil + base.ExitIfErrors() if err != nil { base.FatalfAt(src.NoXPos, "conf.Check error: %v", err) } - base.ExitIfErrors() if base.Flag.G < 2 { os.Exit(0) } diff --git a/test/fixedbugs/bug188.go b/test/fixedbugs/bug188.go index 5506147894..8195e3666d 100644 --- a/test/fixedbugs/bug188.go +++ b/test/fixedbugs/bug188.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -9,7 +9,7 @@ package main import "sort" func main() { - sort.Sort(nil); - var x int; - sort(x); // ERROR "package" + sort.Sort(nil) + var x int + sort(x) // ERROR "package" } diff --git a/test/fixedbugs/bug358.go b/test/fixedbugs/bug358.go index 5ca0be1f6e..541051cdd3 100644 --- a/test/fixedbugs/bug358.go +++ b/test/fixedbugs/bug358.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/bug397.go b/test/fixedbugs/bug397.go index db8d652814..bf3a5fffc8 100644 --- a/test/fixedbugs/bug397.go +++ b/test/fixedbugs/bug397.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -7,7 +7,7 @@ package main // Issue 2623 -var m = map[string]int { - "abc":1, - 1:2, // ERROR "cannot use 1.*as type string in map key|incompatible type|cannot convert" +var m = map[string]int{ + "abc": 1, + 1: 2, // ERROR "cannot use 1.*as type string in map key|incompatible type|cannot convert" } -- GitLab From a2d92b5143ad6ed1b55b71032c5c1f468ba76fd4 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 19 Feb 2021 17:11:40 -0500 Subject: [PATCH 0183/1298] cmd/compile: register abi, morestack work and mole whacking Morestack works for non-pointer register parameters Within a function body, pointer-typed parameters are correctly tracked. Results still not hooked up. For #40724. Change-Id: Icaee0b51d0da54af983662d945d939b756088746 Reviewed-on: https://go-review.googlesource.com/c/go/+/294410 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 4 ++ src/cmd/compile/internal/amd64/ssa.go | 11 +++++ src/cmd/compile/internal/ssa/debug.go | 4 +- src/cmd/compile/internal/ssa/stackalloc.go | 41 +++++++++------- src/cmd/compile/internal/ssagen/ssa.go | 48 +++++++++++++++++-- src/cmd/internal/obj/link.go | 23 ++++++--- src/cmd/internal/obj/x86/obj6.go | 55 ++++++++++++++-------- test/abi/f_ret_z_not.go | 14 +++--- test/abi/many_int_input.go | 30 ++++++++++++ test/abi/many_int_input.out | 1 + test/abi/regabipragma.go | 1 + 11 files changed, 175 insertions(+), 57 deletions(-) create mode 100644 test/abi/many_int_input.go create mode 100644 test/abi/many_int_input.out diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 3eab4b8d8b..f84f8f8e01 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -5,6 +5,7 @@ package abi import ( + "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/src" "fmt" @@ -337,6 +338,9 @@ func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field if fOffset == types.BOGUS_FUNARG_OFFSET { // Set the Offset the first time. After that, we may recompute it, but it should never change. f.Offset = off + if f.Nname != nil { + f.Nname.(*ir.Name).SetFrameOffset(off) + } } else if fOffset != off { panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off)) } diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index d83d78f080..60baa4270f 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -980,6 +980,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() + case ssa.OpArgIntReg, ssa.OpArgFloatReg: + // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill + // The loop only runs once. + for _, ap := range v.Block.Func.RegArgs { + // Pass the spill/unspill information along to the assembler, offset by size of return PC pushed on stack. + addr := ssagen.SpillSlotAddr(ap.Mem(), x86.REG_SP, v.Block.Func.Config.PtrSize) + s.FuncInfo().AddSpill( + obj.RegSpill{Reg: ap.Reg(), Addr: addr, Unspill: loadByType(ap.Type()), Spill: storeByType(ap.Type())}) + } + v.Block.Func.RegArgs = nil + ssagen.CheckArgReg(v) case ssa.OpAMD64LoweredGetClosurePtr: // Closure pointer is DX. ssagen.CheckLoweredGetClosurePtr(v) diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index 68b6ab5fe9..d725fc526e 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -901,10 +901,10 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { if opcodeTable[v.Op].zeroWidth { if changed { - if v.Op == OpArg || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() { + if hasAnyArgOp(v) || v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() { // These ranges begin at true beginning of block, not after first instruction if zeroWidthPending { - b.Func.Fatalf("Unexpected op mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", b, b.Func.Name, b.Func) + panic(fmt.Errorf("Unexpected op '%s' mixed with OpArg/OpPhi/OpLoweredGetClosurePtr at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func)) } apcChangedSize = len(state.changedVars.contents()) continue diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 041e7855f6..45058d4e72 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -112,7 +112,7 @@ func (s *stackAllocState) init(f *Func, spillLive [][]ID) { for _, v := range b.Values { s.values[v.ID].typ = v.Type s.values[v.ID].needSlot = !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && f.getHome(v.ID) == nil && !v.rematerializeable() && !v.OnWasmStack - s.values[v.ID].isArg = v.Op == OpArg + s.values[v.ID].isArg = hasAnyArgOp(v) if f.pass.debug > stackDebug && s.values[v.ID].needSlot { fmt.Printf("%s needs a stack slot\n", v) } @@ -151,28 +151,29 @@ func (s *stackAllocState) stackalloc() { // Allocate args to their assigned locations. for _, v := range f.Entry.Values { - if v.Op != OpArg { // && v.Op != OpArgFReg && v.Op != OpArgIReg { + if !hasAnyArgOp(v) { continue } if v.Aux == nil { f.Fatalf("%s has nil Aux\n", v.LongString()) } - var loc LocalSlot - var name *ir.Name - var offset int64 if v.Op == OpArg { - name = v.Aux.(*ir.Name) - offset = v.AuxInt - } else { - nameOff := v.Aux.(*AuxNameOffset) - name = nameOff.Name - offset = nameOff.Offset + loc := LocalSlot{N: v.Aux.(*ir.Name), Type: v.Type, Off: v.AuxInt} + if f.pass.debug > stackDebug { + fmt.Printf("stackalloc OpArg %s to %s\n", v, loc) + } + f.setHome(v, loc) + continue } - loc = LocalSlot{N: name, Type: v.Type, Off: offset} + + nameOff := v.Aux.(*AuxNameOffset) + loc := LocalSlot{N: nameOff.Name, Type: v.Type, Off: nameOff.Offset} if f.pass.debug > stackDebug { - fmt.Printf("stackalloc %s to %s\n", v, loc) + fmt.Printf("stackalloc Op%s %s to %s\n", v.Op, v, loc) } - f.setHome(v, loc) + // register args already allocated to registers, but need to know the stack allocation for later + reg := f.getHome(v.ID).(*Register) + f.RegArgs = append(f.RegArgs, ArgPair{reg: reg, mem: loc}) } // For each type, we keep track of all the stack slots we @@ -209,7 +210,7 @@ func (s *stackAllocState) stackalloc() { s.nNotNeed++ continue } - if v.Op == OpArg { + if hasAnyArgOp(v) { s.nArgSlot++ continue // already picked } @@ -396,7 +397,7 @@ func (s *stackAllocState) buildInterferenceGraph() { for _, id := range live.contents() { // Note: args can have different types and still interfere // (with each other or with other values). See issue 23522. - if s.values[v.ID].typ.Compare(s.values[id].typ) == types.CMPeq || v.Op == OpArg || s.values[id].isArg { + if s.values[v.ID].typ.Compare(s.values[id].typ) == types.CMPeq || hasAnyArgOp(v) || s.values[id].isArg { s.interfere[v.ID] = append(s.interfere[v.ID], id) s.interfere[id] = append(s.interfere[id], v.ID) } @@ -407,13 +408,15 @@ func (s *stackAllocState) buildInterferenceGraph() { live.add(a.ID) } } - if v.Op == OpArg && s.values[v.ID].needSlot { + if hasAnyArgOp(v) && s.values[v.ID].needSlot { // OpArg is an input argument which is pre-spilled. // We add back v.ID here because we want this value // to appear live even before this point. Being live // all the way to the start of the entry block prevents other // values from being allocated to the same slot and clobbering // the input value before we have a chance to load it. + + // TODO(register args) this is apparently not wrong for register args -- is it necessary? live.add(v.ID) } } @@ -430,3 +433,7 @@ func (s *stackAllocState) buildInterferenceGraph() { } } } + +func hasAnyArgOp(v *Value) bool { + return v.Op == OpArg || v.Op == OpArgIntReg || v.Op == OpArgFloatReg +} diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 05dd0c62a9..9ee855343f 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -221,7 +221,7 @@ func AbiForFunc(fn *ir.Func) *abi.ABIConfig { // Passing a nil function returns ABIInternal. func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { a := abi1 - if true || objabi.Regabi_enabled == 0 { + if !regabiEnabledForAllCompilation() { a = abi0 } if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working @@ -235,6 +235,11 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { return a } +func regabiEnabledForAllCompilation() bool { + // TODO compiler does not yet change behavior for GOEXPERIMENT=regabi + return false && objabi.Regabi_enabled != 0 +} + // getParam returns the Field of ith param of node n (which is a // function/method/interface call), where the receiver of a method call is // considered as the 0th parameter. This does not include the receiver of an @@ -6404,6 +6409,10 @@ type State struct { OnWasmStackSkipped int } +func (s *State) FuncInfo() *obj.FuncInfo { + return s.pp.CurFunc.LSym.Func() +} + // Prog appends a new Prog. func (s *State) Prog(as obj.As) *obj.Prog { p := s.pp.Prog(as) @@ -6561,11 +6570,9 @@ func genssa(f *ssa.Func, pp *objw.Progs) { // memory arg needs no code case ssa.OpArg: // input args need no code - case ssa.OpArgIntReg, ssa.OpArgFloatReg: - CheckArgReg(v) case ssa.OpSP, ssa.OpSB: // nothing to do - case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN: + case ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult: // nothing to do case ssa.OpGetG: // nothing to do when there's a g register, @@ -7470,6 +7477,39 @@ func deferstruct(stksize int64) *types.Type { return s } +// SlotAddr uses LocalSlot information to initialize an obj.Addr +// The resulting addr is used in a non-standard context -- in the prologue +// of a function, before the frame has been constructed, so the standard +// addressing for the parameters will be wrong. +func SpillSlotAddr(slot *ssa.LocalSlot, baseReg int16, extraOffset int64) obj.Addr { + n, off := slot.N, slot.Off + if n.Class != ir.PPARAM && n.Class != ir.PPARAMOUT { + panic("Only expected to see param and returns here") + } + return obj.Addr{ + Name: obj.NAME_NONE, + Type: obj.TYPE_MEM, + Reg: baseReg, + Offset: off + extraOffset + n.FrameOffset(), + } +} + +// AddrForParamSlot fills in an Addr appropriately for a Spill, +// Restore, or VARLIVE. +func AddrForParamSlot(slot *ssa.LocalSlot, addr *obj.Addr) { + // TODO replace this boilerplate in a couple of places. + n, off := slot.N, slot.Off + addr.Type = obj.TYPE_MEM + addr.Sym = n.Linksym() + addr.Offset = off + if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT { + addr.Name = obj.NAME_PARAM + addr.Offset += n.FrameOffset() + } else { + addr.Name = obj.NAME_AUTO + } +} + var ( BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index c74de779d2..448f45b47b 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -473,6 +473,7 @@ type FuncInfo struct { Autot map[*LSym]struct{} Pcln Pcln InlMarks []InlMark + spills []RegSpill dwarfInfoSym *LSym dwarfLocSym *LSym @@ -552,6 +553,11 @@ func (fi *FuncInfo) AddInlMark(p *Prog, id int32) { fi.InlMarks = append(fi.InlMarks, InlMark{p: p, id: id}) } +// AddSpill appends a spill record to the list for FuncInfo fi +func (fi *FuncInfo) AddSpill(s RegSpill) { + fi.spills = append(fi.spills, s) +} + // Record the type symbol for an auto variable so that the linker // an emit DWARF type information for the type. func (fi *FuncInfo) RecordAutoType(gotype *LSym) { @@ -803,12 +809,12 @@ type Auto struct { Gotype *LSym } -// RegArg provides spill/fill information for a register-resident argument +// RegSpill provides spill/fill information for a register-resident argument // to a function. These need spilling/filling in the safepoint/stackgrowth case. // At the time of fill/spill, the offset must be adjusted by the architecture-dependent // adjustment to hardware SP that occurs in a call instruction. E.g., for AMD64, // at Offset+8 because the return address was pushed. -type RegArg struct { +type RegSpill struct { Addr Addr Reg int16 Spill, Unspill As @@ -844,7 +850,6 @@ type Link struct { DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node GenAbstractFunc func(fn *LSym) Errors int - RegArgs []RegArg InParallel bool // parallel backend phase in effect UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges @@ -893,9 +898,11 @@ func (ctxt *Link) Logf(format string, args ...interface{}) { ctxt.Bso.Flush() } -func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { +// SpillRegisterArgs emits the code to spill register args into whatever +// locations the spill records specify. +func (fi *FuncInfo) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { // Spill register args. - for _, ra := range ctxt.RegArgs { + for _, ra := range fi.spills { spill := Appendp(last, pa) spill.As = ra.Spill spill.From.Type = TYPE_REG @@ -906,9 +913,11 @@ func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { return last } -func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { +// UnspillRegisterArgs emits the code to restore register args from whatever +// locations the spill records specify. +func (fi *FuncInfo) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { // Unspill any spilled register args - for _, ra := range ctxt.RegArgs { + for _, ra := range fi.spills { unspill := Appendp(last, pa) unspill.As = ra.Unspill unspill.From = ra.Addr diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index bc3a3b4bbe..d70cbebc5e 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -135,7 +135,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { p.To.Index = REG_NONE } } else { - // load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it + // load_g, below, always inserts the 1-instruction sequence. Rewrite it // as the 2-instruction sequence if necessary. // MOVQ 0(TLS), BX // becomes @@ -644,8 +644,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { regg = REGG // use the g register directly in ABIInternal } else { p = obj.Appendp(p, newprog) - p = load_g_cx(ctxt, p, newprog) // load g into CX regg = REG_CX + if ctxt.Arch.Family == sys.AMD64 { + // Using this register means that stacksplit works w/ //go:registerparams even when objabi.Regabi_enabled == 0 + regg = REGG // == REG_R14 + } + p = load_g(ctxt, p, newprog, regg) // load g into regg } } @@ -963,7 +967,7 @@ func indir_cx(ctxt *obj.Link, a *obj.Addr) { // Overwriting p is unusual but it lets use this in both the // prologue (caller must call appendp first) and in the epilogue. // Returns last new instruction. -func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog { +func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.Prog { p.As = AMOVQ if ctxt.Arch.PtrSize == 4 { p.As = AMOVL @@ -972,7 +976,7 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog { p.From.Reg = REG_TLS p.From.Offset = 0 p.To.Type = obj.TYPE_REG - p.To.Reg = REG_CX + p.To.Reg = rg next := p.Link progedit(ctxt, p, newprog) @@ -1027,9 +1031,14 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA // unnecessarily. See issue #35470. p = ctxt.StartUnsafePoint(p, newprog) } else if framesize <= objabi.StackBig { + tmp := int16(REG_AX) // use AX for 32-bit + if ctxt.Arch.Family == sys.AMD64 { + // for 64-bit, stay away from register ABI parameter registers, even w/o GOEXPERIMENT=regabi + tmp = int16(REG_R13) + } // large stack: SP-framesize <= stackguard-StackSmall - // LEAQ -xxx(SP), AX - // CMPQ AX, stackguard + // LEAQ -xxx(SP), tmp + // CMPQ tmp, stackguard p = obj.Appendp(p, newprog) p.As = lea @@ -1037,12 +1046,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p.From.Reg = REG_SP p.From.Offset = -(int64(framesize) - objabi.StackSmall) p.To.Type = obj.TYPE_REG - p.To.Reg = REG_AX + p.To.Reg = tmp p = obj.Appendp(p, newprog) p.As = cmp p.From.Type = obj.TYPE_REG - p.From.Reg = REG_AX + p.From.Reg = tmp p.To.Type = obj.TYPE_MEM p.To.Reg = rg p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 @@ -1052,6 +1061,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p = ctxt.StartUnsafePoint(p, newprog) // see the comment above } else { + tmp1 := int16(REG_SI) + tmp2 := int16(REG_AX) + if ctxt.Arch.Family == sys.AMD64 { + tmp1 = int16(REG_R13) // register ABI uses REG_SI and REG_AX for parameters. + tmp2 = int16(REG_R12) + } // Such a large stack we need to protect against wraparound. // If SP is close to zero: // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) @@ -1060,12 +1075,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA // // Preemption sets stackguard to StackPreempt, a very large value. // That breaks the math above, so we have to check for that explicitly. - // MOVQ stackguard, SI + // MOVQ stackguard, tmp1 // CMPQ SI, $StackPreempt // JEQ label-of-call-to-morestack - // LEAQ StackGuard(SP), AX - // SUBQ SI, AX - // CMPQ AX, $(framesize+(StackGuard-StackSmall)) + // LEAQ StackGuard(SP), tmp2 + // SUBQ tmp1, tmp2 + // CMPQ tmp2, $(framesize+(StackGuard-StackSmall)) p = obj.Appendp(p, newprog) @@ -1077,14 +1092,14 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 } p.To.Type = obj.TYPE_REG - p.To.Reg = REG_SI + p.To.Reg = tmp1 p = ctxt.StartUnsafePoint(p, newprog) // see the comment above p = obj.Appendp(p, newprog) p.As = cmp p.From.Type = obj.TYPE_REG - p.From.Reg = REG_SI + p.From.Reg = tmp1 p.To.Type = obj.TYPE_CONST p.To.Offset = objabi.StackPreempt if ctxt.Arch.Family == sys.I386 { @@ -1102,19 +1117,19 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p.From.Reg = REG_SP p.From.Offset = int64(objabi.StackGuard) p.To.Type = obj.TYPE_REG - p.To.Reg = REG_AX + p.To.Reg = tmp2 p = obj.Appendp(p, newprog) p.As = sub p.From.Type = obj.TYPE_REG - p.From.Reg = REG_SI + p.From.Reg = tmp1 p.To.Type = obj.TYPE_REG - p.To.Reg = REG_AX + p.To.Reg = tmp2 p = obj.Appendp(p, newprog) p.As = cmp p.From.Type = obj.TYPE_REG - p.From.Reg = REG_AX + p.From.Reg = tmp2 p.To.Type = obj.TYPE_CONST p.To.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall) } @@ -1139,7 +1154,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog) spill := ctxt.StartUnsafePoint(pcdata, newprog) - pcdata = ctxt.SpillRegisterArgs(spill, newprog) + pcdata = cursym.Func().SpillRegisterArgs(spill, newprog) call := obj.Appendp(pcdata, newprog) call.Pos = cursym.Func().Text.Pos @@ -1164,7 +1179,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA progedit(ctxt, callend.Link, newprog) } - pcdata = ctxt.UnspillRegisterArgs(callend, newprog) + pcdata = cursym.Func().UnspillRegisterArgs(callend, newprog) pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1) jmp := obj.Appendp(pcdata, newprog) diff --git a/test/abi/f_ret_z_not.go b/test/abi/f_ret_z_not.go index b072aea75e..d890223ff7 100644 --- a/test/abi/f_ret_z_not.go +++ b/test/abi/f_ret_z_not.go @@ -16,18 +16,18 @@ type NZ struct { } //go:noinline -func f(x,y int) (Z,NZ,Z) { +func f(x, y int) (Z, NZ, Z) { var z Z - return z,NZ{x,y},z + return z, NZ{x, y}, z } //go:noinline -func g() (Z,NZ,Z) { - a,b,c := f(3,4) - return c,b,a +func g() (Z, NZ, Z) { + a, b, c := f(3, 4) + return c, b, a } func main() { - _,b,_ := g() - fmt.Println(b.x+b.y) + _, b, _ := g() + fmt.Println(b.x + b.y) } diff --git a/test/abi/many_int_input.go b/test/abi/many_int_input.go new file mode 100644 index 0000000000..6c3332f842 --- /dev/null +++ b/test/abi/many_int_input.go @@ -0,0 +1,30 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 ( + "fmt" +) + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) { + G(z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a) +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) { + fmt.Println(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) +} + +func main() { + F(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26) +} diff --git a/test/abi/many_int_input.out b/test/abi/many_int_input.out new file mode 100644 index 0000000000..fecfa82581 --- /dev/null +++ b/test/abi/many_int_input.out @@ -0,0 +1 @@ +26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 diff --git a/test/abi/regabipragma.go b/test/abi/regabipragma.go index 86f42f9779..070b3110d6 100644 --- a/test/abi/regabipragma.go +++ b/test/abi/regabipragma.go @@ -1,5 +1,6 @@ // skip // runindir -gcflags=-c=1 +//go:build !windows // +build !windows // Copyright 2021 The Go Authors. All rights reserved. -- GitLab From 3778f8e07d06cabfccd1508295ad67270af078cd Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 19 Feb 2021 18:00:48 -0500 Subject: [PATCH 0184/1298] cmd/compile: fix pointer maps for morestack Verified with test and with single step watching changes to register values across morestack calls, after reload. Also added stack-growth test with pointer parameters of varying lifetime. For #40724. Change-Id: Idb5fe27786ac5c6665a734d41e68d3d39de2f4da Reviewed-on: https://go-review.googlesource.com/c/go/+/294429 Trust: David Chase Reviewed-by: Cherry Zhang Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/liveness/plive.go | 16 +++++ src/cmd/compile/internal/ssa/value.go | 12 ++-- test/abi/uglyfib.go | 79 ++++++++++++++++++++++ test/abi/uglyfib.out | 1 + 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 test/abi/uglyfib.go create mode 100644 test/abi/uglyfib.out diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go index 53ae797fce..48a26cf66a 100644 --- a/src/cmd/compile/internal/liveness/plive.go +++ b/src/cmd/compile/internal/liveness/plive.go @@ -297,6 +297,22 @@ func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) { n, _ := ssa.AutoVar(v) return n, ssa.SymWrite + case ssa.OpArgIntReg: + // This forces the spill slot for the register to be live at function entry. + // one of the following holds for a function F with pointer-valued register arg X: + // 0. No GC (so an uninitialized spill slot is okay) + // 1. GC at entry of F. GC is precise, but the spills around morestack initialize X's spill slot + // 2. Stack growth at entry of F. Same as GC. + // 3. GC occurs within F itself. This has to be from preemption, and thus GC is conservative. + // a. X is in a register -- then X is seen, and the spill slot is also scanned conservatively. + // b. X is spilled -- the spill slot is initialized, and scanned conservatively + // c. X is not live -- the spill slot is scanned conservatively, and it may contain X from an earlier spill. + // 4. GC within G, transitively called from F + // a. X is live at call site, therefore is spilled, to its spill slot (which is live because of subsequent LoadReg). + // b. X is not live at call site -- but neither is its spill slot. + n, _ := ssa.AutoVar(v) + return n, ssa.SymRead + case ssa.OpVarLive: return v.Aux.(*ir.Name), ssa.SymRead case ssa.OpVarDef, ssa.OpVarKill: diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 127e4ce641..c20fc87e90 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -517,9 +517,13 @@ func (*Value) CanBeAnSSAAux() {} // AutoVar returns a *Name and int64 representing the auto variable and offset within it // where v should be spilled. func AutoVar(v *Value) (*ir.Name, int64) { - loc := v.Block.Func.RegAlloc[v.ID].(LocalSlot) - if v.Type.Size() > loc.Type.Size() { - v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type) + if loc, ok := v.Block.Func.RegAlloc[v.ID].(LocalSlot); ok { + if v.Type.Size() > loc.Type.Size() { + v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type) + } + return loc.N, loc.Off } - return loc.N, loc.Off + // Assume it is a register, return its spill slot, which needs to be live + nameOff := v.Aux.(*AuxNameOffset) + return nameOff.Name, nameOff.Offset } diff --git a/test/abi/uglyfib.go b/test/abi/uglyfib.go new file mode 100644 index 0000000000..bde3548bee --- /dev/null +++ b/test/abi/uglyfib.go @@ -0,0 +1,79 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 "fmt" + +// This test is designed to provoke a stack growth +// in a way that very likely leaves junk in the +// parameter save area if they aren't saved or spilled +// there, as appropriate. + +//go:registerparams +//go:noinline +func f(x int, xm1, xm2, p *int) { + var y = [2]int{x - 4, 0} + if x < 2 { + *p += x + return + } + x -= 3 + g(*xm1, xm2, &x, p) // xm1 is no longer live. + h(*xm2, &x, &y[0], p) // xm2 is no longer live, but was spilled. +} + +//go:registerparams +//go:noinline +func g(x int, xm1, xm2, p *int) { + var y = [3]int{x - 4, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + k(*xm2, &x, &y[0], p) + h(*xm1, xm2, &x, p) +} + +//go:registerparams +//go:noinline +func h(x int, xm1, xm2, p *int) { + var y = [4]int{x - 4, 0, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + k(*xm1, xm2, &x, p) + f(*xm2, &x, &y[0], p) +} + +//go:registerparams +//go:noinline +func k(x int, xm1, xm2, p *int) { + var y = [5]int{x - 4, 0, 0, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + f(*xm2, &x, &y[0], p) + g(*xm1, xm2, &x, p) +} + +func main() { + x := 40 + var y int + xm1 := x - 1 + xm2 := x - 2 + f(x, &xm1, &xm2, &y) + + fmt.Printf("Fib(%d)=%d\n", x, y) +} diff --git a/test/abi/uglyfib.out b/test/abi/uglyfib.out new file mode 100644 index 0000000000..d892270e20 --- /dev/null +++ b/test/abi/uglyfib.out @@ -0,0 +1 @@ +Fib(40)=102334155 -- GitLab From a416efef5a278c9c8c5e133bbec5c2c1d0df9491 Mon Sep 17 00:00:00 2001 From: Tao Qingyun Date: Sat, 7 Nov 2020 02:43:27 +0000 Subject: [PATCH 0185/1298] =?UTF-8?q?runtime:=20remove=20a=20duplicated=20?= =?UTF-8?q?testcase=20of=20TestPallocDataFindScavengeCa=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib44729ffb5d4d7b84114dcf028b7e0418c9d5035 GitHub-Last-Rev: 13f59a650aa424b4852ee4a803eebc793dbbfc15 GitHub-Pull-Request: golang/go#42434 Reviewed-on: https://go-review.googlesource.com/c/go/+/268021 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Michael Pratt Trust: Martin Möhrmann --- src/runtime/mgcscavenge_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/runtime/mgcscavenge_test.go b/src/runtime/mgcscavenge_test.go index 250343077f..3b12a2e1e6 100644 --- a/src/runtime/mgcscavenge_test.go +++ b/src/runtime/mgcscavenge_test.go @@ -152,12 +152,6 @@ func TestPallocDataFindScavengeCandidate(t *testing.T) { max: PallocChunkPages, want: BitRange{0, uint(m)}, } - tests["StartFree"+suffix] = test{ - alloc: []BitRange{{uint(m), PallocChunkPages - uint(m)}}, - min: m, - max: PallocChunkPages, - want: BitRange{0, uint(m)}, - } tests["EndFree"+suffix] = test{ alloc: []BitRange{{0, PallocChunkPages - uint(m)}}, min: m, -- GitLab From 9a40dee3ee9c69e8bb4952f9e14b1817195d1f3d Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 4 Mar 2021 10:39:32 -0500 Subject: [PATCH 0186/1298] cmd/go: reject 'go list -m MOD@patch' when no existing version of MOD is required Noticed while debugging failing tests for #36460. Fixes #44788 Change-Id: Ic2cf511d871b29284f7372920f6f7d452825dd63 Reviewed-on: https://go-review.googlesource.com/c/go/+/298651 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/internal/modload/list.go | 2 +- src/cmd/go/internal/modload/query.go | 2 +- src/cmd/go/internal/modload/query_test.go | 2 +- src/cmd/go/testdata/script/mod_prefer_compatible.txt | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go index de16c2f786..6dba6bea22 100644 --- a/src/cmd/go/internal/modload/list.go +++ b/src/cmd/go/internal/modload/list.go @@ -78,7 +78,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted if i := strings.Index(arg, "@"); i >= 0 { path := arg[:i] vers := arg[i+1:] - var current string + current := "none" for _, m := range buildList { if m.Path == path { current = m.Version diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 8affd179bb..a8012c792a 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -330,7 +330,7 @@ func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (* } case query == "patch": - if current == "none" { + if current == "" || current == "none" { return nil, &NoPatchBaseError{path} } if current == "" { diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go index e225a0e71e..6e39df45a7 100644 --- a/src/cmd/go/internal/modload/query_test.go +++ b/src/cmd/go/internal/modload/query_test.go @@ -122,7 +122,7 @@ var queryTests = []struct { {path: queryRepo, query: "upgrade", allow: "NOMATCH", err: `no matching versions for query "upgrade"`}, {path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `vcs-test.golang.org/git/querytest.git@v1.9.9: disallowed module version`}, {path: queryRepo, query: "upgrade", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`}, - {path: queryRepo, query: "patch", current: "", vers: "v1.9.9"}, + {path: queryRepo, query: "patch", current: "", err: `can't query version "patch" of module vcs-test.golang.org/git/querytest.git: no existing version is required`}, {path: queryRepo, query: "patch", current: "v0.1.0", vers: "v0.1.2"}, {path: queryRepo, query: "patch", current: "v1.9.0", vers: "v1.9.9"}, {path: queryRepo, query: "patch", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"}, diff --git a/src/cmd/go/testdata/script/mod_prefer_compatible.txt b/src/cmd/go/testdata/script/mod_prefer_compatible.txt index aa6260f63c..1b408c3e9e 100644 --- a/src/cmd/go/testdata/script/mod_prefer_compatible.txt +++ b/src/cmd/go/testdata/script/mod_prefer_compatible.txt @@ -23,8 +23,8 @@ stdout '^github.com/russross/blackfriday v1\.' go list -m github.com/russross/blackfriday@upgrade stdout '^github.com/russross/blackfriday v1\.' -go list -m github.com/russross/blackfriday@patch -stdout '^github.com/russross/blackfriday v1\.' +! go list -m github.com/russross/blackfriday@patch +stderr '^go list -m: github.com/russross/blackfriday@patch: can''t query version "patch" of module github.com/russross/blackfriday: no existing version is required$' # If we're fetching directly from version control, ignored +incompatible # versions should also be omitted by 'go list'. -- GitLab From 9c54f878d26e106f8e375c31aabceb1e36ff4050 Mon Sep 17 00:00:00 2001 From: LeonardWang Date: Thu, 7 Jan 2021 00:36:34 +0800 Subject: [PATCH 0187/1298] runtime: remove GODEBUG=scavenge mode Change-Id: Ic4c7b5086303c7faa49f4cbf6738e66d5de35c7e Reviewed-on: https://go-review.googlesource.com/c/go/+/282012 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/runtime/extern.go | 2 -- src/runtime/runtime1.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/runtime/extern.go b/src/runtime/extern.go index bbe41dd0d4..b73d68428f 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -110,8 +110,6 @@ It is a comma-separated list of name=val pairs setting these named variables: with a trivial allocator that obtains memory from the operating system and never reclaims any memory. - scavenge: scavenge=1 enables debugging mode of heap scavenger. - scavtrace: setting scavtrace=1 causes the runtime to emit a single line to standard error, roughly once per GC cycle, summarizing the amount of work done by the scavenger as well as the total amount of memory returned to the operating system diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 30b7044bff..b238da8f51 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -310,7 +310,6 @@ var debug struct { gctrace int32 invalidptr int32 madvdontneed int32 // for Linux; issue 28466 - scavenge int32 scavtrace int32 scheddetail int32 schedtrace int32 @@ -339,7 +338,6 @@ var dbgvars = []dbgVar{ {"invalidptr", &debug.invalidptr}, {"madvdontneed", &debug.madvdontneed}, {"sbrk", &debug.sbrk}, - {"scavenge", &debug.scavenge}, {"scavtrace", &debug.scavtrace}, {"scheddetail", &debug.scheddetail}, {"schedtrace", &debug.schedtrace}, -- GitLab From cfb609bfb70027e60d71a5ac7e9202144246b98a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 4 Feb 2021 22:46:23 -0500 Subject: [PATCH 0188/1298] cmd/go: ensure that the test subprocess always times out in TestScript/test_write_profiles_on_timeout This test verifies the behavior of a test that fails due to timing out. However, the test to be timed out was only sleeping for 1s before returning successfully. That is empirically not always long enough for the test process itself to detect the timeout and terminate. We could replace the sleep with a select{}, but that would assume that the deadlock detector does not terminate a test that reaches that state (true today, but not necessarily so). We could replace the arbitrarily sleep with an arbitrarily longer sleep, but that's, well, arbitrary. Instead, have the test sleep in an unbounded loop to ensure that it always continues to run until the timeout is detected, and check the test output to ensure that it actually reached the timeout path. Fixes #32983 Change-Id: Ie7f210b36ef0cc0a4db473f780e15a3d6def8bda Reviewed-on: https://go-review.googlesource.com/c/go/+/289889 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../script/test_write_profiles_on_timeout.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt index 08e67a429e..0db183f8f0 100644 --- a/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt +++ b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt @@ -3,6 +3,7 @@ [short] skip ! go test -cpuprofile cpu.pprof -memprofile mem.pprof -timeout 1ms +stdout '^panic: test timed out' grep . cpu.pprof grep . mem.pprof @@ -12,6 +13,14 @@ module profiling go 1.16 -- timeout_test.go -- package timeouttest_test -import "testing" -import "time" -func TestSleep(t *testing.T) { time.Sleep(time.Second) } + +import ( + "testing" + "time" +) + +func TestSleep(t *testing.T) { + for { + time.Sleep(1 * time.Second) + } +} -- GitLab From 2d30c94874c127d9028e29b77fadeb284c23e89a Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Tue, 3 Nov 2020 10:35:34 -0600 Subject: [PATCH 0189/1298] cmd/internal: Add 6 args to ppc64 optab This is a preparatory patch to support 6 arg opcodes on POWER10, and simplify 5 arg opcode processing (e.g RLWNM and similar). This expands the optab structure, and renames a4 arguments to a6. No actual change in functionality is made. Change-Id: I785e4177778e4bf1326cf8e46e8aeaaa0e4d406b Reviewed-on: https://go-review.googlesource.com/c/go/+/295031 Run-TryBot: Lynn Boger Run-TryBot: Carlos Eduardo Seo Reviewed-by: Lynn Boger Reviewed-by: Cherry Zhang Trust: Keith Randall --- src/cmd/internal/obj/ppc64/asm9.go | 915 +++++++++++++++-------------- 1 file changed, 465 insertions(+), 450 deletions(-) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 97b4cb2317..7985f050de 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -64,13 +64,15 @@ const ( type Optab struct { as obj.As // Opcode - a1 uint8 - a2 uint8 - a3 uint8 - a4 uint8 - type_ int8 // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r - size int8 - param int16 + a1 uint8 // p.From argument (obj.Addr). p is of type obj.Prog. + a2 uint8 // p.Reg argument (int16 Register) + a3 uint8 // p.RestArgs[0] (obj.AddrPos) + a4 uint8 // p.RestArgs[1] + a5 uint8 // p.RestARgs[2] + a6 uint8 // p.To (obj.Addr) + type_ int8 // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r + size int8 // Text space in bytes to lay operation + param int16 // Implied base register for pseudo-registers } // optab contains an array to be sliced of accepted operand combinations for an @@ -88,546 +90,546 @@ type Optab struct { // Likewise, each slice of optab is dynamically sorted using the ocmp Sort interface // to arrange entries to minimize text size of each opcode. var optab = []Optab{ - {as: obj.ATEXT, a1: C_LEXT, a4: C_TEXTSIZE, type_: 0, size: 0}, - {as: obj.ATEXT, a1: C_LEXT, a3: C_LCON, a4: C_TEXTSIZE, type_: 0, size: 0}, - {as: obj.ATEXT, a1: C_ADDR, a4: C_TEXTSIZE, type_: 0, size: 0}, - {as: obj.ATEXT, a1: C_ADDR, a3: C_LCON, a4: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_LEXT, a6: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_LEXT, a3: C_LCON, a6: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_ADDR, a6: C_TEXTSIZE, type_: 0, size: 0}, + {as: obj.ATEXT, a1: C_ADDR, a3: C_LCON, a6: C_TEXTSIZE, type_: 0, size: 0}, /* move register */ - {as: AMOVD, a1: C_REG, a4: C_REG, type_: 1, size: 4}, - {as: AMOVB, a1: C_REG, a4: C_REG, type_: 12, size: 4}, - {as: AMOVBZ, a1: C_REG, a4: C_REG, type_: 13, size: 4}, - {as: AMOVW, a1: C_REG, a4: C_REG, type_: 12, size: 4}, - {as: AMOVWZ, a1: C_REG, a4: C_REG, type_: 13, size: 4}, - {as: AADD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AADD, a1: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AADD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, - {as: AADD, a1: C_SCON, a4: C_REG, type_: 4, size: 4}, - {as: AADD, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, - {as: AADD, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, - {as: AADD, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 20, size: 4}, - {as: AADD, a1: C_UCON, a4: C_REG, type_: 20, size: 4}, - {as: AADD, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 22, size: 8}, - {as: AADD, a1: C_ANDCON, a4: C_REG, type_: 22, size: 8}, - {as: AADD, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, - {as: AADD, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, - {as: AADDIS, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 20, size: 4}, - {as: AADDIS, a1: C_ADDCON, a4: C_REG, type_: 20, size: 4}, - {as: AADDC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AADDC, a1: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AADDC, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, - {as: AADDC, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, - {as: AADDC, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, - {as: AADDC, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, - {as: AAND, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, /* logical, no literal */ - {as: AAND, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: AANDCC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: AANDCC, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: AANDCC, a1: C_ANDCON, a4: C_REG, type_: 58, size: 4}, - {as: AANDCC, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 58, size: 4}, - {as: AANDCC, a1: C_UCON, a4: C_REG, type_: 59, size: 4}, - {as: AANDCC, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, - {as: AANDCC, a1: C_ADDCON, a4: C_REG, type_: 23, size: 8}, - {as: AANDCC, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 23, size: 8}, - {as: AANDCC, a1: C_LCON, a4: C_REG, type_: 23, size: 12}, - {as: AANDCC, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 23, size: 12}, - {as: AANDISCC, a1: C_ANDCON, a4: C_REG, type_: 59, size: 4}, - {as: AANDISCC, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, - {as: AMULLW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AMULLW, a1: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: AMULLW, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, - {as: AMULLW, a1: C_ADDCON, a4: C_REG, type_: 4, size: 4}, - {as: AMULLW, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 4, size: 4}, - {as: AMULLW, a1: C_ANDCON, a4: C_REG, type_: 4, size: 4}, - {as: AMULLW, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 22, size: 12}, - {as: AMULLW, a1: C_LCON, a4: C_REG, type_: 22, size: 12}, - {as: ASUBC, a1: C_REG, a2: C_REG, a4: C_REG, type_: 10, size: 4}, - {as: ASUBC, a1: C_REG, a4: C_REG, type_: 10, size: 4}, - {as: ASUBC, a1: C_REG, a3: C_ADDCON, a4: C_REG, type_: 27, size: 4}, - {as: ASUBC, a1: C_REG, a3: C_LCON, a4: C_REG, type_: 28, size: 12}, - {as: AOR, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, /* logical, literal not cc (or/xor) */ - {as: AOR, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: AOR, a1: C_ANDCON, a4: C_REG, type_: 58, size: 4}, - {as: AOR, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 58, size: 4}, - {as: AOR, a1: C_UCON, a4: C_REG, type_: 59, size: 4}, - {as: AOR, a1: C_UCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, - {as: AOR, a1: C_ADDCON, a4: C_REG, type_: 23, size: 8}, - {as: AOR, a1: C_ADDCON, a2: C_REG, a4: C_REG, type_: 23, size: 8}, - {as: AOR, a1: C_LCON, a4: C_REG, type_: 23, size: 12}, - {as: AOR, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 23, size: 12}, - {as: AORIS, a1: C_ANDCON, a4: C_REG, type_: 59, size: 4}, - {as: AORIS, a1: C_ANDCON, a2: C_REG, a4: C_REG, type_: 59, size: 4}, - {as: ADIVW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 2, size: 4}, /* op r1[,r2],r3 */ - {as: ADIVW, a1: C_REG, a4: C_REG, type_: 2, size: 4}, - {as: ASUB, a1: C_REG, a2: C_REG, a4: C_REG, type_: 10, size: 4}, /* op r2[,r1],r3 */ - {as: ASUB, a1: C_REG, a4: C_REG, type_: 10, size: 4}, - {as: ASLW, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASLW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASLD, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASLD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASLD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 25, size: 4}, - {as: ASLD, a1: C_SCON, a4: C_REG, type_: 25, size: 4}, - {as: AEXTSWSLI, a1: C_SCON, a4: C_REG, type_: 25, size: 4}, - {as: AEXTSWSLI, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 25, size: 4}, - {as: ASLW, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 57, size: 4}, - {as: ASLW, a1: C_SCON, a4: C_REG, type_: 57, size: 4}, - {as: ASRAW, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASRAW, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASRAW, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 56, size: 4}, - {as: ASRAW, a1: C_SCON, a4: C_REG, type_: 56, size: 4}, - {as: ASRAD, a1: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASRAD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 6, size: 4}, - {as: ASRAD, a1: C_SCON, a2: C_REG, a4: C_REG, type_: 56, size: 4}, - {as: ASRAD, a1: C_SCON, a4: C_REG, type_: 56, size: 4}, - {as: ARLWMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 62, size: 4}, - {as: ARLWMI, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 63, size: 4}, - {as: ACLRLSLWI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 62, size: 4}, - {as: ARLDMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 30, size: 4}, - {as: ARLDC, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 29, size: 4}, - {as: ARLDCL, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 29, size: 4}, - {as: ARLDCL, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, - {as: ARLDICL, a1: C_REG, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, - {as: ARLDICL, a1: C_SCON, a2: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, - {as: ARLDCL, a1: C_REG, a3: C_LCON, a4: C_REG, type_: 14, size: 4}, - {as: AFADD, a1: C_FREG, a4: C_FREG, type_: 2, size: 4}, - {as: AFADD, a1: C_FREG, a2: C_FREG, a4: C_FREG, type_: 2, size: 4}, - {as: AFABS, a1: C_FREG, a4: C_FREG, type_: 33, size: 4}, - {as: AFABS, a4: C_FREG, type_: 33, size: 4}, - {as: AFMOVD, a1: C_FREG, a4: C_FREG, type_: 33, size: 4}, - {as: AFMADD, a1: C_FREG, a2: C_FREG, a3: C_FREG, a4: C_FREG, type_: 34, size: 4}, - {as: AFMUL, a1: C_FREG, a4: C_FREG, type_: 32, size: 4}, - {as: AFMUL, a1: C_FREG, a2: C_FREG, a4: C_FREG, type_: 32, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_REG, type_: 1, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_REG, type_: 12, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_REG, type_: 12, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, + {as: AADD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AADD, a1: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AADD, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_SCON, a6: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_ADDCON, a6: C_REG, type_: 4, size: 4}, + {as: AADD, a1: C_UCON, a2: C_REG, a6: C_REG, type_: 20, size: 4}, + {as: AADD, a1: C_UCON, a6: C_REG, type_: 20, size: 4}, + {as: AADD, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 22, size: 8}, + {as: AADD, a1: C_ANDCON, a6: C_REG, type_: 22, size: 8}, + {as: AADD, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 22, size: 12}, + {as: AADD, a1: C_LCON, a6: C_REG, type_: 22, size: 12}, + {as: AADDIS, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 20, size: 4}, + {as: AADDIS, a1: C_ADDCON, a6: C_REG, type_: 20, size: 4}, + {as: AADDC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AADDC, a1: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AADDC, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, + {as: AADDC, a1: C_ADDCON, a6: C_REG, type_: 4, size: 4}, + {as: AADDC, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 22, size: 12}, + {as: AADDC, a1: C_LCON, a6: C_REG, type_: 22, size: 12}, + {as: AAND, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, /* logical, no literal */ + {as: AAND, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: AANDCC, a1: C_ANDCON, a6: C_REG, type_: 58, size: 4}, + {as: AANDCC, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 58, size: 4}, + {as: AANDCC, a1: C_UCON, a6: C_REG, type_: 59, size: 4}, + {as: AANDCC, a1: C_UCON, a2: C_REG, a6: C_REG, type_: 59, size: 4}, + {as: AANDCC, a1: C_ADDCON, a6: C_REG, type_: 23, size: 8}, + {as: AANDCC, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 23, size: 8}, + {as: AANDCC, a1: C_LCON, a6: C_REG, type_: 23, size: 12}, + {as: AANDCC, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 23, size: 12}, + {as: AANDISCC, a1: C_ANDCON, a6: C_REG, type_: 59, size: 4}, + {as: AANDISCC, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 59, size: 4}, + {as: AMULLW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AMULLW, a1: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: AMULLW, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ADDCON, a6: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_ANDCON, a6: C_REG, type_: 4, size: 4}, + {as: AMULLW, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 22, size: 12}, + {as: AMULLW, a1: C_LCON, a6: C_REG, type_: 22, size: 12}, + {as: ASUBC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 10, size: 4}, + {as: ASUBC, a1: C_REG, a6: C_REG, type_: 10, size: 4}, + {as: ASUBC, a1: C_REG, a3: C_ADDCON, a6: C_REG, type_: 27, size: 4}, + {as: ASUBC, a1: C_REG, a3: C_LCON, a6: C_REG, type_: 28, size: 12}, + {as: AOR, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, /* logical, literal not cc (or/xor) */ + {as: AOR, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: AOR, a1: C_ANDCON, a6: C_REG, type_: 58, size: 4}, + {as: AOR, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 58, size: 4}, + {as: AOR, a1: C_UCON, a6: C_REG, type_: 59, size: 4}, + {as: AOR, a1: C_UCON, a2: C_REG, a6: C_REG, type_: 59, size: 4}, + {as: AOR, a1: C_ADDCON, a6: C_REG, type_: 23, size: 8}, + {as: AOR, a1: C_ADDCON, a2: C_REG, a6: C_REG, type_: 23, size: 8}, + {as: AOR, a1: C_LCON, a6: C_REG, type_: 23, size: 12}, + {as: AOR, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 23, size: 12}, + {as: AORIS, a1: C_ANDCON, a6: C_REG, type_: 59, size: 4}, + {as: AORIS, a1: C_ANDCON, a2: C_REG, a6: C_REG, type_: 59, size: 4}, + {as: ADIVW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, /* op r1[,r2],r3 */ + {as: ADIVW, a1: C_REG, a6: C_REG, type_: 2, size: 4}, + {as: ASUB, a1: C_REG, a2: C_REG, a6: C_REG, type_: 10, size: 4}, /* op r2[,r1],r3 */ + {as: ASUB, a1: C_REG, a6: C_REG, type_: 10, size: 4}, + {as: ASLW, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASLW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASLD, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 25, size: 4}, + {as: ASLD, a1: C_SCON, a6: C_REG, type_: 25, size: 4}, + {as: AEXTSWSLI, a1: C_SCON, a6: C_REG, type_: 25, size: 4}, + {as: AEXTSWSLI, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 25, size: 4}, + {as: ASLW, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 57, size: 4}, + {as: ASLW, a1: C_SCON, a6: C_REG, type_: 57, size: 4}, + {as: ASRAW, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASRAW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASRAW, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 56, size: 4}, + {as: ASRAW, a1: C_SCON, a6: C_REG, type_: 56, size: 4}, + {as: ASRAD, a1: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASRAD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, + {as: ASRAD, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 56, size: 4}, + {as: ASRAD, a1: C_SCON, a6: C_REG, type_: 56, size: 4}, + {as: ARLWMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 62, size: 4}, + {as: ARLWMI, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 63, size: 4}, + {as: ACLRLSLWI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 62, size: 4}, + {as: ARLDMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 30, size: 4}, + {as: ARLDC, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 29, size: 4}, + {as: ARLDCL, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 29, size: 4}, + {as: ARLDCL, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4}, + {as: ARLDICL, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4}, + {as: ARLDICL, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4}, + {as: ARLDCL, a1: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4}, + {as: AFADD, a1: C_FREG, a6: C_FREG, type_: 2, size: 4}, + {as: AFADD, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 2, size: 4}, + {as: AFABS, a1: C_FREG, a6: C_FREG, type_: 33, size: 4}, + {as: AFABS, a6: C_FREG, type_: 33, size: 4}, + {as: AFMOVD, a1: C_FREG, a6: C_FREG, type_: 33, size: 4}, + {as: AFMADD, a1: C_FREG, a2: C_FREG, a3: C_FREG, a6: C_FREG, type_: 34, size: 4}, + {as: AFMUL, a1: C_FREG, a6: C_FREG, type_: 32, size: 4}, + {as: AFMUL, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 32, size: 4}, /* store, short offset */ - {as: AMOVD, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBU, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVD, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVW, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVWZ, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVBZ, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVB, a1: C_REG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVD, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVW, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVBZ, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVB, a1: C_REG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVD, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBU, a1: C_REG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVW, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVWZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVBZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVB, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AMOVD, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVW, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVBZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVB, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVBU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, /* load, short offset */ - {as: AMOVD, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVD, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVW, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVWZ, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVBZ, a1: C_SEXT, a4: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVB, a1: C_SEXT, a4: C_REG, type_: 9, size: 8, param: REGSB}, - {as: AMOVD, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVW, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVBZ, a1: C_SAUTO, a4: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVB, a1: C_SAUTO, a4: C_REG, type_: 9, size: 8, param: REGSP}, - {as: AMOVD, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_SOREG, a4: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_SOREG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVBU, a1: C_SOREG, a4: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVW, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVWZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVBZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, + {as: AMOVB, a1: C_SEXT, a6: C_REG, type_: 9, size: 8, param: REGSB}, + {as: AMOVD, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVW, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVBZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, + {as: AMOVB, a1: C_SAUTO, a6: C_REG, type_: 9, size: 8, param: REGSP}, + {as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, + {as: AMOVB, a1: C_SOREG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, /* store, long offset */ - {as: AMOVD, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVW, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVBZ, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVB, a1: C_REG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVD, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVW, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVBZ, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVB, a1: C_REG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVD, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVW, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVB, a1: C_REG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVD, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, - {as: AMOVW, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, - {as: AMOVWZ, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, - {as: AMOVBZ, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, - {as: AMOVB, a1: C_REG, a4: C_ADDR, type_: 74, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVW, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVBZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVB, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AMOVD, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVW, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVBZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVB, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVWZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVBZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, /* load, long offset */ - {as: AMOVD, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVW, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVBZ, a1: C_LEXT, a4: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVB, a1: C_LEXT, a4: C_REG, type_: 37, size: 12, param: REGSB}, - {as: AMOVD, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVW, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVBZ, a1: C_LAUTO, a4: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVB, a1: C_LAUTO, a4: C_REG, type_: 37, size: 12, param: REGSP}, - {as: AMOVD, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVW, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVWZ, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVBZ, a1: C_LOREG, a4: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVB, a1: C_LOREG, a4: C_REG, type_: 37, size: 12, param: REGZERO}, - {as: AMOVD, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, - {as: AMOVW, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, - {as: AMOVWZ, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, - {as: AMOVBZ, a1: C_ADDR, a4: C_REG, type_: 75, size: 8}, - {as: AMOVB, a1: C_ADDR, a4: C_REG, type_: 76, size: 12}, - - {as: AMOVD, a1: C_TLS_LE, a4: C_REG, type_: 79, size: 4}, - {as: AMOVD, a1: C_TLS_IE, a4: C_REG, type_: 80, size: 8}, - - {as: AMOVD, a1: C_GOTADDR, a4: C_REG, type_: 81, size: 8}, - {as: AMOVD, a1: C_TOCADDR, a4: C_REG, type_: 95, size: 8}, + {as: AMOVD, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVW, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVBZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, + {as: AMOVB, a1: C_LEXT, a6: C_REG, type_: 37, size: 12, param: REGSB}, + {as: AMOVD, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVW, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVBZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, + {as: AMOVB, a1: C_LAUTO, a6: C_REG, type_: 37, size: 12, param: REGSP}, + {as: AMOVD, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVWZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, + {as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 37, size: 12, param: REGZERO}, + {as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVW, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVWZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVBZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVB, a1: C_ADDR, a6: C_REG, type_: 76, size: 12}, + + {as: AMOVD, a1: C_TLS_LE, a6: C_REG, type_: 79, size: 4}, + {as: AMOVD, a1: C_TLS_IE, a6: C_REG, type_: 80, size: 8}, + + {as: AMOVD, a1: C_GOTADDR, a6: C_REG, type_: 81, size: 8}, + {as: AMOVD, a1: C_TOCADDR, a6: C_REG, type_: 95, size: 8}, /* load constant */ - {as: AMOVD, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, - {as: AMOVD, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVD, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVD, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVD, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVD, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ - {as: AMOVW, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVW, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVW, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVW, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_SECON, a4: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ - {as: AMOVWZ, a1: C_SACON, a4: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_LECON, a4: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_LACON, a4: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_ADDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_ANDCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, + {as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVD, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVD, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ + {as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVW, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVW, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ + {as: AMOVWZ, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, + {as: AMOVWZ, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, + {as: AMOVWZ, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, + {as: AMOVWZ, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, /* load unsigned/long constants (TO DO: check) */ - {as: AMOVD, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVD, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, - {as: AMOVW, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, - {as: AMOVWZ, a1: C_UCON, a4: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_LCON, a4: C_REG, type_: 19, size: 8}, - {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 45, size: 4}, - {as: AMOVHBR, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, - {as: AMOVHBR, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, - {as: AMOVHBR, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, + {as: AMOVD, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, + {as: AMOVW, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, + {as: AMOVWZ, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, + {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 45, size: 4}, + {as: AMOVHBR, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, + {as: AMOVHBR, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AMOVHBR, a1: C_REG, a6: C_ZOREG, type_: 44, size: 4}, {as: ASYSCALL, type_: 5, size: 4}, {as: ASYSCALL, a1: C_REG, type_: 77, size: 12}, {as: ASYSCALL, a1: C_SCON, type_: 77, size: 12}, - {as: ABEQ, a4: C_SBRA, type_: 16, size: 4}, - {as: ABEQ, a1: C_CREG, a4: C_SBRA, type_: 16, size: 4}, - {as: ABR, a4: C_LBRA, type_: 11, size: 4}, - {as: ABR, a4: C_LBRAPIC, type_: 11, size: 8}, - {as: ABC, a1: C_SCON, a2: C_REG, a4: C_SBRA, type_: 16, size: 4}, - {as: ABC, a1: C_SCON, a2: C_REG, a4: C_LBRA, type_: 17, size: 4}, - {as: ABR, a4: C_LR, type_: 18, size: 4}, - {as: ABR, a3: C_SCON, a4: C_LR, type_: 18, size: 4}, - {as: ABR, a4: C_CTR, type_: 18, size: 4}, - {as: ABR, a1: C_REG, a4: C_CTR, type_: 18, size: 4}, - {as: ABR, a4: C_ZOREG, type_: 15, size: 8}, - {as: ABC, a2: C_REG, a4: C_LR, type_: 18, size: 4}, - {as: ABC, a2: C_REG, a4: C_CTR, type_: 18, size: 4}, - {as: ABC, a1: C_SCON, a2: C_REG, a4: C_LR, type_: 18, size: 4}, - {as: ABC, a1: C_SCON, a2: C_REG, a4: C_CTR, type_: 18, size: 4}, - {as: ABC, a4: C_ZOREG, type_: 15, size: 8}, - {as: AFMOVD, a1: C_SEXT, a4: C_FREG, type_: 8, size: 4, param: REGSB}, - {as: AFMOVD, a1: C_SAUTO, a4: C_FREG, type_: 8, size: 4, param: REGSP}, - {as: AFMOVD, a1: C_SOREG, a4: C_FREG, type_: 8, size: 4, param: REGZERO}, - {as: AFMOVD, a1: C_LEXT, a4: C_FREG, type_: 36, size: 8, param: REGSB}, - {as: AFMOVD, a1: C_LAUTO, a4: C_FREG, type_: 36, size: 8, param: REGSP}, - {as: AFMOVD, a1: C_LOREG, a4: C_FREG, type_: 36, size: 8, param: REGZERO}, - {as: AFMOVD, a1: C_ZCON, a4: C_FREG, type_: 24, size: 4}, - {as: AFMOVD, a1: C_ADDCON, a4: C_FREG, type_: 24, size: 8}, - {as: AFMOVD, a1: C_ADDR, a4: C_FREG, type_: 75, size: 8}, - {as: AFMOVD, a1: C_FREG, a4: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AFMOVD, a1: C_FREG, a4: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AFMOVD, a1: C_FREG, a4: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AFMOVD, a1: C_FREG, a4: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AFMOVD, a1: C_FREG, a4: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AFMOVD, a1: C_FREG, a4: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AFMOVD, a1: C_FREG, a4: C_ADDR, type_: 74, size: 8}, - {as: AFMOVSX, a1: C_ZOREG, a2: C_REG, a4: C_FREG, type_: 45, size: 4}, - {as: AFMOVSX, a1: C_ZOREG, a4: C_FREG, type_: 45, size: 4}, - {as: AFMOVSX, a1: C_FREG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, - {as: AFMOVSX, a1: C_FREG, a4: C_ZOREG, type_: 44, size: 4}, - {as: AFMOVSZ, a1: C_ZOREG, a2: C_REG, a4: C_FREG, type_: 45, size: 4}, - {as: AFMOVSZ, a1: C_ZOREG, a4: C_FREG, type_: 45, size: 4}, + {as: ABEQ, a6: C_SBRA, type_: 16, size: 4}, + {as: ABEQ, a1: C_CREG, a6: C_SBRA, type_: 16, size: 4}, + {as: ABR, a6: C_LBRA, type_: 11, size: 4}, + {as: ABR, a6: C_LBRAPIC, type_: 11, size: 8}, + {as: ABC, a1: C_SCON, a2: C_REG, a6: C_SBRA, type_: 16, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a6: C_LBRA, type_: 17, size: 4}, + {as: ABR, a6: C_LR, type_: 18, size: 4}, + {as: ABR, a3: C_SCON, a6: C_LR, type_: 18, size: 4}, + {as: ABR, a6: C_CTR, type_: 18, size: 4}, + {as: ABR, a1: C_REG, a6: C_CTR, type_: 18, size: 4}, + {as: ABR, a6: C_ZOREG, type_: 15, size: 8}, + {as: ABC, a2: C_REG, a6: C_LR, type_: 18, size: 4}, + {as: ABC, a2: C_REG, a6: C_CTR, type_: 18, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a6: C_LR, type_: 18, size: 4}, + {as: ABC, a1: C_SCON, a2: C_REG, a6: C_CTR, type_: 18, size: 4}, + {as: ABC, a6: C_ZOREG, type_: 15, size: 8}, + {as: AFMOVD, a1: C_SEXT, a6: C_FREG, type_: 8, size: 4, param: REGSB}, + {as: AFMOVD, a1: C_SAUTO, a6: C_FREG, type_: 8, size: 4, param: REGSP}, + {as: AFMOVD, a1: C_SOREG, a6: C_FREG, type_: 8, size: 4, param: REGZERO}, + {as: AFMOVD, a1: C_LEXT, a6: C_FREG, type_: 36, size: 8, param: REGSB}, + {as: AFMOVD, a1: C_LAUTO, a6: C_FREG, type_: 36, size: 8, param: REGSP}, + {as: AFMOVD, a1: C_LOREG, a6: C_FREG, type_: 36, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_ZCON, a6: C_FREG, type_: 24, size: 4}, + {as: AFMOVD, a1: C_ADDCON, a6: C_FREG, type_: 24, size: 8}, + {as: AFMOVD, a1: C_ADDR, a6: C_FREG, type_: 75, size: 8}, + {as: AFMOVD, a1: C_FREG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, + {as: AFMOVD, a1: C_FREG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, + {as: AFMOVD, a1: C_FREG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AFMOVD, a1: C_FREG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, + {as: AFMOVD, a1: C_FREG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, + {as: AFMOVD, a1: C_FREG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_FREG, a6: C_ADDR, type_: 74, size: 8}, + {as: AFMOVSX, a1: C_ZOREG, a2: C_REG, a6: C_FREG, type_: 45, size: 4}, + {as: AFMOVSX, a1: C_ZOREG, a6: C_FREG, type_: 45, size: 4}, + {as: AFMOVSX, a1: C_FREG, a2: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AFMOVSX, a1: C_FREG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AFMOVSZ, a1: C_ZOREG, a2: C_REG, a6: C_FREG, type_: 45, size: 4}, + {as: AFMOVSZ, a1: C_ZOREG, a6: C_FREG, type_: 45, size: 4}, {as: ASYNC, type_: 46, size: 4}, {as: AWORD, a1: C_LCON, type_: 40, size: 4}, {as: ADWORD, a1: C_LCON, type_: 31, size: 8}, {as: ADWORD, a1: C_DCON, type_: 31, size: 8}, - {as: AADDME, a1: C_REG, a4: C_REG, type_: 47, size: 4}, - {as: AEXTSB, a1: C_REG, a4: C_REG, type_: 48, size: 4}, - {as: AEXTSB, a4: C_REG, type_: 48, size: 4}, - {as: AISEL, a1: C_LCON, a2: C_REG, a3: C_REG, a4: C_REG, type_: 84, size: 4}, - {as: AISEL, a1: C_ZCON, a2: C_REG, a3: C_REG, a4: C_REG, type_: 84, size: 4}, - {as: ANEG, a1: C_REG, a4: C_REG, type_: 47, size: 4}, - {as: ANEG, a4: C_REG, type_: 47, size: 4}, - {as: AREM, a1: C_REG, a4: C_REG, type_: 50, size: 12}, - {as: AREM, a1: C_REG, a2: C_REG, a4: C_REG, type_: 50, size: 12}, - {as: AREMU, a1: C_REG, a4: C_REG, type_: 50, size: 16}, - {as: AREMU, a1: C_REG, a2: C_REG, a4: C_REG, type_: 50, size: 16}, - {as: AREMD, a1: C_REG, a4: C_REG, type_: 51, size: 12}, - {as: AREMD, a1: C_REG, a2: C_REG, a4: C_REG, type_: 51, size: 12}, + {as: AADDME, a1: C_REG, a6: C_REG, type_: 47, size: 4}, + {as: AEXTSB, a1: C_REG, a6: C_REG, type_: 48, size: 4}, + {as: AEXTSB, a6: C_REG, type_: 48, size: 4}, + {as: AISEL, a1: C_LCON, a2: C_REG, a3: C_REG, a6: C_REG, type_: 84, size: 4}, + {as: AISEL, a1: C_ZCON, a2: C_REG, a3: C_REG, a6: C_REG, type_: 84, size: 4}, + {as: ANEG, a1: C_REG, a6: C_REG, type_: 47, size: 4}, + {as: ANEG, a6: C_REG, type_: 47, size: 4}, + {as: AREM, a1: C_REG, a6: C_REG, type_: 50, size: 12}, + {as: AREM, a1: C_REG, a2: C_REG, a6: C_REG, type_: 50, size: 12}, + {as: AREMU, a1: C_REG, a6: C_REG, type_: 50, size: 16}, + {as: AREMU, a1: C_REG, a2: C_REG, a6: C_REG, type_: 50, size: 16}, + {as: AREMD, a1: C_REG, a6: C_REG, type_: 51, size: 12}, + {as: AREMD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 51, size: 12}, {as: AMTFSB0, a1: C_SCON, type_: 52, size: 4}, - {as: AMOVFL, a1: C_FPSCR, a4: C_FREG, type_: 53, size: 4}, - {as: AMOVFL, a1: C_FREG, a4: C_FPSCR, type_: 64, size: 4}, - {as: AMOVFL, a1: C_FREG, a3: C_LCON, a4: C_FPSCR, type_: 64, size: 4}, - {as: AMOVFL, a1: C_LCON, a4: C_FPSCR, type_: 65, size: 4}, - {as: AMOVD, a1: C_MSR, a4: C_REG, type_: 54, size: 4}, /* mfmsr */ - {as: AMOVD, a1: C_REG, a4: C_MSR, type_: 54, size: 4}, /* mtmsrd */ - {as: AMOVWZ, a1: C_REG, a4: C_MSR, type_: 54, size: 4}, /* mtmsr */ + {as: AMOVFL, a1: C_FPSCR, a6: C_FREG, type_: 53, size: 4}, + {as: AMOVFL, a1: C_FREG, a6: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_FREG, a3: C_LCON, a6: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_LCON, a6: C_FPSCR, type_: 65, size: 4}, + {as: AMOVD, a1: C_MSR, a6: C_REG, type_: 54, size: 4}, /* mfmsr */ + {as: AMOVD, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsrd */ + {as: AMOVWZ, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsr */ /* Other ISA 2.05+ instructions */ - {as: APOPCNTD, a1: C_REG, a4: C_REG, type_: 93, size: 4}, /* population count, x-form */ - {as: ACMPB, a1: C_REG, a2: C_REG, a4: C_REG, type_: 92, size: 4}, /* compare byte, x-form */ - {as: ACMPEQB, a1: C_REG, a2: C_REG, a4: C_CREG, type_: 92, size: 4}, /* compare equal byte, x-form, ISA 3.0 */ - {as: ACMPEQB, a1: C_REG, a4: C_REG, type_: 70, size: 4}, - {as: AFTDIV, a1: C_FREG, a2: C_FREG, a4: C_SCON, type_: 92, size: 4}, /* floating test for sw divide, x-form */ - {as: AFTSQRT, a1: C_FREG, a4: C_SCON, type_: 93, size: 4}, /* floating test for sw square root, x-form */ - {as: ACOPY, a1: C_REG, a4: C_REG, type_: 92, size: 4}, /* copy/paste facility, x-form */ - {as: ADARN, a1: C_SCON, a4: C_REG, type_: 92, size: 4}, /* deliver random number, x-form */ - {as: ALDMX, a1: C_SOREG, a4: C_REG, type_: 45, size: 4}, /* load doubleword monitored, x-form */ - {as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a4: C_REG, type_: 83, size: 4}, /* multiply-add high/low doubleword, va-form */ - {as: AADDEX, a1: C_REG, a2: C_REG, a3: C_SCON, a4: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */ - {as: ACRAND, a1: C_CREG, a4: C_CREG, type_: 2, size: 4}, /* logical ops for condition registers xl-form */ + {as: APOPCNTD, a1: C_REG, a6: C_REG, type_: 93, size: 4}, /* population count, x-form */ + {as: ACMPB, a1: C_REG, a2: C_REG, a6: C_REG, type_: 92, size: 4}, /* compare byte, x-form */ + {as: ACMPEQB, a1: C_REG, a2: C_REG, a6: C_CREG, type_: 92, size: 4}, /* compare equal byte, x-form, ISA 3.0 */ + {as: ACMPEQB, a1: C_REG, a6: C_REG, type_: 70, size: 4}, + {as: AFTDIV, a1: C_FREG, a2: C_FREG, a6: C_SCON, type_: 92, size: 4}, /* floating test for sw divide, x-form */ + {as: AFTSQRT, a1: C_FREG, a6: C_SCON, type_: 93, size: 4}, /* floating test for sw square root, x-form */ + {as: ACOPY, a1: C_REG, a6: C_REG, type_: 92, size: 4}, /* copy/paste facility, x-form */ + {as: ADARN, a1: C_SCON, a6: C_REG, type_: 92, size: 4}, /* deliver random number, x-form */ + {as: ALDMX, a1: C_SOREG, a6: C_REG, type_: 45, size: 4}, /* load doubleword monitored, x-form */ + {as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a6: C_REG, type_: 83, size: 4}, /* multiply-add high/low doubleword, va-form */ + {as: AADDEX, a1: C_REG, a2: C_REG, a3: C_SCON, a6: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */ + {as: ACRAND, a1: C_CREG, a6: C_CREG, type_: 2, size: 4}, /* logical ops for condition registers xl-form */ /* Vector instructions */ /* Vector load */ - {as: ALV, a1: C_SOREG, a4: C_VREG, type_: 45, size: 4}, /* vector load, x-form */ + {as: ALV, a1: C_SOREG, a6: C_VREG, type_: 45, size: 4}, /* vector load, x-form */ /* Vector store */ - {as: ASTV, a1: C_VREG, a4: C_SOREG, type_: 44, size: 4}, /* vector store, x-form */ + {as: ASTV, a1: C_VREG, a6: C_SOREG, type_: 44, size: 4}, /* vector store, x-form */ /* Vector logical */ - {as: AVAND, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector and, vx-form */ - {as: AVOR, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector or, vx-form */ + {as: AVAND, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector and, vx-form */ + {as: AVOR, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector or, vx-form */ /* Vector add */ - {as: AVADDUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add unsigned modulo, vx-form */ - {as: AVADDCU, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add & write carry unsigned, vx-form */ - {as: AVADDUS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add unsigned saturate, vx-form */ - {as: AVADDSS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector add signed saturate, vx-form */ - {as: AVADDE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector add extended, va-form */ + {as: AVADDUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector add unsigned modulo, vx-form */ + {as: AVADDCU, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector add & write carry unsigned, vx-form */ + {as: AVADDUS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector add unsigned saturate, vx-form */ + {as: AVADDSS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector add signed saturate, vx-form */ + {as: AVADDE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector add extended, va-form */ /* Vector subtract */ - {as: AVSUBUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned modulo, vx-form */ - {as: AVSUBCU, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract & write carry unsigned, vx-form */ - {as: AVSUBUS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned saturate, vx-form */ - {as: AVSUBSS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector subtract signed saturate, vx-form */ - {as: AVSUBE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector subtract extended, va-form */ + {as: AVSUBUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned modulo, vx-form */ + {as: AVSUBCU, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector subtract & write carry unsigned, vx-form */ + {as: AVSUBUS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector subtract unsigned saturate, vx-form */ + {as: AVSUBSS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector subtract signed saturate, vx-form */ + {as: AVSUBE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector subtract extended, va-form */ /* Vector multiply */ - {as: AVMULESB, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4, param: 9}, /* vector multiply, vx-form */ - {as: AVPMSUM, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector polynomial multiply & sum, vx-form */ - {as: AVMSUMUDM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector multiply-sum, va-form */ + {as: AVMULESB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4, param: 9}, /* vector multiply, vx-form */ + {as: AVPMSUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector polynomial multiply & sum, vx-form */ + {as: AVMSUMUDM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector multiply-sum, va-form */ /* Vector rotate */ - {as: AVR, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector rotate, vx-form */ + {as: AVR, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector rotate, vx-form */ /* Vector shift */ - {as: AVS, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector shift, vx-form */ - {as: AVSA, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector shift algebraic, vx-form */ - {as: AVSOI, a1: C_ANDCON, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector shift by octet immediate, va-form */ + {as: AVS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector shift, vx-form */ + {as: AVSA, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector shift algebraic, vx-form */ + {as: AVSOI, a1: C_ANDCON, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector shift by octet immediate, va-form */ /* Vector count */ - {as: AVCLZ, a1: C_VREG, a4: C_VREG, type_: 85, size: 4}, /* vector count leading zeros, vx-form */ - {as: AVPOPCNT, a1: C_VREG, a4: C_VREG, type_: 85, size: 4}, /* vector population count, vx-form */ + {as: AVCLZ, a1: C_VREG, a6: C_VREG, type_: 85, size: 4}, /* vector count leading zeros, vx-form */ + {as: AVPOPCNT, a1: C_VREG, a6: C_VREG, type_: 85, size: 4}, /* vector population count, vx-form */ /* Vector compare */ - {as: AVCMPEQ, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare equal, vc-form */ - {as: AVCMPGT, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare greater than, vc-form */ - {as: AVCMPNEZB, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector compare not equal, vx-form */ + {as: AVCMPEQ, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector compare equal, vc-form */ + {as: AVCMPGT, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector compare greater than, vc-form */ + {as: AVCMPNEZB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector compare not equal, vx-form */ /* Vector merge */ - {as: AVMRGOW, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector merge odd word, vx-form */ + {as: AVMRGOW, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector merge odd word, vx-form */ /* Vector permute */ - {as: AVPERM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector permute, va-form */ + {as: AVPERM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector permute, va-form */ /* Vector bit permute */ - {as: AVBPERMQ, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector bit permute, vx-form */ + {as: AVBPERMQ, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector bit permute, vx-form */ /* Vector select */ - {as: AVSEL, a1: C_VREG, a2: C_VREG, a3: C_VREG, a4: C_VREG, type_: 83, size: 4}, /* vector select, va-form */ + {as: AVSEL, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector select, va-form */ /* Vector splat */ - {as: AVSPLTB, a1: C_SCON, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector splat, vx-form */ - {as: AVSPLTB, a1: C_ADDCON, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, - {as: AVSPLTISB, a1: C_SCON, a4: C_VREG, type_: 82, size: 4}, /* vector splat immediate, vx-form */ - {as: AVSPLTISB, a1: C_ADDCON, a4: C_VREG, type_: 82, size: 4}, + {as: AVSPLTB, a1: C_SCON, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector splat, vx-form */ + {as: AVSPLTB, a1: C_ADDCON, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, + {as: AVSPLTISB, a1: C_SCON, a6: C_VREG, type_: 82, size: 4}, /* vector splat immediate, vx-form */ + {as: AVSPLTISB, a1: C_ADDCON, a6: C_VREG, type_: 82, size: 4}, /* Vector AES */ - {as: AVCIPH, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES cipher, vx-form */ - {as: AVNCIPH, a1: C_VREG, a2: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES inverse cipher, vx-form */ - {as: AVSBOX, a1: C_VREG, a4: C_VREG, type_: 82, size: 4}, /* vector AES subbytes, vx-form */ + {as: AVCIPH, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector AES cipher, vx-form */ + {as: AVNCIPH, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector AES inverse cipher, vx-form */ + {as: AVSBOX, a1: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector AES subbytes, vx-form */ /* Vector SHA */ - {as: AVSHASIGMA, a1: C_ANDCON, a2: C_VREG, a3: C_ANDCON, a4: C_VREG, type_: 82, size: 4}, /* vector SHA sigma, vx-form */ + {as: AVSHASIGMA, a1: C_ANDCON, a2: C_VREG, a3: C_ANDCON, a6: C_VREG, type_: 82, size: 4}, /* vector SHA sigma, vx-form */ /* VSX vector load */ - {as: ALXVD2X, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx vector load, xx1-form */ - {as: ALXV, a1: C_SOREG, a4: C_VSREG, type_: 96, size: 4}, /* vsx vector load, dq-form */ - {as: ALXVL, a1: C_REG, a2: C_REG, a4: C_VSREG, type_: 98, size: 4}, /* vsx vector load length */ + {as: ALXVD2X, a1: C_SOREG, a6: C_VSREG, type_: 87, size: 4}, /* vsx vector load, xx1-form */ + {as: ALXV, a1: C_SOREG, a6: C_VSREG, type_: 96, size: 4}, /* vsx vector load, dq-form */ + {as: ALXVL, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 98, size: 4}, /* vsx vector load length */ /* VSX vector store */ - {as: ASTXVD2X, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx vector store, xx1-form */ - {as: ASTXV, a1: C_VSREG, a4: C_SOREG, type_: 97, size: 4}, /* vsx vector store, dq-form */ - {as: ASTXVL, a1: C_VSREG, a2: C_REG, a4: C_REG, type_: 99, size: 4}, /* vsx vector store with length x-form */ + {as: ASTXVD2X, a1: C_VSREG, a6: C_SOREG, type_: 86, size: 4}, /* vsx vector store, xx1-form */ + {as: ASTXV, a1: C_VSREG, a6: C_SOREG, type_: 97, size: 4}, /* vsx vector store, dq-form */ + {as: ASTXVL, a1: C_VSREG, a2: C_REG, a6: C_REG, type_: 99, size: 4}, /* vsx vector store with length x-form */ /* VSX scalar load */ - {as: ALXSDX, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx scalar load, xx1-form */ + {as: ALXSDX, a1: C_SOREG, a6: C_VSREG, type_: 87, size: 4}, /* vsx scalar load, xx1-form */ /* VSX scalar store */ - {as: ASTXSDX, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx scalar store, xx1-form */ + {as: ASTXSDX, a1: C_VSREG, a6: C_SOREG, type_: 86, size: 4}, /* vsx scalar store, xx1-form */ /* VSX scalar as integer load */ - {as: ALXSIWAX, a1: C_SOREG, a4: C_VSREG, type_: 87, size: 4}, /* vsx scalar as integer load, xx1-form */ + {as: ALXSIWAX, a1: C_SOREG, a6: C_VSREG, type_: 87, size: 4}, /* vsx scalar as integer load, xx1-form */ /* VSX scalar store as integer */ - {as: ASTXSIWX, a1: C_VSREG, a4: C_SOREG, type_: 86, size: 4}, /* vsx scalar as integer store, xx1-form */ + {as: ASTXSIWX, a1: C_VSREG, a6: C_SOREG, type_: 86, size: 4}, /* vsx scalar as integer store, xx1-form */ /* VSX move from VSR */ - {as: AMFVSRD, a1: C_VSREG, a4: C_REG, type_: 88, size: 4}, /* vsx move from vsr, xx1-form */ - {as: AMFVSRD, a1: C_FREG, a4: C_REG, type_: 88, size: 4}, - {as: AMFVSRD, a1: C_VREG, a4: C_REG, type_: 88, size: 4}, + {as: AMFVSRD, a1: C_VSREG, a6: C_REG, type_: 88, size: 4}, /* vsx move from vsr, xx1-form */ + {as: AMFVSRD, a1: C_FREG, a6: C_REG, type_: 88, size: 4}, + {as: AMFVSRD, a1: C_VREG, a6: C_REG, type_: 88, size: 4}, /* VSX move to VSR */ - {as: AMTVSRD, a1: C_REG, a4: C_VSREG, type_: 88, size: 4}, /* vsx move to vsr, xx1-form */ - {as: AMTVSRD, a1: C_REG, a2: C_REG, a4: C_VSREG, type_: 88, size: 4}, - {as: AMTVSRD, a1: C_REG, a4: C_FREG, type_: 88, size: 4}, - {as: AMTVSRD, a1: C_REG, a4: C_VREG, type_: 88, size: 4}, + {as: AMTVSRD, a1: C_REG, a6: C_VSREG, type_: 88, size: 4}, /* vsx move to vsr, xx1-form */ + {as: AMTVSRD, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 88, size: 4}, + {as: AMTVSRD, a1: C_REG, a6: C_FREG, type_: 88, size: 4}, + {as: AMTVSRD, a1: C_REG, a6: C_VREG, type_: 88, size: 4}, /* VSX logical */ - {as: AXXLAND, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx and, xx3-form */ - {as: AXXLOR, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx or, xx3-form */ + {as: AXXLAND, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx and, xx3-form */ + {as: AXXLOR, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx or, xx3-form */ /* VSX select */ - {as: AXXSEL, a1: C_VSREG, a2: C_VSREG, a3: C_VSREG, a4: C_VSREG, type_: 91, size: 4}, /* vsx select, xx4-form */ + {as: AXXSEL, a1: C_VSREG, a2: C_VSREG, a3: C_VSREG, a6: C_VSREG, type_: 91, size: 4}, /* vsx select, xx4-form */ /* VSX merge */ - {as: AXXMRGHW, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx merge, xx3-form */ + {as: AXXMRGHW, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx merge, xx3-form */ /* VSX splat */ - {as: AXXSPLTW, a1: C_VSREG, a3: C_SCON, a4: C_VSREG, type_: 89, size: 4}, /* vsx splat, xx2-form */ - {as: AXXSPLTIB, a1: C_SCON, a4: C_VSREG, type_: 100, size: 4}, /* vsx splat, xx2-form */ + {as: AXXSPLTW, a1: C_VSREG, a3: C_SCON, a6: C_VSREG, type_: 89, size: 4}, /* vsx splat, xx2-form */ + {as: AXXSPLTIB, a1: C_SCON, a6: C_VSREG, type_: 100, size: 4}, /* vsx splat, xx2-form */ /* VSX permute */ - {as: AXXPERM, a1: C_VSREG, a2: C_VSREG, a4: C_VSREG, type_: 90, size: 4}, /* vsx permute, xx3-form */ + {as: AXXPERM, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx permute, xx3-form */ /* VSX shift */ - {as: AXXSLDWI, a1: C_VSREG, a2: C_VSREG, a3: C_SCON, a4: C_VSREG, type_: 90, size: 4}, /* vsx shift immediate, xx3-form */ + {as: AXXSLDWI, a1: C_VSREG, a2: C_VSREG, a3: C_SCON, a6: C_VSREG, type_: 90, size: 4}, /* vsx shift immediate, xx3-form */ /* VSX reverse bytes */ - {as: AXXBRQ, a1: C_VSREG, a4: C_VSREG, type_: 101, size: 4}, /* vsx reverse bytes */ + {as: AXXBRQ, a1: C_VSREG, a6: C_VSREG, type_: 101, size: 4}, /* vsx reverse bytes */ /* VSX scalar FP-FP conversion */ - {as: AXSCVDPSP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-fp conversion, xx2-form */ + {as: AXSCVDPSP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-fp conversion, xx2-form */ /* VSX vector FP-FP conversion */ - {as: AXVCVDPSP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-fp conversion, xx2-form */ + {as: AXVCVDPSP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-fp conversion, xx2-form */ /* VSX scalar FP-integer conversion */ - {as: AXSCVDPSXDS, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-integer conversion, xx2-form */ + {as: AXSCVDPSXDS, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-integer conversion, xx2-form */ /* VSX scalar integer-FP conversion */ - {as: AXSCVSXDDP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx scalar integer-fp conversion, xx2-form */ + {as: AXSCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar integer-fp conversion, xx2-form */ /* VSX vector FP-integer conversion */ - {as: AXVCVDPSXDS, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-integer conversion, xx2-form */ + {as: AXVCVDPSXDS, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-integer conversion, xx2-form */ /* VSX vector integer-FP conversion */ - {as: AXVCVSXDDP, a1: C_VSREG, a4: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */ + {as: AXVCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */ /* 64-bit special registers */ - {as: AMOVD, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a4: C_LR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a4: C_XER, type_: 66, size: 4}, - {as: AMOVD, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_LR, a4: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_CTR, a4: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_XER, a4: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_LR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVD, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_LR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_CTR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_XER, a6: C_REG, type_: 66, size: 4}, /* 32-bit special registers (gloss over sign-extension or not?) */ - {as: AMOVW, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, - {as: AMOVW, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, - {as: AMOVW, a1: C_REG, a4: C_XER, type_: 66, size: 4}, - {as: AMOVW, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, - {as: AMOVW, a1: C_XER, a4: C_REG, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a4: C_SPR, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a4: C_CTR, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a4: C_XER, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_SPR, a4: C_REG, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_XER, a4: C_REG, type_: 66, size: 4}, - {as: AMOVFL, a1: C_FPSCR, a4: C_CREG, type_: 73, size: 4}, - {as: AMOVFL, a1: C_CREG, a4: C_CREG, type_: 67, size: 4}, - {as: AMOVW, a1: C_CREG, a4: C_REG, type_: 68, size: 4}, - {as: AMOVWZ, a1: C_CREG, a4: C_REG, type_: 68, size: 4}, - {as: AMOVFL, a1: C_REG, a4: C_LCON, type_: 69, size: 4}, - {as: AMOVFL, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, - {as: AMOVW, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, - {as: AMOVWZ, a1: C_REG, a4: C_CREG, type_: 69, size: 4}, - {as: ACMP, a1: C_REG, a4: C_REG, type_: 70, size: 4}, - {as: ACMP, a1: C_REG, a2: C_REG, a4: C_REG, type_: 70, size: 4}, - {as: ACMP, a1: C_REG, a4: C_ADDCON, type_: 71, size: 4}, - {as: ACMP, a1: C_REG, a2: C_REG, a4: C_ADDCON, type_: 71, size: 4}, - {as: ACMPU, a1: C_REG, a4: C_REG, type_: 70, size: 4}, - {as: ACMPU, a1: C_REG, a2: C_REG, a4: C_REG, type_: 70, size: 4}, - {as: ACMPU, a1: C_REG, a4: C_ANDCON, type_: 71, size: 4}, - {as: ACMPU, a1: C_REG, a2: C_REG, a4: C_ANDCON, type_: 71, size: 4}, - {as: AFCMPO, a1: C_FREG, a4: C_FREG, type_: 70, size: 4}, - {as: AFCMPO, a1: C_FREG, a2: C_REG, a4: C_FREG, type_: 70, size: 4}, - {as: ATW, a1: C_LCON, a2: C_REG, a4: C_REG, type_: 60, size: 4}, - {as: ATW, a1: C_LCON, a2: C_REG, a4: C_ADDCON, type_: 61, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVW, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVW, a1: C_XER, a6: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_XER, a6: C_REG, type_: 66, size: 4}, + {as: AMOVFL, a1: C_FPSCR, a6: C_CREG, type_: 73, size: 4}, + {as: AMOVFL, a1: C_CREG, a6: C_CREG, type_: 67, size: 4}, + {as: AMOVW, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, + {as: AMOVWZ, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, + {as: AMOVFL, a1: C_REG, a6: C_LCON, type_: 69, size: 4}, + {as: AMOVFL, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: ACMP, a1: C_REG, a6: C_REG, type_: 70, size: 4}, + {as: ACMP, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4}, + {as: ACMP, a1: C_REG, a6: C_ADDCON, type_: 71, size: 4}, + {as: ACMP, a1: C_REG, a2: C_REG, a6: C_ADDCON, type_: 71, size: 4}, + {as: ACMPU, a1: C_REG, a6: C_REG, type_: 70, size: 4}, + {as: ACMPU, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4}, + {as: ACMPU, a1: C_REG, a6: C_ANDCON, type_: 71, size: 4}, + {as: ACMPU, a1: C_REG, a2: C_REG, a6: C_ANDCON, type_: 71, size: 4}, + {as: AFCMPO, a1: C_FREG, a6: C_FREG, type_: 70, size: 4}, + {as: AFCMPO, a1: C_FREG, a2: C_REG, a6: C_FREG, type_: 70, size: 4}, + {as: ATW, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 60, size: 4}, + {as: ATW, a1: C_LCON, a2: C_REG, a6: C_ADDCON, type_: 61, size: 4}, {as: ADCBF, a1: C_ZOREG, type_: 43, size: 4}, {as: ADCBF, a1: C_SOREG, type_: 43, size: 4}, - {as: ADCBF, a1: C_ZOREG, a2: C_REG, a4: C_SCON, type_: 43, size: 4}, - {as: ADCBF, a1: C_SOREG, a4: C_SCON, type_: 43, size: 4}, - {as: AECOWX, a1: C_REG, a2: C_REG, a4: C_ZOREG, type_: 44, size: 4}, - {as: AECIWX, a1: C_ZOREG, a2: C_REG, a4: C_REG, type_: 45, size: 4}, - {as: AECOWX, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, - {as: AECIWX, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, - {as: ALDAR, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, - {as: ALDAR, a1: C_ZOREG, a3: C_ANDCON, a4: C_REG, type_: 45, size: 4}, + {as: ADCBF, a1: C_ZOREG, a2: C_REG, a6: C_SCON, type_: 43, size: 4}, + {as: ADCBF, a1: C_SOREG, a6: C_SCON, type_: 43, size: 4}, + {as: AECOWX, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AECIWX, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 45, size: 4}, + {as: AECOWX, a1: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AECIWX, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, + {as: ALDAR, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, + {as: ALDAR, a1: C_ZOREG, a3: C_ANDCON, a6: C_REG, type_: 45, size: 4}, {as: AEIEIO, type_: 46, size: 4}, {as: ATLBIE, a1: C_REG, type_: 49, size: 4}, - {as: ATLBIE, a1: C_SCON, a4: C_REG, type_: 49, size: 4}, - {as: ASLBMFEE, a1: C_REG, a4: C_REG, type_: 55, size: 4}, - {as: ASLBMTE, a1: C_REG, a4: C_REG, type_: 55, size: 4}, - {as: ASTSW, a1: C_REG, a4: C_ZOREG, type_: 44, size: 4}, - {as: ASTSW, a1: C_REG, a3: C_LCON, a4: C_ZOREG, type_: 41, size: 4}, - {as: ALSW, a1: C_ZOREG, a4: C_REG, type_: 45, size: 4}, - {as: ALSW, a1: C_ZOREG, a3: C_LCON, a4: C_REG, type_: 42, size: 4}, + {as: ATLBIE, a1: C_SCON, a6: C_REG, type_: 49, size: 4}, + {as: ASLBMFEE, a1: C_REG, a6: C_REG, type_: 55, size: 4}, + {as: ASLBMTE, a1: C_REG, a6: C_REG, type_: 55, size: 4}, + {as: ASTSW, a1: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: ASTSW, a1: C_REG, a3: C_LCON, a6: C_ZOREG, type_: 41, size: 4}, + {as: ALSW, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, + {as: ALSW, a1: C_ZOREG, a3: C_LCON, a6: C_REG, type_: 42, size: 4}, {as: obj.AUNDEF, type_: 78, size: 4}, - {as: obj.APCDATA, a1: C_LCON, a4: C_LCON, type_: 0, size: 0}, - {as: obj.AFUNCDATA, a1: C_SCON, a4: C_ADDR, type_: 0, size: 0}, + {as: obj.APCDATA, a1: C_LCON, a6: C_LCON, type_: 0, size: 0}, + {as: obj.AFUNCDATA, a1: C_SCON, a6: C_ADDR, type_: 0, size: 0}, {as: obj.ANOP, type_: 0, size: 0}, {as: obj.ANOP, a1: C_LCON, type_: 0, size: 0}, // NOP operand variations added for #40689 {as: obj.ANOP, a1: C_REG, type_: 0, size: 0}, // to preserve previous behavior {as: obj.ANOP, a1: C_FREG, type_: 0, size: 0}, - {as: obj.ADUFFZERO, a4: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL - {as: obj.ADUFFCOPY, a4: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL + {as: obj.ADUFFZERO, a6: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL + {as: obj.ADUFFCOPY, a6: C_LBRA, type_: 11, size: 4}, // same as ABR/ABL {as: obj.APCALIGN, a1: C_LCON, type_: 0, size: 0}, // align code {as: obj.AXXX, type_: 0, size: 4}, @@ -1042,25 +1044,28 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab { a1 = c.aclass(&p.From) + 1 p.From.Class = int8(a1) } - a1-- - a3 := C_NONE + 1 - if p.GetFrom3() != nil { - a3 = int(p.GetFrom3().Class) - if a3 == 0 { - a3 = c.aclass(p.GetFrom3()) + 1 - p.GetFrom3().Class = int8(a3) + + argsv := [3]int{C_NONE + 1, C_NONE + 1, C_NONE + 1} + for i, ap := range p.RestArgs { + argsv[i] = int(ap.Addr.Class) + if argsv[i] == 0 { + argsv[i] = c.aclass(&ap.Addr) + 1 + ap.Addr.Class = int8(argsv[i]) } - } - a3-- - a4 := int(p.To.Class) - if a4 == 0 { - a4 = c.aclass(&p.To) + 1 - p.To.Class = int8(a4) } + a3 := argsv[0] - 1 + a4 := argsv[1] - 1 + a5 := argsv[2] - 1 + + a6 := int(p.To.Class) + if a6 == 0 { + a6 = c.aclass(&p.To) + 1 + p.To.Class = int8(a6) + } + a6-- - a4-- a2 := C_NONE if p.Reg != 0 { if REG_R0 <= p.Reg && p.Reg <= REG_R31 { @@ -1074,20 +1079,22 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab { } } - // c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4) + // c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4, a5, a6) ops := oprange[p.As&obj.AMask] c1 := &xcmp[a1] c3 := &xcmp[a3] c4 := &xcmp[a4] + c5 := &xcmp[a5] + c6 := &xcmp[a6] for i := range ops { op := &ops[i] - if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && c4[op.a4] { + if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && c4[op.a4] && c5[op.a5] && c6[op.a6] { p.Optab = uint16(cap(optab) - cap(ops) + i + 1) return op } } - c.ctxt.Diag("illegal combination %v %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4)) + c.ctxt.Diag("illegal combination %v %v %v %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4), DRconv(a5), DRconv(a6)) prasm(p) if ops == nil { ops = optab @@ -1217,6 +1224,14 @@ func (x ocmp) Less(i, j int) bool { if n != 0 { return n < 0 } + n = int(p1.a5) - int(p2.a5) + if n != 0 { + return n < 0 + } + n = int(p1.a6) - int(p2.a6) + if n != 0 { + return n < 0 + } return false } -- GitLab From 9d88a9e2bf89068238ed02a0c960e58f547bb102 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 22 Feb 2021 21:51:35 -0500 Subject: [PATCH 0190/1298] cmd/compile: implement simple register results at least for ints and strings includes simple test For #40724. Change-Id: Ib8484e5b957b08f961574a67cfd93d3d26551558 Reviewed-on: https://go-review.googlesource.com/c/go/+/295309 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 64 ++++++++++++++++++++ src/cmd/compile/internal/ssa/expand_calls.go | 58 ++++++++++++------ src/cmd/compile/internal/ssa/lower.go | 3 +- src/cmd/compile/internal/ssa/op.go | 25 +++++++- src/cmd/compile/internal/ssa/regalloc.go | 3 + test/abi/fibish.go | 33 ++++++++++ test/abi/fibish.out | 1 + 7 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 test/abi/fibish.go create mode 100644 test/abi/fibish.out diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index f84f8f8e01..ffa709965c 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -101,6 +101,70 @@ func (a *ABIParamAssignment) Offset() int32 { return a.offset } +// RegisterTypes returns a slice of the types of the registers +// corresponding to a slice of parameters. The returned slice +// has capacity for one more, likely a memory type. +func RegisterTypes(apa []ABIParamAssignment) []*types.Type { + rcount := 0 + for _, pa := range apa { + rcount += len(pa.Registers) + } + if rcount == 0 { + // Note that this catches top-level struct{} and [0]Foo, which are stack allocated. + return make([]*types.Type, 0, 1) + } + rts := make([]*types.Type, 0, rcount+1) + for _, pa := range apa { + if len(pa.Registers) == 0 { + continue + } + rts = appendParamRegs(rts, pa.Type) + } + return rts +} + +func appendParamRegs(rts []*types.Type, t *types.Type) []*types.Type { + if t.IsScalar() || t.IsPtrShaped() { + if t.IsComplex() { + c := types.FloatForComplex(t) + return append(rts, c, c) + } else { + if int(t.Size()) <= types.RegSize { + return append(rts, t) + } + // assume 64bit int on 32-bit machine + // TODO endianness? Should high-order (sign bits) word come first? + if t.IsSigned() { + rts = append(rts, types.Types[types.TINT32]) + } else { + rts = append(rts, types.Types[types.TUINT32]) + } + return append(rts, types.Types[types.TUINT32]) + } + } else { + typ := t.Kind() + switch typ { + case types.TARRAY: + for i := int64(0); i < t.Size(); i++ { // 0 gets no registers, plus future-proofing. + rts = appendParamRegs(rts, t.Elem()) + } + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + if f.Type.Size() > 0 { // embedded zero-width types receive no registers + rts = appendParamRegs(rts, f.Type) + } + } + case types.TSLICE: + return appendParamRegs(rts, synthSlice) + case types.TSTRING: + return appendParamRegs(rts, synthString) + case types.TINTER: + return appendParamRegs(rts, synthIface) + } + } + return rts +} + // SpillOffset returns the offset *within the spill area* for the parameter that "a" describes. // Registers will be spilled here; if a memory home is needed (for a pointer method e.g.) // then that will be the address. diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index ff16eac90f..6e14a90e79 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -14,10 +14,10 @@ import ( ) type selKey struct { - from *Value - offset int64 - size int64 - typ *types.Type + from *Value // what is selected from + offsetOrIndex int64 // whatever is appropriate for the selector + size int64 + typ *types.Type } type offsetKey struct { @@ -372,6 +372,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, // if applied to Op-mumble-call, the Aux tells us which result, regOffset specifies offset within result. If a register, should rewrite to OpSelectN for new call. // TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there. call := selector.Args[0] + call0 := call aux := call.Aux.(*AuxCall) which := selector.AuxInt if which == aux.NResults() { // mem is after the results. @@ -398,7 +399,6 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, leafType := removeTrivialWrapperTypes(leaf.Type) if x.canSSAType(leafType) { pt := types.NewPtr(leafType) - off := x.offsetFrom(x.sp, offset+aux.OffsetOfResult(which), pt) // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input. if call.Op == OpStaticLECall { // TODO this is temporary until all calls are register-able // Create a "mem" for any loads that need to occur. @@ -413,15 +413,30 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, call = mem } } - if leaf.Block == call.Block { - leaf.reset(OpLoad) - leaf.SetArgs2(off, call) - leaf.Type = leafType + outParam := aux.abiInfo.OutParam(int(which)) + if len(outParam.Registers) > 0 { + reg := int64(outParam.Registers[regOffset]) + if leaf.Block == call.Block { + leaf.reset(OpSelectN) + leaf.SetArgs1(call0) + leaf.Type = leafType + leaf.AuxInt = reg + } else { + w := call.Block.NewValue1I(leaf.Pos, OpSelectN, leafType, reg, call0) + leaf.copyOf(w) + } } else { - w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call) - leaf.copyOf(w) - if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) + off := x.offsetFrom(x.sp, offset+aux.OffsetOfResult(which), pt) + if leaf.Block == call.Block { + leaf.reset(OpLoad) + leaf.SetArgs2(off, call) + leaf.Type = leafType + } else { + w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call) + leaf.copyOf(w) + if x.debug { + fmt.Printf("\tnew %s\n", w.LongString()) + } } } for _, s := range x.namedSelects[selector] { @@ -812,7 +827,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) } if x.debug { - fmt.Printf("\t\tstoreArg returns %s\n", s.LongString()) + fmt.Printf("\t\tstoreArg returns %s, storeRc=%s\n", s.LongString(), storeRc.String()) } return s } @@ -983,9 +998,11 @@ func expandCalls(f *Func) { mem = x.storeArgOrLoad(v.Pos, b, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc) } } - // TODO REGISTER -- keep the Result for block control, splice in contents of AllResults - b.SetControl(mem) - v.reset(OpInvalid) // otherwise it can have a mem operand which will fail check(), even though it is dead. + v.resetArgs() + v.AddArgs(allResults...) + v.AddArg(mem) + v.Type = types.NewResults(append(abi.RegisterTypes(aux.abiInfo.OutParams()), types.TypeMem)) + b.SetControl(v) } } @@ -1170,7 +1187,7 @@ func expandCalls(f *Func) { case OpArraySelect: offset = size * v.AuxInt case OpSelectN: - offset = w.Aux.(*AuxCall).OffsetOfResult(v.AuxInt) + offset = v.AuxInt // offset is just a key, really. case OpInt64Hi: offset = x.hiOffset case OpInt64Lo: @@ -1182,7 +1199,7 @@ func expandCalls(f *Func) { case OpComplexImag: offset = size } - sk := selKey{from: w, size: size, offset: offset, typ: typ} + sk := selKey{from: w, size: size, offsetOrIndex: offset, typ: typ} dupe := x.commonSelectors[sk] if dupe == nil { x.commonSelectors[sk] = v @@ -1240,8 +1257,9 @@ func expandCalls(f *Func) { x.rewriteArgToMemOrRegs(v) case OpStaticLECall: v.Op = OpStaticCall + rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams()) // TODO need to insert all the register types. - v.Type = types.NewResults([]*types.Type{types.TypeMem}) + v.Type = types.NewResults(append(rts, types.TypeMem)) case OpClosureLECall: v.Op = OpClosureCall v.Type = types.TypeMem diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index bbb80a7a30..5760c35601 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -24,7 +24,7 @@ func checkLower(f *Func) { case OpSP, OpSB, OpInitMem, OpArg, OpArgIntReg, OpArgFloatReg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark: continue // ok not to lower case OpMakeResult: - if len(b.Controls) == 1 && b.Controls[0] == v { + if b.Controls[0] == v { continue } case OpGetG: @@ -34,6 +34,7 @@ func checkLower(f *Func) { } } s := "not lowered: " + v.String() + ", " + v.Op.String() + " " + v.Type.SimpleString() + for _, a := range v.Args { s += " " + a.Type.SimpleString() } diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 4082e84c6a..0577ec7bed 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -134,6 +134,24 @@ func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo { return a.reg } +func (a *AuxCall) ResultReg(c *Config) *regInfo { + if a.abiInfo.OutRegistersUsed() == 0 { + return a.reg + } + if len(a.reg.inputs) > 0 { + return a.reg + } + k := 0 + for _, p := range a.abiInfo.OutParams() { + for _, r := range p.Registers { + m := archRegForAbiReg(r, c) + a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)}) + k++ + } + } + return a.reg +} + func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 { var m int8 if int(r) < len(c.intParamRegs) { @@ -285,10 +303,13 @@ func ClosureAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParam func (*AuxCall) CanBeAnSSAAux() {} // OwnAuxCall returns a function's own AuxCall - func OwnAuxCall(fn *obj.LSym, args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { // TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate. - return &AuxCall{Fn: fn, args: args, results: results, abiInfo: paramResultInfo} + var reg *regInfo + if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { + reg = ®Info{} + } + return &AuxCall{Fn: fn, args: args, results: results, abiInfo: paramResultInfo, reg: reg} } const ( diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index c2d0478e82..15f6412a85 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -830,6 +830,9 @@ func (s *regAllocState) regspec(v *Value) regInfo { return *ac.Reg(&opcodeTable[op].reg, s.f.Config) } } + if op == OpMakeResult && s.f.OwnAux.reg != nil { + return *s.f.OwnAux.ResultReg(s.f.Config) + } return opcodeTable[op].reg } diff --git a/test/abi/fibish.go b/test/abi/fibish.go new file mode 100644 index 0000000000..b72f1322de --- /dev/null +++ b/test/abi/fibish.go @@ -0,0 +1,33 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 "fmt" + +// Test that register results are correctly returned (and passed) + +//go:registerparams +//go:noinline +func f(x int) (int, int) { + + if x < 3 { + return 0, x + } + + a, b := f(x - 2) + c, d := f(x - 1) + return a + d, b + c +} + +func main() { + x := 40 + a, b := f(x) + fmt.Printf("f(%d)=%d,%d\n", x, a, b) +} diff --git a/test/abi/fibish.out b/test/abi/fibish.out new file mode 100644 index 0000000000..9bd80c32c9 --- /dev/null +++ b/test/abi/fibish.out @@ -0,0 +1 @@ +f(40)=39088169,126491972 -- GitLab From 77505c25d83a2130011736d6a2a915eaa3ae230a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 28 Feb 2021 12:18:18 +0100 Subject: [PATCH 0191/1298] syscall: treat proc thread attribute lists as unsafe.Pointers It turns out that the proc thread update function doesn't actually allocate new memory for its arguments and instead just copies the pointer values into the preallocated memory. Since we were allocating that memory as []byte, the garbage collector didn't scan it for pointers to Go allocations and freed them. We _could_ fix this by requiring that all users of this use runtime.KeepAlive for everything they pass to the update function, but that seems harder than necessary. Instead, we can just do the allocation as []unsafe.Pointer, which means the GC can operate as intended and not free these from beneath our feet. In order to ensure this remains true, we also add a test for this. Fixes #44662. Change-Id: Ib392ba8ceacacec94b11379919c8179841cba29f Reviewed-on: https://go-review.googlesource.com/c/go/+/297389 Trust: Jason A. Donenfeld Trust: Alex Brainman Trust: Bryan C. Mills Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/syscall/exec_windows.go | 4 ++-- src/syscall/export_windows_test.go | 11 +++++++++ src/syscall/syscall_windows.go | 5 ++-- src/syscall/syscall_windows_test.go | 36 +++++++++++++++++++++++++++++ src/syscall/types_windows.go | 8 ++++++- src/syscall/zsyscall_windows.go | 2 +- 6 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/syscall/export_windows_test.go diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 7b73cf1f6f..b20a27d28b 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -340,7 +340,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle si.ShowWindow = SW_HIDE } if sys.ParentProcess != 0 { - err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, uintptr(unsafe.Pointer(&sys.ParentProcess)), unsafe.Sizeof(sys.ParentProcess), 0, nil) + err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, unsafe.Pointer(&sys.ParentProcess), unsafe.Sizeof(sys.ParentProcess), nil, nil) if err != nil { return 0, 0, err } @@ -351,7 +351,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle fd = append(fd, sys.AdditionalInheritedHandles...) // Do not accidentally inherit more than these handles. - err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, uintptr(unsafe.Pointer(&fd[0])), uintptr(len(fd))*unsafe.Sizeof(fd[0]), 0, nil) + err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil) if err != nil { return 0, 0, err } diff --git a/src/syscall/export_windows_test.go b/src/syscall/export_windows_test.go new file mode 100644 index 0000000000..a72a1ee391 --- /dev/null +++ b/src/syscall/export_windows_test.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 + +var NewProcThreadAttributeList = newProcThreadAttributeList +var UpdateProcThreadAttribute = updateProcThreadAttribute +var DeleteProcThreadAttributeList = deleteProcThreadAttributeList + +const PROC_THREAD_ATTRIBUTE_HANDLE_LIST = _PROC_THREAD_ATTRIBUTE_HANDLE_LIST diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index cc8dc487d3..05a7d3027d 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -286,7 +286,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW //sys initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList //sys deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) = DeleteProcThreadAttributeList -//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value uintptr, size uintptr, prevvalue uintptr, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute +//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute // syscall interface implementation for other packages @@ -1256,7 +1256,8 @@ func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LI } return nil, err } - al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]byte, size)[0])) + // size is guaranteed to be ≥1 by initializeProcThreadAttributeList. + al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]unsafe.Pointer, (size+ptrSize-1)/ptrSize)[0])) err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size) if err != nil { return nil, err diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index a9ae54752b..d5e8d58b5a 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -7,8 +7,11 @@ package syscall_test import ( "os" "path/filepath" + "runtime" "syscall" "testing" + "time" + "unsafe" ) func TestWin32finddata(t *testing.T) { @@ -75,3 +78,36 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", syscall.TOKEN_ALL_ACCESS) } } + +func TestProcThreadAttributeListPointers(t *testing.T) { + list, err := syscall.NewProcThreadAttributeList(1) + if err != nil { + t.Errorf("unable to create ProcThreadAttributeList: %v", err) + } + done := make(chan struct{}) + fds := make([]syscall.Handle, 20) + runtime.SetFinalizer(&fds[0], func(*syscall.Handle) { + close(done) + }) + err = syscall.UpdateProcThreadAttribute(list, 0, syscall.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fds[0]), uintptr(len(fds))*unsafe.Sizeof(fds[0]), nil, nil) + if err != nil { + syscall.DeleteProcThreadAttributeList(list) + t.Errorf("unable to update ProcThreadAttributeList: %v", err) + return + } + runtime.GC() + runtime.GC() + select { + case <-done: + t.Error("ProcThreadAttributeList was garbage collected unexpectedly") + default: + } + syscall.DeleteProcThreadAttributeList(list) + runtime.GC() + runtime.GC() + select { + case <-done: + case <-time.After(time.Second): + t.Error("ProcThreadAttributeList was not garbage collected after a second") + } +} diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index 384b5b4f2c..31fe7664c9 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -4,6 +4,8 @@ package syscall +import "unsafe" + const ( // Windows errors. ERROR_FILE_NOT_FOUND Errno = 2 @@ -491,7 +493,11 @@ type StartupInfo struct { } type _PROC_THREAD_ATTRIBUTE_LIST struct { - _ [1]byte + // This is of type unsafe.Pointer, not of type byte or uintptr, because + // the contents of it is mostly a list of pointers, and in most cases, + // that's a list of pointers to Go-allocated objects. In order to keep + // the GC from collecting these objects, we declare this as unsafe.Pointer. + _ [1]unsafe.Pointer } const ( diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index b08e6ac5c2..10d0f54e8c 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -1115,7 +1115,7 @@ func UnmapViewOfFile(addr uintptr) (err error) { return } -func updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value uintptr, size uintptr, prevvalue uintptr, returnedsize *uintptr) (err error) { +func updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) { r1, _, e1 := Syscall9(procUpdateProcThreadAttribute.Addr(), 7, uintptr(unsafe.Pointer(attrlist)), uintptr(flags), uintptr(attr), uintptr(value), uintptr(size), uintptr(prevvalue), uintptr(unsafe.Pointer(returnedsize)), 0, 0) if r1 == 0 { err = errnoErr(e1) -- GitLab From c015f76acb73990d4cb7fb056165b64d79b1b037 Mon Sep 17 00:00:00 2001 From: David Chase Date: Tue, 23 Feb 2021 20:00:31 -0500 Subject: [PATCH 0192/1298] cmd/compile: implement too-big-to-SSA struct passing in registers Added a test that exercises named results Change-Id: Ie228b68f4f846266595a95e0f65a6e4b8bf79635 Reviewed-on: https://go-review.googlesource.com/c/go/+/297029 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 59 +++++++++++-- src/cmd/compile/internal/ssa/expand_calls.go | 26 ++++-- src/cmd/compile/internal/ssagen/ssa.go | 27 +++--- test/abi/named_results.go | 91 ++++++++++++++++++++ test/abi/named_results.out | 13 +++ 5 files changed, 190 insertions(+), 26 deletions(-) create mode 100644 test/abi/named_results.go create mode 100644 test/abi/named_results.out diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index ffa709965c..3c07be62e0 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -118,12 +118,22 @@ func RegisterTypes(apa []ABIParamAssignment) []*types.Type { if len(pa.Registers) == 0 { continue } - rts = appendParamRegs(rts, pa.Type) + rts = appendParamTypes(rts, pa.Type) } return rts } -func appendParamRegs(rts []*types.Type, t *types.Type) []*types.Type { +func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) { + l := len(pa.Registers) + if l == 0 { + return nil, nil + } + typs := make([]*types.Type, 0, l) + offs := make([]int64, 0, l) + return appendParamTypes(typs, pa.Type), appendParamOffsets(offs, 0, pa.Type) +} + +func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type { if t.IsScalar() || t.IsPtrShaped() { if t.IsComplex() { c := types.FloatForComplex(t) @@ -146,25 +156,60 @@ func appendParamRegs(rts []*types.Type, t *types.Type) []*types.Type { switch typ { case types.TARRAY: for i := int64(0); i < t.Size(); i++ { // 0 gets no registers, plus future-proofing. - rts = appendParamRegs(rts, t.Elem()) + rts = appendParamTypes(rts, t.Elem()) } case types.TSTRUCT: for _, f := range t.FieldSlice() { if f.Type.Size() > 0 { // embedded zero-width types receive no registers - rts = appendParamRegs(rts, f.Type) + rts = appendParamTypes(rts, f.Type) } } case types.TSLICE: - return appendParamRegs(rts, synthSlice) + return appendParamTypes(rts, synthSlice) case types.TSTRING: - return appendParamRegs(rts, synthString) + return appendParamTypes(rts, synthString) case types.TINTER: - return appendParamRegs(rts, synthIface) + return appendParamTypes(rts, synthIface) } } return rts } +// appendParamOffsets appends the offset(s) of type t, starting from "at", +// to input offsets, and returns the longer slice. +func appendParamOffsets(offsets []int64, at int64, t *types.Type) []int64 { + at = align(at, t) + if t.IsScalar() || t.IsPtrShaped() { + if t.IsComplex() || int(t.Width) > types.RegSize { // complex and *int64 on 32-bit + s := t.Width / 2 + return append(offsets, at, at+s) + } else { + return append(offsets, at) + } + } else { + typ := t.Kind() + switch typ { + case types.TARRAY: + for i := int64(0); i < t.NumElem(); i++ { + offsets = appendParamOffsets(offsets, at, t.Elem()) + } + return offsets + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + offsets = appendParamOffsets(offsets, at, f.Type) + at += f.Type.Width + } + case types.TSLICE: + return appendParamOffsets(offsets, at, synthSlice) + case types.TSTRING: + return appendParamOffsets(offsets, at, synthString) + case types.TINTER: + return appendParamOffsets(offsets, at, synthIface) + } + } + return offsets +} + // SpillOffset returns the offset *within the spill area* for the parameter that "a" describes. // Registers will be spilled here; if a memory home is needed (for a pointer method e.g.) // then that will be the address. diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 6e14a90e79..fd8ae30caf 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -657,7 +657,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, case OpCopy: return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc) - case OpLoad: + case OpLoad, OpDereference: ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad) if ret != nil { return ret @@ -820,6 +820,9 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, } s := mem + if source.Op == OpDereference { + source.Op = OpLoad // For purposes of parameter passing expansion, a Dereference is a Load. + } if storeRc.hasRegs() { storeRc.addArg(source) } else { @@ -846,14 +849,11 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) { auxI := int64(i) aRegs := aux.RegsOfArg(auxI) aType := aux.TypeOfArg(auxI) - if a.Op == OpDereference { + if len(aRegs) == 0 && a.Op == OpDereference { aOffset := aux.OffsetOfArg(auxI) if a.MemoryArg() != m0 { x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString()) } - if len(aRegs) > 0 { - x.f.Fatalf("Not implemented yet, not-SSA-type %v passed in registers", aType) - } // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move // TODO(register args) this will be more complicated with registers in the picture. mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos) @@ -969,10 +969,7 @@ func expandCalls(f *Func) { auxOffset := int64(0) auxSize := aux.SizeOfResult(i) aRegs := aux.RegsOfResult(int64(j)) - if a.Op == OpDereference { - if len(aRegs) > 0 { - x.f.Fatalf("Not implemented yet, not-SSA-type %v returned in register", auxType) - } + if len(aRegs) == 0 && a.Op == OpDereference { // Avoid a self-move, and if one is detected try to remove the already-inserted VarDef for the assignment that won't happen. if dAddr, dMem := a.Args[0], a.Args[1]; dAddr.Op == OpLocalAddr && dAddr.Args[0].Op == OpSP && dAddr.Args[1] == dMem && dAddr.Aux == aux.results[i].Name { @@ -1392,3 +1389,14 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, } } } + +// argOpAndRegisterFor converts an abi register index into an ssa Op and corresponding +// arg register index. +// TODO could call this in at least two places earlier in this file. +func ArgOpAndRegisterFor(r abi.RegIndex, abiConfig *abi.ABIConfig) (Op, int64) { + i := abiConfig.FloatIndexFor(r) + if i >= 0 { // float PR + return OpArgFloatReg, i + } + return OpArgIntReg, int64(r) +} diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 9ee855343f..2a281860af 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -555,19 +555,26 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { } s.vars[n] = v s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself. - } else if !s.canSSAName(n) { // I.e., the address was taken. The type may or may not be okay. - // If the value will arrive in registers, - // AND if it can be SSA'd (if it cannot, panic for now), - // THEN - // (1) receive it as an OpArg (but do not store its name in the var table) - // (2) store it to its spill location, which is its address as well. + } else { // address was taken AND/OR too large for SSA paramAssignment := ssa.ParamAssignmentForArgName(s.f, n) if len(paramAssignment.Registers) > 0 { - if !TypeOK(n.Type()) { // TODO register args -- if v is not an SSA-able type, must decompose, here. - panic(fmt.Errorf("Arg in registers is too big to be SSA'd, need to implement decomposition, type=%v, n=%v", n.Type(), n)) + if TypeOK(n.Type()) { // SSA-able type, so address was taken -- receive value in OpArg, DO NOT bind to var, store immediately to memory. + v := s.newValue0A(ssa.OpArg, n.Type(), n) + s.store(n.Type(), s.decladdrs[n], v) + } else { // Too big for SSA. + // Brute force, and early, do a bunch of stores from registers + // TODO fix the nasty storeArgOrLoad recursion in ssa/expand_calls.go so this Just Works with store of a big Arg. + typs, offs := paramAssignment.RegisterTypesAndOffsets() + for i, t := range typs { + o := offs[i] + r := paramAssignment.Registers[i] + op, reg := ssa.ArgOpAndRegisterFor(r, s.f.ABISelf) + v := s.newValue0I(op, t, reg) + v.Aux = &ssa.AuxNameOffset{Name: n, Offset: o} + p := s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), o, s.decladdrs[n]) + s.store(t, p, v) + } } - v := s.newValue0A(ssa.OpArg, n.Type(), n) - s.store(n.Type(), s.decladdrs[n], v) } } } diff --git a/test/abi/named_results.go b/test/abi/named_results.go new file mode 100644 index 0000000000..eaaadb184f --- /dev/null +++ b/test/abi/named_results.go @@ -0,0 +1,91 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 ( + "fmt" +) + +var sink *string + +var y int + +//go:registerparams +//go:noinline +func F(a, b, c *int) (x int) { + x = *a + G(&x) + x += *b + G(&x) + x += *c + G(&x) + return +} + +//go:registerparams +//go:noinline +func G(x *int) { + y += *x + fmt.Println("y = ", y) +} + +//go:registerparams +//go:noinline +func X() { + *sink += " !!!!!!!!!!!!!!!" +} + +//go:registerparams +//go:noinline +func H(s, t string) (result string) { // result leaks to heap + result = "Aloha! " + s + " " + t + sink = &result + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +//go:registerparams +//go:noinline +func K(s, t string) (result string) { // result spills + result = "Aloha! " + s + " " + t + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z := H("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + + fmt.Println() + + y = K("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z = K("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + +} diff --git a/test/abi/named_results.out b/test/abi/named_results.out new file mode 100644 index 0000000000..02f12e806d --- /dev/null +++ b/test/abi/named_results.out @@ -0,0 +1,13 @@ +y = 1 +y = 6 +y = 27 +x = 21 +len(y) = 41 +y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!! +len(z) = 17 +z = Aloha! Hello Pal! + +len(y) = 25 +y = OKAY! Aloha! Hello World! +len(z) = 17 +z = Aloha! Hello Pal! -- GitLab From 9d3718e834fcf5b602b84539364606445cfc8a1a Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 4 Mar 2021 16:38:20 -0500 Subject: [PATCH 0193/1298] cmd/compile: remove I-saw-a-register-pragma chatter It is not multithreaded-compilation-safe, and also seems to cause problems on the noopt-builder. Change-Id: I52dbcd507d256990f1ec7c8040ec7b76595aae4f Reviewed-on: https://go-review.googlesource.com/c/go/+/298850 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssagen/ssa.go | 4 --- test/abi/regabipragma.dir/main.go | 36 -------------------------- test/abi/regabipragma.dir/tmp/foo.go | 19 -------------- test/abi/regabipragma.go | 13 ---------- test/abi/regabipragma.out | 6 ----- 5 files changed, 78 deletions(-) delete mode 100644 test/abi/regabipragma.dir/main.go delete mode 100644 test/abi/regabipragma.dir/tmp/foo.go delete mode 100644 test/abi/regabipragma.go delete mode 100644 test/abi/regabipragma.out diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 2a281860af..881fdcc8f4 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -230,7 +230,6 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) } a = abi1 - base.WarnfAt(fn.Pos(), "declared function %v has register params", fn) } return a } @@ -4850,9 +4849,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val inRegistersImported := fn.Pragma()&ir.RegisterParams != 0 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0 inRegisters = inRegistersImported || inRegistersSamePackage - if inRegisters { - s.f.Warnl(n.Pos(), "called function %v has register params", callee) - } break } closure = s.expr(fn) diff --git a/test/abi/regabipragma.dir/main.go b/test/abi/regabipragma.dir/main.go deleted file mode 100644 index d663337a10..0000000000 --- a/test/abi/regabipragma.dir/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021 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 ( - "fmt" - "regabipragma.dir/tmp" -) - -type S string - -//go:noinline -func (s S) ff(t string) string { - return string(s) + " " + t -} - -//go:noinline -//go:registerparams -func f(s,t string) string { // ERROR "Declared function f has register params" - return s + " " + t -} - -func check(s string) { - if s != "Hello world!" { - fmt.Printf("FAIL, wanted 'Hello world!' but got '%s'\n", s) - } -} - -func main() { - check(f("Hello", "world!")) // ERROR "Called function ...f has register params" - check(tmp.F("Hello", "world!")) // ERROR "Called function regabipragma.dir/tmp.F has register params" - check(S("Hello").ff("world!")) - check(tmp.S("Hello").FF("world!")) -} diff --git a/test/abi/regabipragma.dir/tmp/foo.go b/test/abi/regabipragma.dir/tmp/foo.go deleted file mode 100644 index cff989bbcd..0000000000 --- a/test/abi/regabipragma.dir/tmp/foo.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 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 tmp - - -type S string - -//go:noinline -func (s S) FF(t string) string { - return string(s) + " " + t -} - -//go:noinline -//go:registerparams -func F(s,t string) string { - return s + " " + t -} diff --git a/test/abi/regabipragma.go b/test/abi/regabipragma.go deleted file mode 100644 index 070b3110d6..0000000000 --- a/test/abi/regabipragma.go +++ /dev/null @@ -1,13 +0,0 @@ -// skip -// runindir -gcflags=-c=1 -//go:build !windows -// +build !windows - -// Copyright 2021 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. - -// TODO(register args) Temporarily disabled now that register abi info is flowing halfway through the compiler. -// TODO(register args) May delete or adapt this test once regabi is the default - -package ignore diff --git a/test/abi/regabipragma.out b/test/abi/regabipragma.out deleted file mode 100644 index 321b1adfcc..0000000000 --- a/test/abi/regabipragma.out +++ /dev/null @@ -1,6 +0,0 @@ -# regabipragma.dir/tmp -tmp/foo.go:17:6: declared function F has register params -# regabipragma.dir -./main.go:21:6: declared function f has register params -./main.go:32:9: called function f has register params -./main.go:33:13: called function tmp.F has register params -- GitLab From a99ff24a26939f30440dd0f06dce426ed5e638ee Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 3 Mar 2021 18:33:45 -0800 Subject: [PATCH 0194/1298] cmd/compile/internal/syntax: print type parameters and type lists types2 uses the syntax printer to print expressions (for tracing or error messages), so we need to (at least) print type lists in interfaces. While at it, also implement the printing of type parameter lists. Fixes #44766. Change-Id: I36a4a7152d9bef7251af264b5c7890aca88d8dc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/298549 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/syntax/printer.go | 57 ++++++++++++++----- .../compile/internal/syntax/printer_test.go | 37 +++++++++++- 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/syntax/printer.go b/src/cmd/compile/internal/syntax/printer.go index 9109ce2363..e557f5d924 100644 --- a/src/cmd/compile/internal/syntax/printer.go +++ b/src/cmd/compile/internal/syntax/printer.go @@ -481,10 +481,10 @@ func (p *printer) printRawNode(n Node) { if len(n.FieldList) > 0 { if p.linebreaks { p.print(newline, indent) - p.printFieldList(n.FieldList, n.TagList) + p.printFieldList(n.FieldList, n.TagList, _Semi) p.print(outdent, newline) } else { - p.printFieldList(n.FieldList, n.TagList) + p.printFieldList(n.FieldList, n.TagList, _Semi) } } p.print(_Rbrace) @@ -494,20 +494,40 @@ func (p *printer) printRawNode(n Node) { p.printSignature(n) case *InterfaceType: + // separate type list and method list + var types []Expr + var methods []*Field + for _, f := range n.MethodList { + if f.Name != nil && f.Name.Value == "type" { + types = append(types, f.Type) + } else { + // method or embedded interface + methods = append(methods, f) + } + } + + multiLine := len(n.MethodList) > 0 && p.linebreaks p.print(_Interface) - if len(n.MethodList) > 0 && p.linebreaks { + if multiLine { p.print(blank) } p.print(_Lbrace) - if len(n.MethodList) > 0 { - if p.linebreaks { - p.print(newline, indent) - p.printMethodList(n.MethodList) - p.print(outdent, newline) - } else { - p.printMethodList(n.MethodList) + if multiLine { + p.print(newline, indent) + } + if len(types) > 0 { + p.print(_Type, blank) + p.printExprList(types) + if len(methods) > 0 { + p.print(_Semi, blank) } } + if len(methods) > 0 { + p.printMethodList(methods) + } + if multiLine { + p.print(outdent, newline) + } p.print(_Rbrace) case *MapType: @@ -667,7 +687,13 @@ func (p *printer) printRawNode(n Node) { if n.Group == nil { p.print(_Type, blank) } - p.print(n.Name, blank) + p.print(n.Name) + if n.TParamList != nil { + p.print(_Lbrack) + p.printFieldList(n.TParamList, nil, _Comma) + p.print(_Rbrack) + } + p.print(blank) if n.Alias { p.print(_Assign, blank) } @@ -696,6 +722,11 @@ func (p *printer) printRawNode(n Node) { p.print(_Rparen, blank) } p.print(n.Name) + if n.TParamList != nil { + p.print(_Lbrack) + p.printFieldList(n.TParamList, nil, _Comma) + p.print(_Rbrack) + } p.printSignature(n.Type) if n.Body != nil { p.print(blank, n.Body) @@ -746,14 +777,14 @@ func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) { } } -func (p *printer) printFieldList(fields []*Field, tags []*BasicLit) { +func (p *printer) printFieldList(fields []*Field, tags []*BasicLit, sep token) { i0 := 0 var typ Expr for i, f := range fields { if f.Name == nil || f.Type != typ { if i0 < i { p.printFields(fields, tags, i0, i) - p.print(_Semi, newline) + p.print(sep, newline) i0 = i } typ = f.Type diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go index bcae815a46..4890327595 100644 --- a/src/cmd/compile/internal/syntax/printer_test.go +++ b/src/cmd/compile/internal/syntax/printer_test.go @@ -61,6 +61,21 @@ var stringTests = []string{ "package p", "package p; type _ int; type T1 = struct{}; type ( _ *struct{}; T2 = float32 )", + // generic type declarations + "package p; type _[T any] struct{}", + "package p; type _[A, B, C interface{m()}] struct{}", + "package p; type _[T any, A, B, C interface{m()}, X, Y, Z interface{type int}] struct{}", + + // generic function declarations + "package p; func _[T any]()", + "package p; func _[A, B, C interface{m()}]()", + "package p; func _[T any, A, B, C interface{m()}, X, Y, Z interface{type int}]()", + + // methods with generic receiver types + "package p; func (R[T]) _()", + "package p; func (*R[A, B, C]) _()", + "package p; func (_ *R[A, B, C]) _()", + // channels "package p; type _ chan chan int", "package p; type _ chan (<-chan int)", @@ -79,7 +94,7 @@ var stringTests = []string{ func TestPrintString(t *testing.T) { for _, want := range stringTests { - ast, err := Parse(nil, strings.NewReader(want), nil, nil, 0) + ast, err := Parse(nil, strings.NewReader(want), nil, nil, AllowGenerics) if err != nil { t.Error(err) continue @@ -116,6 +131,24 @@ var exprTests = [][2]string{ {"func(x int) complex128 { return 0 }", "func(x int) complex128 {…}"}, {"[]int{1, 2, 3}", "[]int{…}"}, + // type expressions + dup("[1 << 10]byte"), + dup("[]int"), + dup("*int"), + dup("struct{x int}"), + dup("func()"), + dup("func(int, float32) string"), + dup("interface{m()}"), + dup("interface{m() string; n(x int)}"), + dup("interface{type int}"), + dup("interface{type int, float64, string}"), + dup("interface{type int; m()}"), + dup("interface{type int, float64, string; m() string; n(x int)}"), + dup("map[string]int"), + dup("chan E"), + dup("<-chan E"), + dup("chan<- E"), + // non-type expressions dup("(x)"), dup("x.f"), @@ -172,7 +205,7 @@ var exprTests = [][2]string{ func TestShortString(t *testing.T) { for _, test := range exprTests { src := "package p; var _ = " + test[0] - ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0) + ast, err := Parse(nil, strings.NewReader(src), nil, nil, AllowGenerics) if err != nil { t.Errorf("%s: %s", test[0], err) continue -- GitLab From b87e9b9f68f1eb0d685fd250b3b47495710e0059 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Thu, 4 Mar 2021 10:35:17 -0500 Subject: [PATCH 0195/1298] cmd/go: clarify errors for commands run outside a module The new error message tells the user what was wrong (no go.mod found) and directs them to 'go help modules', which links to tutorials. Fixes #44745 Change-Id: I98f31fec4a8757eb1792b45491519da4c552cb0f Reviewed-on: https://go-review.googlesource.com/c/go/+/298650 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/modget/query.go | 2 +- src/cmd/go/internal/modload/import.go | 18 ++++--- src/cmd/go/internal/modload/init.go | 6 ++- src/cmd/go/internal/modload/list.go | 2 +- src/cmd/go/internal/run/run.go | 20 +------ .../go/testdata/script/mod_convert_dep.txt | 2 +- src/cmd/go/testdata/script/mod_find.txt | 2 +- src/cmd/go/testdata/script/mod_outside.txt | 52 +++++++++---------- src/go/build/build_test.go | 2 +- 9 files changed, 47 insertions(+), 59 deletions(-) diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go index d8364c8c0d..1a5a60f7eb 100644 --- a/src/cmd/go/internal/modget/query.go +++ b/src/cmd/go/internal/modget/query.go @@ -186,7 +186,7 @@ func (q *query) validate() error { if q.pattern == "all" { // If there is no main module, "all" is not meaningful. if !modload.HasModRoot() { - return fmt.Errorf(`cannot match "all": working directory is not part of a module`) + return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot) } if !versionOkForMainModule(q.version) { // TODO(bcmills): "all@none" seems like a totally reasonable way to diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 182429aee4..995641c9f1 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string { if e.isStd { return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path)) } - if e.QueryErr != nil { + if e.QueryErr != nil && e.QueryErr != ErrNoModRoot { return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr) } if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) { @@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string { return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg) } - suggestion := "" - if !HasModRoot() { - suggestion = ": working directory is not part of a module" - } else { - suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path) + message := fmt.Sprintf("no required module provides package %s", e.Path) + if e.QueryErr != nil { + return fmt.Sprintf("%s: %v", message, e.QueryErr) } - return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion) + return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path) } if e.newMissingVersion != "" { @@ -318,7 +316,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve return mods[0], dirs[0], nil } - return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd} + var queryErr error + if !HasModRoot() { + queryErr = ErrNoModRoot + } + return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd} } // queryImport attempts to locate a module that can be added to the current diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 4de5ac9303..8ec1c8681a 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -177,7 +177,7 @@ func Init() { base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.") } if RootMode == NeedRoot { - base.Fatalf("go: cannot find main module; see 'go help modules'") + base.Fatalf("go: %v", ErrNoModRoot) } if !mustUseModules { // GO111MODULE is 'auto', and we can't find a module root. @@ -338,9 +338,11 @@ func die() { } base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd) } - base.Fatalf("go: cannot find main module; see 'go help modules'") + base.Fatalf("go: %v", ErrNoModRoot) } +var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'") + // LoadModFile sets Target and, if there is a main module, parses the initial // build list from its go.mod file. // diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go index 6dba6bea22..c7ef8c9fb7 100644 --- a/src/cmd/go/internal/modload/list.go +++ b/src/cmd/go/internal/modload/list.go @@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted base.Fatalf("go: cannot use relative path %s to specify module", arg) } if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) { - base.Fatalf("go: cannot match %q: working directory is not part of a module", arg) + base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) } if i := strings.Index(arg, "@"); i >= 0 { path := arg[:i] diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go index 99578b244c..666b1a0e56 100644 --- a/src/cmd/go/internal/run/run.go +++ b/src/cmd/go/internal/run/run.go @@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) { base.Fatalf("go run: no go files listed") } cmdArgs := args[i:] - if p.Error != nil { - base.Fatalf("%s", p.Error) - } + load.CheckPackageErrors([]*load.Package{p}) - p.Internal.OmitDebug = true - if len(p.DepsErrors) > 0 { - // Since these are errors in dependencies, - // the same error might show up multiple times, - // once in each package that depends on it. - // Only print each once. - printed := map[*load.PackageError]bool{} - for _, err := range p.DepsErrors { - if !printed[err] { - printed[err] = true - base.Errorf("%s", err) - } - } - } - base.ExitIfErrors() if p.Name != "main" { base.Fatalf("go run: cannot run non-main package") } + p.Internal.OmitDebug = true p.Target = "" // must build - not up to date if p.Internal.CmdlineFiles { //set executable name if go file is given as cmd-argument diff --git a/src/cmd/go/testdata/script/mod_convert_dep.txt b/src/cmd/go/testdata/script/mod_convert_dep.txt index ad22aca5be..875a836fd2 100644 --- a/src/cmd/go/testdata/script/mod_convert_dep.txt +++ b/src/cmd/go/testdata/script/mod_convert_dep.txt @@ -18,7 +18,7 @@ stdout '^m$' # Test that we ignore directories when trying to find alternate config files. cd $WORK/gopkgdir/x ! go list . -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! stderr 'Gopkg.lock' -- $WORK/test/Gopkg.lock -- diff --git a/src/cmd/go/testdata/script/mod_find.txt b/src/cmd/go/testdata/script/mod_find.txt index 9468acfd33..1e01973ff4 100644 --- a/src/cmd/go/testdata/script/mod_find.txt +++ b/src/cmd/go/testdata/script/mod_find.txt @@ -49,7 +49,7 @@ rm go.mod # Test that we ignore directories when trying to find go.mod. cd $WORK/gomoddir ! go list . -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' [!symlink] stop diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt index 7b45f1a209..9d4c22c77b 100644 --- a/src/cmd/go/testdata/script/mod_outside.txt +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -12,13 +12,13 @@ stdout 'NUL|/dev/null' # 'go list' without arguments implicitly operates on the current directory, # which is not in a module. ! go list -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' go list -m stdout '^command-line-arguments$' # 'go list' in the working directory should fail even if there is a a 'package # main' present: without a main module, we do not know its package path. ! go list ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list all' lists the transitive import graph of the main module, # which is empty if there is no main module. @@ -41,7 +41,7 @@ stdout 'command-line-arguments' # 'go list' on a package from a module should fail. ! go list example.com/printversion -stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list -m' with an explicit version should resolve that version. @@ -54,19 +54,19 @@ stdout 'v1.0.0\s+v1.0.1\s+v1.1.0' # 'go list -m all' should fail. "all" is not meaningful outside of a module. ! go list -m all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list -m all' should also fail. ! go list -m example.com/printversion@v1.0.0 all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! stdout 'example.com/version' # 'go list -m' with wildcards should fail. Wildcards match modules in the # build list, so they aren't meaningful outside a module. ! go list -m ... -stderr 'go: cannot match "...": working directory is not part of a module' +stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go list -m rsc.io/quote/... -stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module' +stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go clean' should skip the current directory if it isn't in a module. @@ -76,20 +76,20 @@ go clean -n # 'go mod graph' should fail, since there's no module graph. ! go mod graph -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod why' should fail, since there is no main module to depend on anything. ! go mod why -m example.com/version -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail: # there is no go.mod file to edit. ! go mod tidy -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go mod edit -fmt -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go mod edit -require example.com/version@v1.0.0 -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod download' without arguments should report an error. @@ -104,33 +104,33 @@ exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip # 'go mod download all' should fail. "all" is not meaningful outside of a module. ! go mod download all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod vendor' should fail: it starts by clearing the existing vendor # directory, and we don't know where that is. ! go mod vendor -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod verify' should fail: we have no modules to verify. ! go mod verify -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get' without arguments implicitly operates on the main module, and thus # should fail. ! go get -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go get -u -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go get -u ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get -u all' upgrades the transitive import graph of the main module, # which is empty. ! go get -u all -stderr 'go get: cannot match "all": working directory is not part of a module' +stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get' should check the proposed module graph for consistency, # even though we won't write it anywhere. @@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/version@v1.0.0 # 'go build' without arguments implicitly operates on the current directory, and should fail. cd needmod ! go build -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' cd .. # 'go build' of a non-module directory should fail too. ! go build ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go build' of source files should fail if they import anything outside std. ! go build -n ./needmod/needmod.go -stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go build' of source files should succeed if they do not import anything outside std. go build -n -o ignore ./stdonly/stdonly.go @@ -179,7 +179,7 @@ go doc fmt # 'go doc' should fail for a package path outside a module. ! go doc example.com/version -stderr 'doc: no required module provides package example.com/version: working directory is not part of a module' +stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go install' with a version should succeed if all constraints are met. # See mod_install_pkg_version. @@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu # 'go install' should fail if a source file imports a package that must be # resolved to a module. ! go install ./needmod/needmod.go -stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module' +stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go install' should succeed with a package in GOROOT. go install cmd/addr2line @@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with' # 'go run' should fail if a package argument must be resolved to a module. ! go run example.com/printversion -stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go run' should fail if a source file imports a package that must be # resolved to a module. ! go run ./needmod/needmod.go -stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go fmt' should be able to format files outside of a module. diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 0762a150eb..6529b6e47e 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -644,7 +644,7 @@ func TestImportPackageOutsideModule(t *testing.T) { ctxt.GOPATH = gopath ctxt.Dir = filepath.Join(gopath, "src/example.com/p") - want := "working directory is not part of a module" + want := "go.mod file not found in current directory or any parent directory" if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil { t.Fatal("importing package when no go.mod is present succeeded unexpectedly") } else if errStr := err.Error(); !strings.Contains(errStr, want) { -- GitLab From 56d52e661114be60fb1893b034ac0c5976b622af Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Thu, 4 Mar 2021 11:50:31 -0500 Subject: [PATCH 0196/1298] cmd/go: don't report missing std import errors for tidy and vendor 'go mod tidy' and 'go mod vendor' normally report errors when a package can't be imported, even if the import appears in a file that wouldn't be compiled by the current version of Go. These errors are common for packages introduced in higher versions of Go, like "embed" in 1.16. This change causes 'go mod tidy' and 'go mod vendor' to ignore missing package errors if the import path appears to come from the standard library because it lacks a dot in the first path element. Fixes #44557 Updates #27063 Change-Id: I61d6443e77ab95fd8c0d1514f57ef4c8885a77cc Reviewed-on: https://go-review.googlesource.com/c/go/+/298749 Trust: Jay Conrod Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/modcmd/tidy.go | 1 + src/cmd/go/internal/modcmd/vendor.go | 1 + src/cmd/go/internal/modload/load.go | 13 ++++++++++++- src/cmd/go/testdata/script/mod_tidy_error.txt | 4 ++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go index e7e63e6533..34ff86ff18 100644 --- a/src/cmd/go/internal/modcmd/tidy.go +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -67,6 +67,7 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) { ResolveMissingImports: true, LoadTests: true, AllowErrors: tidyE, + SilenceMissingStdImports: true, }, "all") modload.TidyBuildList() diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index 2cd683b75c..6ebc18dcd8 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -69,6 +69,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) { ResolveMissingImports: true, UseVendorAll: true, AllowErrors: vendorE, + SilenceMissingStdImports: true, } _, pkgs := modload.LoadPackages(ctx, loadOpts, "all") diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 0dba49e40e..2e62a7659f 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -175,6 +175,12 @@ type PackageOpts struct { // that occur while loading packages. SilenceErrors implies AllowErrors. SilenceErrors bool + // SilenceMissingStdImports indicates that LoadPackages should not print + // errors or terminate the process if an imported package is missing, and the + // import path looks like it might be in the standard library (perhaps in a + // future version). + SilenceMissingStdImports bool + // SilenceUnmatchedWarnings suppresses the warnings normally emitted for // patterns that did not match any packages. SilenceUnmatchedWarnings bool @@ -292,8 +298,13 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma sumErr.importerIsTest = importer.testOf != nil } } + silence := opts.SilenceErrors + if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) && + stdErr.isStd && opts.SilenceMissingStdImports { + silence = true + } - if !opts.SilenceErrors { + if !silence { if opts.AllowErrors { fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err) } else { diff --git a/src/cmd/go/testdata/script/mod_tidy_error.txt b/src/cmd/go/testdata/script/mod_tidy_error.txt index b6c24ceaf7..395537b1a7 100644 --- a/src/cmd/go/testdata/script/mod_tidy_error.txt +++ b/src/cmd/go/testdata/script/mod_tidy_error.txt @@ -4,12 +4,12 @@ env GO111MODULE=on # 'go mod tidy' and 'go mod vendor' should not hide loading errors. ! go mod tidy -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' ! go mod vendor -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' -- GitLab From 5c5552c5bab55c7233cc0cc105876a982ec25b74 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 24 Feb 2021 12:58:01 -0500 Subject: [PATCH 0197/1298] cmd/compile: add register abi tests Change-Id: I4b2b62a8eb1c4bf47f552214127d4ed5710af196 Reviewed-on: https://go-review.googlesource.com/c/go/+/297030 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- test/abi/f_ret_z_not.go | 6 ++ test/abi/many_int_input.go | 3 + test/abi/many_intstar_input.go | 45 ++++++++++++++ test/abi/many_intstar_input.out | 3 + test/abi/more_intstar_input.go | 44 ++++++++++++++ test/abi/more_intstar_input.out | 2 + test/abi/named_return_stuff.go | 94 ++++++++++++++++++++++++++++++ test/abi/named_return_stuff.out | 13 +++++ test/abi/return_stuff.go | 38 ++++++++++++ test/abi/return_stuff.out | 3 + test/abi/struct_3_string_input.go | 40 +++++++++++++ test/abi/struct_3_string_input.out | 0 test/abi/uglyfib.go | 3 + 13 files changed, 294 insertions(+) create mode 100644 test/abi/many_intstar_input.go create mode 100644 test/abi/many_intstar_input.out create mode 100644 test/abi/more_intstar_input.go create mode 100644 test/abi/more_intstar_input.out create mode 100644 test/abi/named_return_stuff.go create mode 100644 test/abi/named_return_stuff.out create mode 100644 test/abi/return_stuff.go create mode 100644 test/abi/return_stuff.out create mode 100644 test/abi/struct_3_string_input.go create mode 100644 test/abi/struct_3_string_input.out diff --git a/test/abi/f_ret_z_not.go b/test/abi/f_ret_z_not.go index d890223ff7..63d6c7918f 100644 --- a/test/abi/f_ret_z_not.go +++ b/test/abi/f_ret_z_not.go @@ -1,9 +1,15 @@ // run +//go:build !wasm +// +build !wasm + // Copyright 2021 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. +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + package main import "fmt" diff --git a/test/abi/many_int_input.go b/test/abi/many_int_input.go index 6c3332f842..8fda937932 100644 --- a/test/abi/many_int_input.go +++ b/test/abi/many_int_input.go @@ -7,6 +7,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + package main import ( diff --git a/test/abi/many_intstar_input.go b/test/abi/many_intstar_input.go new file mode 100644 index 0000000000..b209c801ba --- /dev/null +++ b/test/abi/many_intstar_input.go @@ -0,0 +1,45 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink int = 3 + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f *int) { + G(f, e, d, c, b, a) + sink += *a // *a == 6 after swapping in G +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f *int) { + var scratch [1000 * 100]int + scratch[*a] = *f // scratch[6] = 1 + fmt.Println(*a, *b, *c, *d, *e, *f) // Forces it to spill b + sink = scratch[*b+1] // scratch[5+1] == 1 + *f, *a = *a, *f + *e, *b = *b, *e + *d, *c = *c, *d +} + +func main() { + a, b, c, d, e, f := 1, 2, 3, 4, 5, 6 + F(&a, &b, &c, &d, &e, &f) + fmt.Println(a, b, c, d, e, f) + fmt.Println(sink) +} diff --git a/test/abi/many_intstar_input.out b/test/abi/many_intstar_input.out new file mode 100644 index 0000000000..0a37ccbec7 --- /dev/null +++ b/test/abi/many_intstar_input.out @@ -0,0 +1,3 @@ +6 5 4 3 2 1 +6 5 4 3 2 1 +7 diff --git a/test/abi/more_intstar_input.go b/test/abi/more_intstar_input.go new file mode 100644 index 0000000000..f0a48fbdc2 --- /dev/null +++ b/test/abi/more_intstar_input.go @@ -0,0 +1,44 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink int + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f, g, h, i, j, k, l, m *int) { + G(m, l, k, j, i, h, g, f, e, d, c, b, a) + // did the pointers get properly updated? + sink = *a + *m +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f, g, h, i, j, k, l, m *int) { + // Do not reference the parameters + var scratch [1000 * 100]int + I := *c - *e - *l // zero. + scratch[I] = *d + fmt.Println("Got this far!") + sink += scratch[0] +} + +func main() { + a, b, c, d, e, f, g, h, i, j, k, l, m := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 + F(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m) + fmt.Printf("Sink = %d\n", sink-7) +} diff --git a/test/abi/more_intstar_input.out b/test/abi/more_intstar_input.out new file mode 100644 index 0000000000..2ab84bfa8c --- /dev/null +++ b/test/abi/more_intstar_input.out @@ -0,0 +1,2 @@ +Got this far! +Sink = 7 diff --git a/test/abi/named_return_stuff.go b/test/abi/named_return_stuff.go new file mode 100644 index 0000000000..faa0221a3c --- /dev/null +++ b/test/abi/named_return_stuff.go @@ -0,0 +1,94 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +var y int + +//go:registerparams +//go:noinline +func F(a, b, c *int) (x int) { + x = *a + G(&x) + x += *b + G(&x) + x += *c + G(&x) + return +} + +//go:registerparams +//go:noinline +func G(x *int) { + y += *x + fmt.Println("y = ", y) +} + +//go:registerparams +//go:noinline +func X() { + *sink += " !!!!!!!!!!!!!!!" +} + +//go:registerparams +//go:noinline +func H(s, t string) (result string) { // result leaks to heap + result = "Aloha! " + s + " " + t + sink = &result + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +//go:registerparams +//go:noinline +func K(s, t string) (result string) { // result spills + result = "Aloha! " + s + " " + t + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z := H("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + + fmt.Println() + + y = K("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z = K("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + +} diff --git a/test/abi/named_return_stuff.out b/test/abi/named_return_stuff.out new file mode 100644 index 0000000000..02f12e806d --- /dev/null +++ b/test/abi/named_return_stuff.out @@ -0,0 +1,13 @@ +y = 1 +y = 6 +y = 27 +x = 21 +len(y) = 41 +y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!! +len(z) = 17 +z = Aloha! Hello Pal! + +len(y) = 25 +y = OKAY! Aloha! Hello World! +len(z) = 17 +z = Aloha! Hello Pal! diff --git a/test/abi/return_stuff.go b/test/abi/return_stuff.go new file mode 100644 index 0000000000..130d8be5c5 --- /dev/null +++ b/test/abi/return_stuff.go @@ -0,0 +1,38 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +//go:registerparams +//go:noinline +func F(a, b, c *int) int { + return *a + *b + *c +} + +//go:registerparams +//go:noinline +func H(s, t string) string { + return s + " " + t +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) +} diff --git a/test/abi/return_stuff.out b/test/abi/return_stuff.out new file mode 100644 index 0000000000..5f519d7b99 --- /dev/null +++ b/test/abi/return_stuff.out @@ -0,0 +1,3 @@ +x = 21 +len(y) = 12 +y = Hello World! diff --git a/test/abi/struct_3_string_input.go b/test/abi/struct_3_string_input.go new file mode 100644 index 0000000000..54a8b38af9 --- /dev/null +++ b/test/abi/struct_3_string_input.go @@ -0,0 +1,40 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type toobig struct { + a, b, c string +} + +//go:registerparams +//go:noinline +func H(x toobig) string { + return x.a + " " + x.b + " " + x.c +} + +func main() { + s := H(toobig{"Hello", "there,", "World"}) + gotVsWant(s, "Hello there, World") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/struct_3_string_input.out b/test/abi/struct_3_string_input.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/abi/uglyfib.go b/test/abi/uglyfib.go index bde3548bee..b8e8739f30 100644 --- a/test/abi/uglyfib.go +++ b/test/abi/uglyfib.go @@ -7,6 +7,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + package main import "fmt" -- GitLab From d6504b80973a22edbb5045e98c53901776101d18 Mon Sep 17 00:00:00 2001 From: David Chase Date: Sat, 27 Feb 2021 17:11:36 -0500 Subject: [PATCH 0198/1298] cmd/compile: tweak offset-generator to elide more +0 offsets this caused a problem in write barrier code when a spurious zero-offset prevented a write barrier elision. removed cache after instrumenting it and discovering zero safe hits (one value must dominate the other, else unsafe). Change-Id: I42dfdb4d38ebfe158b13e766a7fabfc514d773f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/297349 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 42 ++++++++------------ 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index fd8ae30caf..03b2a98fce 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -20,12 +20,6 @@ type selKey struct { typ *types.Type } -type offsetKey struct { - from *Value - offset int64 - pt *types.Type -} - type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1. func isBlockMultiValueExit(b *Block) bool { @@ -194,8 +188,7 @@ type expandState struct { sdom SparseTree commonSelectors map[selKey]*Value // used to de-dupe selectors commonArgs map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg - offsets map[offsetKey]*Value - memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. + memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. } // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target @@ -223,9 +216,16 @@ func (x *expandState) isAlreadyExpandedAggregateType(t *types.Type) bool { // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP // TODO should also optimize offsets from SB? -func (x *expandState) offsetFrom(from *Value, offset int64, pt *types.Type) *Value { - if offset == 0 && from.Type == pt { // this is not actually likely - return from +func (x *expandState) offsetFrom(b *Block, from *Value, offset int64, pt *types.Type) *Value { + ft := from.Type + if offset == 0 { + if ft == pt { + return from + } + // This captures common, (apparently) safe cases. The unsafe cases involve ft == uintptr + if (ft.IsPtr() || ft.IsUnsafePtr()) && pt.IsPtr() { + return from + } } // Simplify, canonicalize for from.Op == OpOffPtr { @@ -235,14 +235,7 @@ func (x *expandState) offsetFrom(from *Value, offset int64, pt *types.Type) *Val if from == x.sp { return x.f.ConstOffPtrSP(pt, offset, x.sp) } - key := offsetKey{from, offset, pt} - v := x.offsets[key] - if v != nil { - return v - } - v = from.Block.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from) - x.offsets[key] = v - return v + return b.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from) } // splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates. @@ -426,7 +419,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, leaf.copyOf(w) } } else { - off := x.offsetFrom(x.sp, offset+aux.OffsetOfResult(which), pt) + off := x.offsetFrom(x.f.Entry, x.sp, offset+aux.OffsetOfResult(which), pt) if leaf.Block == call.Block { leaf.reset(OpLoad) leaf.SetArgs2(off, call) @@ -531,7 +524,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, size int64, typ *types.Type, pos src.XPos) *Value { source := a.Args[0] - dst := x.offsetFrom(base, offset, source.Type) + dst := x.offsetFrom(b, base, offset, source.Type) if a.Uses == 1 && a.Block == b { a.reset(OpMove) a.Pos = pos @@ -624,7 +617,7 @@ func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t * // storeOneLoad creates a decomposed (one step) load that is then stored. func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - from := x.offsetFrom(source.Args[0], offArg, types.NewPtr(t)) + from := x.offsetFrom(b, source.Args[0], offArg, types.NewPtr(t)) w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem) return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) } @@ -826,7 +819,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, if storeRc.hasRegs() { storeRc.addArg(source) } else { - dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t)) + dst := x.offsetFrom(b, storeRc.storeDest, offset, types.NewPtr(t)) s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) } if x.debug { @@ -904,7 +897,6 @@ func expandCalls(f *Func) { namedSelects: make(map[*Value][]namedVal), sdom: f.Sdom(), commonArgs: make(map[selKey]*Value), - offsets: make(map[offsetKey]*Value), memForCall: make(map[ID]*Value), } @@ -1098,7 +1090,7 @@ func expandCalls(f *Func) { which := v.AuxInt aux := call.Aux.(*AuxCall) pt := v.Type - off := x.offsetFrom(x.sp, aux.OffsetOfResult(which), pt) + off := x.offsetFrom(x.f.Entry, x.sp, aux.OffsetOfResult(which), pt) v.copyOf(off) } } -- GitLab From d891ebdce1ac2c72e1d923c24f5a65ec14ba7cf8 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 26 Feb 2021 14:27:59 -0500 Subject: [PATCH 0199/1298] cmd/compile: return (and receive) medium-large results includes three tests Change-Id: I33ac0cfe35085d4b6ad2775abcaa3d7d6527b49f Reviewed-on: https://go-review.googlesource.com/c/go/+/297031 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 80 +++++++++--------- src/cmd/compile/internal/ssa/op.go | 9 ++- src/cmd/compile/internal/ssagen/ssa.go | 85 +++++++++++++------- test/abi/double_nested_addressed_struct.go | 62 ++++++++++++++ test/abi/double_nested_struct.go | 55 +++++++++++++ test/abi/too_big_to_ssa.go | 47 +++++++++++ test/abi/too_big_to_ssa.out | 2 + 7 files changed, 264 insertions(+), 76 deletions(-) create mode 100644 test/abi/double_nested_addressed_struct.go create mode 100644 test/abi/double_nested_struct.go create mode 100644 test/abi/too_big_to_ssa.go create mode 100644 test/abi/too_big_to_ssa.out diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 03b2a98fce..df135853fe 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -248,7 +248,7 @@ func (x *expandState) splitSlots(ls []LocalSlot, sfx string, offset int64, ty *t } // prAssignForArg returns the ABIParamAssignment for v, assumed to be an OpArg. -func (x *expandState) prAssignForArg(v *Value) abi.ABIParamAssignment { +func (x *expandState) prAssignForArg(v *Value) *abi.ABIParamAssignment { if v.Op != OpArg { panic(badVal("Wanted OpArg, instead saw", v)) } @@ -256,13 +256,12 @@ func (x *expandState) prAssignForArg(v *Value) abi.ABIParamAssignment { } // ParamAssignmentForArgName returns the ABIParamAssignment for f's arg with matching name. -func ParamAssignmentForArgName(f *Func, name *ir.Name) abi.ABIParamAssignment { +func ParamAssignmentForArgName(f *Func, name *ir.Name) *abi.ABIParamAssignment { abiInfo := f.OwnAux.abiInfo - // This is unfortunate, but apparently the only way. - // TODO after register args stabilize, find a better way - for _, a := range abiInfo.InParams() { + ip := abiInfo.InParams() + for i, a := range ip { if a.Name == name { - return a + return &ip[i] } } panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, abiInfo.InParams())) @@ -646,6 +645,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String()) } + // Start with Opcodes that can be disassembled switch source.Op { case OpCopy: return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc) @@ -1025,14 +1025,9 @@ func expandCalls(f *Func) { t = tSrc } } - if iAEATt { - if x.debug { - fmt.Printf("Splitting store %s\n", v.LongString()) - } - dst, mem := v.Args[0], v.Args[2] - mem = x.storeArgOrLoad(v.Pos, b, source, mem, t, 0, 0, registerCursor{storeDest: dst}) - v.copyOf(mem) - } + dst, mem := v.Args[0], v.Args[2] + mem = x.storeArgOrLoad(v.Pos, b, source, mem, t, 0, 0, registerCursor{storeDest: dst}) + v.copyOf(mem) } } } @@ -1322,14 +1317,12 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, } pa := x.prAssignForArg(baseArg) - switch len(pa.Registers) { - case 0: + if len(pa.Registers) == 0 { // Arg is on stack frameOff := baseArg.Aux.(*ir.Name).FrameOffset() if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) { panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s", pa.Offset(), frameOff, baseArg.LongString())) } - aux := baseArg.Aux auxInt := baseArg.AuxInt + offset if toReplace != nil && toReplace.Block == baseArg.Block { @@ -1350,35 +1343,34 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, } return w } - - default: - r := pa.Registers[regOffset] - auxInt := x.f.ABISelf.FloatIndexFor(r) - op := OpArgFloatReg - // TODO seems like this has implications for debugging. How does this affect the location? - if auxInt < 0 { // int (not float) parameter register - op = OpArgIntReg - auxInt = int64(r) + } + // Arg is in registers + r := pa.Registers[regOffset] + auxInt := x.f.ABISelf.FloatIndexFor(r) + op := OpArgFloatReg + // TODO seems like this has implications for debugging. How does this affect the location? + if auxInt < 0 { // int (not float) parameter register + op = OpArgIntReg + auxInt = int64(r) + } + aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset} + if toReplace != nil && toReplace.Block == baseArg.Block { + toReplace.reset(op) + toReplace.Aux = aux + toReplace.AuxInt = auxInt + toReplace.Type = t + x.commonArgs[key] = toReplace + return toReplace + } else { + w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) + if x.debug { + fmt.Printf("\tnew %s\n", w.LongString()) } - aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset} - if toReplace != nil && toReplace.Block == baseArg.Block { - toReplace.reset(op) - toReplace.Aux = aux - toReplace.AuxInt = auxInt - toReplace.Type = t - x.commonArgs[key] = toReplace - return toReplace - } else { - w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) - if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) - } - x.commonArgs[key] = w - if toReplace != nil { - toReplace.copyOf(w) - } - return w + x.commonArgs[key] = w + if toReplace != nil { + toReplace.copyOf(w) } + return w } } diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 0577ec7bed..574377a33d 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -133,7 +133,9 @@ func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo { a.reg.clobbers = i.clobbers return a.reg } - +func (a *AuxCall) ABI() *abi.ABIConfig { + return a.abiInfo.Config() +} func (a *AuxCall) ResultReg(c *Config) *regInfo { if a.abiInfo.OutRegistersUsed() == 0 { return a.reg @@ -162,6 +164,11 @@ func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 { return uint8(m) } +// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). +func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment { + return a.abiInfo.OutParam(int(which)) +} + // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc). func (a *AuxCall) OffsetOfResult(which int64) int64 { n := int64(a.abiInfo.OutParam(int(which)).Offset()) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 881fdcc8f4..b590bd4f2f 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -563,16 +563,9 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { } else { // Too big for SSA. // Brute force, and early, do a bunch of stores from registers // TODO fix the nasty storeArgOrLoad recursion in ssa/expand_calls.go so this Just Works with store of a big Arg. - typs, offs := paramAssignment.RegisterTypesAndOffsets() - for i, t := range typs { - o := offs[i] - r := paramAssignment.Registers[i] - op, reg := ssa.ArgOpAndRegisterFor(r, s.f.ABISelf) - v := s.newValue0I(op, t, reg) - v.Aux = &ssa.AuxNameOffset{Name: n, Offset: o} - p := s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), o, s.decladdrs[n]) - s.store(t, p, v) - } + abi := s.f.ABISelf + addr := s.decladdrs[n] + s.storeParameterRegsToStack(abi, paramAssignment, n, addr) } } } @@ -648,6 +641,20 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { return s.f } +func (s *state) storeParameterRegsToStack(abi *abi.ABIConfig, paramAssignment *abi.ABIParamAssignment, n *ir.Name, addr *ssa.Value) { + typs, offs := paramAssignment.RegisterTypesAndOffsets() + for i, t := range typs { + r := paramAssignment.Registers[i] + o := offs[i] + op, reg := ssa.ArgOpAndRegisterFor(r, abi) + aux := &ssa.AuxNameOffset{Name: n, Offset: o} + v := s.newValue0I(op, t, reg) + v.Aux = aux + p := s.newValue1I(ssa.OpOffPtr, types.NewPtr(t), o, addr) + s.store(t, p, v) + } +} + // zeroResults zeros the return values at the start of the function. // We need to do this very early in the function. Defer might stop a // panic and show the return values as they exist at the time of @@ -2968,12 +2975,7 @@ func (s *state) expr(n ir.Node) *ssa.Value { if which == -1 { panic(fmt.Errorf("ORESULT %v does not match call %s", n, s.prevCall)) } - if TypeOK(n.Type()) { - return s.newValue1I(ssa.OpSelectN, n.Type(), which, s.prevCall) - } else { - addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(n.Type()), which, s.prevCall) - return s.rawLoad(n.Type(), addr) - } + return s.resultOfCall(s.prevCall, which, n.Type()) case ir.ODEREF: n := n.(*ir.StarExpr) @@ -3174,6 +3176,30 @@ func (s *state) expr(n ir.Node) *ssa.Value { } } +func (s *state) resultOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value { + aux := c.Aux.(*ssa.AuxCall) + pa := aux.ParamAssignmentForResult(which) + // TODO(register args) determine if in-memory TypeOK is better loaded early from SelectNAddr or later when SelectN is expanded. + // SelectN is better for pattern-matching and possible call-aware analysis we might want to do in the future. + if len(pa.Registers) == 0 && !TypeOK(t) { + addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c) + return s.rawLoad(t, addr) + } + return s.newValue1I(ssa.OpSelectN, t, which, c) +} + +func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value { + aux := c.Aux.(*ssa.AuxCall) + pa := aux.ParamAssignmentForResult(which) + if len(pa.Registers) == 0 { + return s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), which, c) + } + _, addr := s.temp(c.Pos, t) + rval := s.newValue1I(ssa.OpSelectN, t, which, c) + s.vars[memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, addr, rval, s.mem(), false) + return addr +} + // append converts an OAPPEND node to SSA. // If inplace is false, it converts the OAPPEND expression n to an ssa.Value, // adds it to s, and returns the Value. @@ -5068,10 +5094,8 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } fp := res.Field(0) if returnResultAddr { - pt := types.NewPtr(fp.Type) - return s.newValue1I(ssa.OpSelectNAddr, pt, 0, call) + return s.resultAddrOfCall(call, 0, fp.Type) } - return s.newValue1I(ssa.OpSelectN, fp.Type, 0, call) } @@ -5169,9 +5193,7 @@ func (s *state) addr(n ir.Node) *ssa.Value { case ir.ORESULT: // load return from callee n := n.(*ir.ResultExpr) - x := s.newValue1I(ssa.OpSelectNAddr, t, n.Index, s.prevCall) - return x - + return s.resultAddrOfCall(s.prevCall, n.Index, n.Type()) case ir.OINDEX: n := n.(*ir.IndexExpr) if n.X.Type().IsSlice() { @@ -5528,12 +5550,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args . res := make([]*ssa.Value, len(results)) for i, t := range results { off = types.Rnd(off, t.Alignment()) - if TypeOK(t) { - res[i] = s.newValue1I(ssa.OpSelectN, t, int64(i), call) - } else { - addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), int64(i), call) - res[i] = s.rawLoad(t, addr) - } + res[i] = s.resultOfCall(call, int64(i), t) off += t.Size() } off = types.Rnd(off, int64(types.PtrSize)) @@ -6233,9 +6250,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val if commaok && !TypeOK(n.Type()) { // unSSAable type, use temporary. // TODO: get rid of some of these temporaries. - tmp = typecheck.TempAt(n.Pos(), s.curfn, n.Type()) - s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp.(*ir.Name), s.mem()) - addr = s.addr(tmp) + tmp, addr = s.temp(n.Pos(), n.Type()) } cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, targetITab) @@ -6317,6 +6332,14 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val return res, resok } +// temp allocates a temp of type t at position pos +func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) { + tmp := typecheck.TempAt(pos, s.curfn, t) + s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem()) + addr := s.addr(tmp) + return tmp, addr +} + // variable returns the value of a variable at the current location. func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value { v := s.vars[n] diff --git a/test/abi/double_nested_addressed_struct.go b/test/abi/double_nested_addressed_struct.go new file mode 100644 index 0000000000..be7c88aaaf --- /dev/null +++ b/test/abi/double_nested_addressed_struct.go @@ -0,0 +1,62 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type stringPair struct { + a, b string +} + +type stringPairPair struct { + x, y stringPair +} + +// The goal of this test is to be sure that the call arg/result expander works correctly +// for a corner case of passing a 2-nested struct that fits in registers to/from calls. +// AND, the struct has its address taken. + +//go:registerparams +//go:noinline +func H(spp stringPairPair) string { + F(&spp) + return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b +} + +//go:registerparams +//go:noinline +func G(d, c, b, a string) stringPairPair { + return stringPairPair{stringPair{a, b}, stringPair{c, d}} +} + +//go:registerparams +//go:noinline +func F(spp *stringPairPair) { + spp.x.a, spp.x.b, spp.y.a, spp.y.b = spp.y.b, spp.y.a, spp.x.b, spp.x.a +} + +func main() { + spp := G("this", "is", "a", "test") + s := H(spp) + gotVsWant(s, "this is a test") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/double_nested_struct.go b/test/abi/double_nested_struct.go new file mode 100644 index 0000000000..70d8ea4bce --- /dev/null +++ b/test/abi/double_nested_struct.go @@ -0,0 +1,55 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type stringPair struct { + a, b string +} + +type stringPairPair struct { + x, y stringPair +} + +// The goal of this test is to be sure that the call arg/result expander works correctly +// for a corner case of passing a 2-nested struct that fits in registers to/from calls. + +//go:registerparams +//go:noinline +func H(spp stringPairPair) string { + return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b +} + +//go:registerparams +//go:noinline +func G(a,b,c,d string) stringPairPair { + return stringPairPair{stringPair{a,b},stringPair{c,d}} +} + + +func main() { + spp := G("this","is","a","test") + s := H(spp) + gotVsWant(s, "this is a test") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/too_big_to_ssa.go b/test/abi/too_big_to_ssa.go new file mode 100644 index 0000000000..a5c6abb0e4 --- /dev/null +++ b/test/abi/too_big_to_ssa.go @@ -0,0 +1,47 @@ +// run + +// +build !wasm + +// Copyright 2021 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 ( + "fmt" +) + +var sink *string + +type toobig struct { + // 6 words will not SSA but will fit in registers + a,b,c string +} + +//go:registerparams +//go:noinline +func H(x toobig) string { + return x.a + " " + x.b + " " + x.c +} + +//go:registerparams +//go:noinline +func I(a,b,c string) toobig { + return toobig{a,b,c} +} + +func main() { + s := H(toobig{"Hello", "there,", "World"}) + gotVsWant(s, "Hello there, World") + fmt.Println(s) + t := H(I("Ahoy", "there,", "Matey")) + gotVsWant(t, "Ahoy there, Matey") + fmt.Println(t) +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/too_big_to_ssa.out b/test/abi/too_big_to_ssa.out new file mode 100644 index 0000000000..eeece34d47 --- /dev/null +++ b/test/abi/too_big_to_ssa.out @@ -0,0 +1,2 @@ +Hello there, World +Ahoy there, Matey -- GitLab From 96a96a9058004af531db56dee26d82af08321cdb Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Thu, 4 Mar 2021 12:09:04 -0800 Subject: [PATCH 0200/1298] cmd/compile: remove types2.(*Selection).TArgs(), now that instance bug seems fixed Previously, we would sometimes see an internal (*instance) type for a receiver of a types2 method, which was a bug. To deal with that, we put in an extra (*Selection).TArgs() method. However, that (*instance) type is no longer showing up for receivers, so we can remove the types2 method we added and do the work with existing types2 API methods. Change-Id: I03e68f5bbaaf82fe706b6efecbb02e951bbd3cd4 Reviewed-on: https://go-review.googlesource.com/c/go/+/298869 Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Dan Scales --- src/cmd/compile/internal/noder/expr.go | 15 ++++++++++++++- src/cmd/compile/internal/types2/selection.go | 16 ---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 3fded144dc..b99f5a4cdd 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -253,7 +253,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto // selinfo.Targs() are the types used to // instantiate the type of receiver - targs2 := selinfo.TArgs() + targs2 := getTargs(selinfo) targs := make([]ir.Node, len(targs2)) for i, targ2 := range targs2 { targs[i] = ir.TypeNode(g.typ(targ2)) @@ -279,6 +279,19 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto return n } +// getTargs gets the targs associated with the receiver of a selected method +func getTargs(selinfo *types2.Selection) []types2.Type { + r := selinfo.Recv() + if p := types2.AsPointer(r); p != nil { + r = p.Elem() + } + n := types2.AsNamed(r) + if n == nil { + base.Fatalf("Incorrect type for selinfo %v", selinfo) + } + return n.TArgs() +} + func (g *irgen) exprList(expr syntax.Expr) []ir.Node { switch expr := expr.(type) { case nil: diff --git a/src/cmd/compile/internal/types2/selection.go b/src/cmd/compile/internal/types2/selection.go index 02c0fc6902..8128aeee2e 100644 --- a/src/cmd/compile/internal/types2/selection.go +++ b/src/cmd/compile/internal/types2/selection.go @@ -51,22 +51,6 @@ func (s *Selection) Kind() SelectionKind { return s.kind } // Recv returns the type of x in x.f. func (s *Selection) Recv() Type { return s.recv } -// Work-around for a compiler issue where an (*instance) escapes. -// TODO(gri): Is this still needed? -func (s *Selection) TArgs() []Type { - r := s.recv - if p := asPointer(r); p != nil { - r = p.Elem() - } - if n := asNamed(r); n != nil { - return n.TArgs() - } - // The base type (after skipping any pointer) must be a Named type. The - // bug is that sometimes it can be an instance type (which is supposed to - // be an internal type only). - return r.(*instance).targs -} - // Obj returns the object denoted by x.f; a *Var for // a field selection, and a *Func in all other cases. func (s *Selection) Obj() Object { return s.obj } -- GitLab From a7526bbf72dfe0fde00d88f85fd6cddccdb3a345 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Thu, 21 Jan 2021 22:53:30 +0800 Subject: [PATCH 0201/1298] encoding/json: marshal maps using reflect.Value.MapRange MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map serialization using reflect.Value.MapIndex cannot retrieve map keys that contain a NaN, resulting in a panic. Switch the implementation to use the reflect.Value.MapRange method instead, which iterates over all map entries regardless of whether they are directly retrievable. Note that according to RFC 8259, section 4, a JSON object should have unique names, but does not forbid the occurrence of duplicate names. Fixes #43207 Change-Id: If4bc55229b1f64b8ca4b0fed37549725efdace39 Reviewed-on: https://go-review.googlesource.com/c/go/+/278632 Trust: Meng Zhuo Trust: Joe Tsai Trust: Bryan C. Mills Run-TryBot: Meng Zhuo TryBot-Result: Go Bot Reviewed-by: Joe Tsai Reviewed-by: Daniel Martí --- src/encoding/json/encode.go | 36 +++++++++++++++++--------------- src/encoding/json/encode_test.go | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 751f03d33d..e473e615a9 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -794,23 +794,24 @@ func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteByte('{') // Extract and sort the keys. - keys := v.MapKeys() - sv := make([]reflectWithString, len(keys)) - for i, v := range keys { - sv[i].v = v + sv := make([]reflectWithString, v.Len()) + mi := v.MapRange() + for i := 0; mi.Next(); i++ { + sv[i].k = mi.Key() + sv[i].v = mi.Value() if err := sv[i].resolve(); err != nil { e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) } } - sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) + sort.Slice(sv, func(i, j int) bool { return sv[i].ks < sv[j].ks }) for i, kv := range sv { if i > 0 { e.WriteByte(',') } - e.string(kv.s, opts.escapeHTML) + e.string(kv.ks, opts.escapeHTML) e.WriteByte(':') - me.elemEnc(e, v.MapIndex(kv.v), opts) + me.elemEnc(e, kv.v, opts) } e.WriteByte('}') e.ptrLevel-- @@ -997,29 +998,30 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { } type reflectWithString struct { - v reflect.Value - s string + k reflect.Value + v reflect.Value + ks string } func (w *reflectWithString) resolve() error { - if w.v.Kind() == reflect.String { - w.s = w.v.String() + if w.k.Kind() == reflect.String { + w.ks = w.k.String() return nil } - if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { - if w.v.Kind() == reflect.Ptr && w.v.IsNil() { + if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok { + if w.k.Kind() == reflect.Ptr && w.k.IsNil() { return nil } buf, err := tm.MarshalText() - w.s = string(buf) + w.ks = string(buf) return err } - switch w.v.Kind() { + switch w.k.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - w.s = strconv.FormatInt(w.v.Int(), 10) + w.ks = strconv.FormatInt(w.k.Int(), 10) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - w.s = strconv.FormatUint(w.v.Uint(), 10) + w.ks = strconv.FormatUint(w.k.Uint(), 10) return nil } panic("unexpected map key type") diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go index 42bb09d5cd..0dad951095 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -245,6 +245,22 @@ func TestUnsupportedValues(t *testing.T) { } } +// Issue 43207 +func TestMarshalTextFloatMap(t *testing.T) { + m := map[textfloat]string{ + textfloat(math.NaN()): "1", + textfloat(math.NaN()): "1", + } + got, err := Marshal(m) + if err != nil { + t.Errorf("Marshal() error: %v", err) + } + want := `{"TF:NaN":"1","TF:NaN":"1"}` + if string(got) != want { + t.Errorf("Marshal() = %s, want %s", got, want) + } +} + // Ref has Marshaler and Unmarshaler methods with pointer receiver. type Ref int @@ -854,6 +870,10 @@ func tenc(format string, a ...interface{}) ([]byte, error) { return buf.Bytes(), nil } +type textfloat float64 + +func (f textfloat) MarshalText() ([]byte, error) { return tenc(`TF:%0.2f`, f) } + // Issue 13783 func TestEncodeBytekind(t *testing.T) { testdata := []struct { @@ -872,6 +892,7 @@ func TestEncodeBytekind(t *testing.T) { {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`}, {[]textint{9, 3}, `["TI:9","TI:3"]`}, {[]int{9, 3}, `[9,3]`}, + {[]textfloat{12, 3}, `["TF:12.00","TF:3.00"]`}, } for _, d := range testdata { js, err := Marshal(d.data) -- GitLab From b62da089091e305b6231082d8a69b27c56603b51 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 4 Mar 2021 21:09:17 -0500 Subject: [PATCH 0202/1298] cmd/go: update error expectations in TestScript/mod_install_pkg_version This test was missed in CL 298650, and not caught by TryBots because it is skipped it short mode (and we forgot to add longtest TryBots on that CL). Updates #44745 Change-Id: I696d01307dabf351b0e4735db0644f4e09c8e369 Reviewed-on: https://go-review.googlesource.com/c/go/+/298794 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Robert Findley TryBot-Result: Go Bot --- src/cmd/go/testdata/script/mod_install_pkg_version.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt index e27ebc5cc5..6ed600ff71 100644 --- a/src/cmd/go/testdata/script/mod_install_pkg_version.txt +++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt @@ -59,9 +59,9 @@ rm $GOPATH/bin env GO111MODULE=on go mod download rsc.io/fortune@v1.0.0 ! go install $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 -stderr '^go: cannot find main module; see ''go help modules''$' +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go install ../pkg/mod/rsc.io/fortune@v1.0.0 -stderr '^go: cannot find main module; see ''go help modules''$' +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' mkdir tmp cd tmp go mod init tmp -- GitLab From 2b0e29f51669063002cbcceca4f4a43e00144876 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Sun, 14 Feb 2021 17:27:56 +0000 Subject: [PATCH 0203/1298] docs: fix case of GitHub Change `Github` to `GitHub` Change-Id: I514e8dc9a19182fcf9fcf5bc1b5fbff253c1a947 GitHub-Last-Rev: 7124c7058e0c7ff19dc8440fa79271eb6cfdaea9 GitHub-Pull-Request: golang/go#44260 Reviewed-on: https://go-review.googlesource.com/c/go/+/291950 Reviewed-by: Bryan C. Mills Reviewed-by: Ian Lance Taylor Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- misc/chrome/gophertool/popup.html | 2 +- src/cmd/go/internal/vcs/vcs.go | 2 +- src/crypto/md5/md5_test.go | 2 +- src/crypto/sha1/sha1_test.go | 2 +- src/crypto/sha256/sha256_test.go | 2 +- src/crypto/sha512/sha512_test.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/misc/chrome/gophertool/popup.html b/misc/chrome/gophertool/popup.html index 9740406276..ad42a3847c 100644 --- a/misc/chrome/gophertool/popup.html +++ b/misc/chrome/gophertool/popup.html @@ -15,7 +15,7 @@ pkg id/name: Also: buildbots -Github +GitHub diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 9feffe0765..91485f6f74 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -1176,7 +1176,7 @@ func expand(match map[string]string, s string) string { // and import paths referring to a fully-qualified importPath // containing a VCS type (foo.com/repo.git/dir) var vcsPaths = []*vcsPath{ - // Github + // GitHub { pathPrefix: "github.com", regexp: lazyregexp.New(`^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`), diff --git a/src/crypto/md5/md5_test.go b/src/crypto/md5/md5_test.go index 282ba1b859..c0ac0971c4 100644 --- a/src/crypto/md5/md5_test.go +++ b/src/crypto/md5/md5_test.go @@ -157,7 +157,7 @@ func TestBlockGeneric(t *testing.T) { // Tests for unmarshaling hashes that have hashed a large amount of data // The initial hash generation is omitted from the test, because it takes a long time. // The test contains some already-generated states, and their expected sums -// Tests a problem that is outlined in Github issue #29541 +// Tests a problem that is outlined in GitHub issue #29541 // The problem is triggered when an amount of data has been hashed for which // the data length has a 1 in the 32nd bit. When casted to int, this changes // the sign of the value, and causes the modulus operation to return a diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go index 681e928de2..c3e6010af1 100644 --- a/src/crypto/sha1/sha1_test.go +++ b/src/crypto/sha1/sha1_test.go @@ -156,7 +156,7 @@ func TestBlockGeneric(t *testing.T) { // Tests for unmarshaling hashes that have hashed a large amount of data // The initial hash generation is omitted from the test, because it takes a long time. // The test contains some already-generated states, and their expected sums -// Tests a problem that is outlined in Github issue #29543 +// Tests a problem that is outlined in GitHub issue #29543 // The problem is triggered when an amount of data has been hashed for which // the data length has a 1 in the 32nd bit. When casted to int, this changes // the sign of the value, and causes the modulus operation to return a diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go index 433c5a4c5e..a2794b015d 100644 --- a/src/crypto/sha256/sha256_test.go +++ b/src/crypto/sha256/sha256_test.go @@ -229,7 +229,7 @@ func TestBlockGeneric(t *testing.T) { // Tests for unmarshaling hashes that have hashed a large amount of data // The initial hash generation is omitted from the test, because it takes a long time. // The test contains some already-generated states, and their expected sums -// Tests a problem that is outlined in Github issue #29517 +// Tests a problem that is outlined in GitHub issue #29517 // The problem is triggered when an amount of data has been hashed for which // the data length has a 1 in the 32nd bit. When casted to int, this changes // the sign of the value, and causes the modulus operation to return a diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go index 59998b1d38..74a13331af 100644 --- a/src/crypto/sha512/sha512_test.go +++ b/src/crypto/sha512/sha512_test.go @@ -835,7 +835,7 @@ func TestBlockGeneric(t *testing.T) { // Tests for unmarshaling hashes that have hashed a large amount of data // The initial hash generation is omitted from the test, because it takes a long time. // The test contains some already-generated states, and their expected sums -// Tests a problem that is outlined in Github issue #29541 +// Tests a problem that is outlined in GitHub issue #29541 // The problem is triggered when an amount of data has been hashed for which // the data length has a 1 in the 32nd bit. When casted to int, this changes // the sign of the value, and causes the modulus operation to return a -- GitLab From f0b6d3753f57bf37487b127f968920743c401ed9 Mon Sep 17 00:00:00 2001 From: Tao Qingyun Date: Fri, 5 Mar 2021 04:01:00 +0000 Subject: [PATCH 0204/1298] cmd/go: update PWD variable for 'go generate' Most subprocess invocations in the go command use base.AppendPWD to append an accurate value of PWD to the command's environment, which can speed up calls like os.Getwd and also help to provide less-confusing output from scripts. Update `go generate` to do so. Fixes #43862 Change-Id: I3b756f1532b2d922f7d74fd86414d5567a0122c0 GitHub-Last-Rev: 3ec8da265a2777d1dcbcea00f107b8f5905f3640 GitHub-Pull-Request: golang/go#43940 Reviewed-on: https://go-review.googlesource.com/c/go/+/287152 Reviewed-by: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Trust: Baokun Lee --- src/cmd/go/internal/generate/generate.go | 1 + src/cmd/go/testdata/script/generate.txt | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go index a48311d51b..97df229b31 100644 --- a/src/cmd/go/internal/generate/generate.go +++ b/src/cmd/go/internal/generate/generate.go @@ -334,6 +334,7 @@ func (g *Generator) setEnv() { "GOPACKAGE=" + g.pkg, "DOLLAR=" + "$", } + g.env = base.AppendPWD(g.env, g.dir) } // split breaks the line into words, evaluating quoted diff --git a/src/cmd/go/testdata/script/generate.txt b/src/cmd/go/testdata/script/generate.txt index c3c563e5f4..73f5bbd57a 100644 --- a/src/cmd/go/testdata/script/generate.txt +++ b/src/cmd/go/testdata/script/generate.txt @@ -26,6 +26,10 @@ stdout 'yes' # flag.go should select yes go generate './generate/env_test.go' stdout 'main_test' +# Test go generate provides the right "$PWD" +go generate './generate/env_pwd.go' +stdout $WORK'[/\\]gopath[/\\]src[/\\]generate' + -- echo.go -- package main @@ -88,4 +92,8 @@ package p -- generate/env_test.go -- package main_test -//go:generate echo $GOPACKAGE \ No newline at end of file +//go:generate echo $GOPACKAGE +-- generate/env_pwd.go -- +package p + +//go:generate echo $PWD -- GitLab From 60b500dc6c78a793775a7dff4eb8c656734a54c8 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 26 Feb 2021 09:16:56 -0800 Subject: [PATCH 0205/1298] math/big: remove bounds checks for shrVU_g inner loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make explicit a shrVU_g precondition. Replace i with i+1 throughout the loop. The resulting loop is functionally identical, but the compiler can do better BCE without the i-1 slice offset. Benchmarks results on amd64 with -tags=math_big_pure_go. name old time/op new time/op delta NonZeroShifts/1/shrVU-8 4.55ns ± 2% 4.45ns ± 3% -2.27% (p=0.000 n=28+30) NonZeroShifts/1/shlVU-8 4.07ns ± 1% 4.13ns ± 4% +1.55% (p=0.000 n=26+29) NonZeroShifts/2/shrVU-8 6.12ns ± 1% 5.55ns ± 1% -9.30% (p=0.000 n=28+28) NonZeroShifts/2/shlVU-8 5.65ns ± 3% 5.70ns ± 2% +0.92% (p=0.008 n=30+29) NonZeroShifts/3/shrVU-8 7.58ns ± 2% 6.79ns ± 2% -10.46% (p=0.000 n=28+28) NonZeroShifts/3/shlVU-8 6.62ns ± 2% 6.69ns ± 1% +1.07% (p=0.000 n=29+28) NonZeroShifts/4/shrVU-8 9.02ns ± 1% 7.79ns ± 2% -13.59% (p=0.000 n=27+30) NonZeroShifts/4/shlVU-8 7.74ns ± 1% 7.82ns ± 1% +0.92% (p=0.000 n=26+28) NonZeroShifts/5/shrVU-8 10.6ns ± 1% 8.9ns ± 3% -16.31% (p=0.000 n=25+29) NonZeroShifts/5/shlVU-8 8.59ns ± 1% 8.68ns ± 1% +1.13% (p=0.000 n=27+29) NonZeroShifts/10/shrVU-8 18.2ns ± 2% 14.4ns ± 1% -20.96% (p=0.000 n=27+28) NonZeroShifts/10/shlVU-8 14.1ns ± 1% 14.1ns ± 1% +0.46% (p=0.001 n=26+28) NonZeroShifts/100/shrVU-8 161ns ± 2% 118ns ± 1% -26.83% (p=0.000 n=29+30) NonZeroShifts/100/shlVU-8 119ns ± 2% 120ns ± 2% +0.92% (p=0.000 n=29+29) NonZeroShifts/1000/shrVU-8 1.54µs ± 1% 1.10µs ± 1% -28.63% (p=0.000 n=29+29) NonZeroShifts/1000/shlVU-8 1.10µs ± 1% 1.10µs ± 2% ~ (p=0.701 n=28+29) NonZeroShifts/10000/shrVU-8 15.3µs ± 2% 10.9µs ± 1% -28.68% (p=0.000 n=28+28) NonZeroShifts/10000/shlVU-8 10.9µs ± 2% 10.9µs ± 2% -0.57% (p=0.003 n=26+29) NonZeroShifts/100000/shrVU-8 154µs ± 1% 111µs ± 2% -28.04% (p=0.000 n=27+28) NonZeroShifts/100000/shlVU-8 113µs ± 2% 113µs ± 2% ~ (p=0.790 n=30+30) Change-Id: Ib6a621ee7c88b27f0f18121fb2cba3606c40c9b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/297049 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/math/big/arith.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/math/big/arith.go b/src/math/big/arith.go index 750ce8aa39..e1947936d4 100644 --- a/src/math/big/arith.go +++ b/src/math/big/arith.go @@ -170,12 +170,16 @@ func shrVU_g(z, x []Word, s uint) (c Word) { if len(z) == 0 { return } + if len(x) != len(z) { + // This is an invariant guaranteed by the caller. + panic("len(x) != len(z)") + } s &= _W - 1 // hint to the compiler that shifts by s don't need guard code ŝ := _W - s ŝ &= _W - 1 // ditto c = x[0] << ŝ - for i := 0; i < len(z)-1; i++ { - z[i] = x[i]>>s | x[i+1]<<ŝ + for i := 1; i < len(z); i++ { + z[i-1] = x[i-1]>>s | x[i]<<ŝ } z[len(z)-1] = x[len(z)-1] >> s return -- GitLab From 31df4e3fcd0c961684a027188a391f6db1ab3439 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Mon, 16 Nov 2020 17:50:01 +0800 Subject: [PATCH 0206/1298] cmd/link: add relocs type for mips64x The race detector of llvm adds four reloc types even with -fPIC elf.R_MIPS_CALL16 elf.R_MIPS_GPREL32 elf.R_MIPS_64 elf.R_MIPS_GOT_DISP Change-Id: If73119dcba14ef74395273eb680f52a0aa853217 Reviewed-on: https://go-review.googlesource.com/c/go/+/270297 Trust: Meng Zhuo Run-TryBot: Meng Zhuo Reviewed-by: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/link/internal/loadelf/ldelf.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index c698874b32..6e3b2c077d 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -983,7 +983,11 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) { MIPS64 | uint32(elf.R_MIPS_GPREL16)<<16, MIPS64 | uint32(elf.R_MIPS_GOT_PAGE)<<16, MIPS64 | uint32(elf.R_MIPS_JALR)<<16, - MIPS64 | uint32(elf.R_MIPS_GOT_OFST)<<16: + MIPS64 | uint32(elf.R_MIPS_GOT_OFST)<<16, + MIPS64 | uint32(elf.R_MIPS_CALL16)<<16, + MIPS64 | uint32(elf.R_MIPS_GPREL32)<<16, + MIPS64 | uint32(elf.R_MIPS_64)<<16, + MIPS64 | uint32(elf.R_MIPS_GOT_DISP)<<16: return 4, nil case S390X | uint32(elf.R_390_8)<<16: -- GitLab From 2217e89ba326875470a856cd0da79f3ec9a896b8 Mon Sep 17 00:00:00 2001 From: Rodolfo Carvalho Date: Mon, 18 Jan 2021 19:56:26 +0100 Subject: [PATCH 0207/1298] net/http/httptrace: fix doc typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I919d9c3968c0fcd33774e714f22182504790bd01 Reviewed-on: https://go-review.googlesource.com/c/go/+/284143 Reviewed-by: Ian Lance Taylor Reviewed-by: Daniel Martí Trust: Daniel Martí --- src/net/http/httptrace/trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go index 6a5cbac9d8..5777c91747 100644 --- a/src/net/http/httptrace/trace.go +++ b/src/net/http/httptrace/trace.go @@ -127,7 +127,7 @@ type ClientTrace struct { // ConnectDone is called when a new connection's Dial // completes. The provided err indicates whether the - // connection completedly successfully. + // connection completed successfully. // If net.Dialer.DualStack ("Happy Eyeballs") support is // enabled, this may be called multiple times. ConnectDone func(network, addr string, err error) -- GitLab From 2e794c2bb1302af764670dba894bbfe537bd63f0 Mon Sep 17 00:00:00 2001 From: Alexey Vilenski Date: Fri, 5 Mar 2021 11:37:54 +0000 Subject: [PATCH 0208/1298] testing: add TB.Setenv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new method TB.Setenv that'll set environment variables only for the isolated lifetime of the test, and will clean up and unset these variables when the test ends. This method disables the test or benchmark from running in parallel. Fixes #41260 Change-Id: I0a18f094ec1c6ec3157b4b12993ea3075e2e9867 GitHub-Last-Rev: 0ca12fa565318f350b927e2ef94f3b4f792c75c2 GitHub-Pull-Request: golang/go#41857 Reviewed-on: https://go-review.googlesource.com/c/go/+/260577 Trust: Daniel Martí Trust: Emmanuel Odeke Run-TryBot: Daniel Martí TryBot-Result: Go Bot Reviewed-by: roger peppe --- src/testing/testing.go | 42 +++++++++++++++++++ src/testing/testing_test.go | 83 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/testing/testing.go b/src/testing/testing.go index 466dd96981..fc52f3c547 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -667,6 +667,7 @@ var _ TB = (*B)(nil) type T struct { common isParallel bool + isEnvSet bool context *testContext // For running tests and subtests. } @@ -964,6 +965,29 @@ func (c *common) TempDir() string { return dir } +// Setenv calls os.Setenv(key, value) and uses Cleanup to +// restore the environment variable to its original value +// after the test. +// +// This cannot be used in parallel tests. +func (c *common) Setenv(key, value string) { + prevValue, ok := os.LookupEnv(key) + + if err := os.Setenv(key, value); err != nil { + c.Fatalf("cannot set environment variable: %v", err) + } + + if ok { + c.Cleanup(func() { + os.Setenv(key, prevValue) + }) + } else { + c.Cleanup(func() { + os.Unsetenv(key) + }) + } +} + // panicHanding is an argument to runCleanup. type panicHandling int @@ -1035,6 +1059,9 @@ func (t *T) Parallel() { if t.isParallel { panic("testing: t.Parallel called multiple times") } + if t.isEnvSet { + panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests") + } t.isParallel = true // We don't want to include the time we spend waiting for serial tests @@ -1068,6 +1095,21 @@ func (t *T) Parallel() { t.raceErrors += -race.Errors() } +// Setenv calls os.Setenv(key, value) and uses Cleanup to +// restore the environment variable to its original value +// after the test. +// +// This cannot be used in parallel tests. +func (t *T) Setenv(key, value string) { + if t.isParallel { + panic("testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests") + } + + t.isEnvSet = true + + t.common.Setenv(key, value) +} + // InternalTest is an internal type but exported because it is cross-package; // it is part of the implementation of the "go test" command. type InternalTest struct { diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 0f096980ca..55a4df4739 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -109,3 +109,86 @@ func testTempDir(t *testing.T) { t.Errorf("unexpected %d files in TempDir: %v", len(files), files) } } + +func TestSetenv(t *testing.T) { + tests := []struct { + name string + key string + initialValueExists bool + initialValue string + newValue string + }{ + { + name: "initial value exists", + key: "GO_TEST_KEY_1", + initialValueExists: true, + initialValue: "111", + newValue: "222", + }, + { + name: "initial value exists but empty", + key: "GO_TEST_KEY_2", + initialValueExists: true, + initialValue: "", + newValue: "222", + }, + { + name: "initial value is not exists", + key: "GO_TEST_KEY_3", + initialValueExists: false, + initialValue: "", + newValue: "222", + }, + } + + for _, test := range tests { + if test.initialValueExists { + if err := os.Setenv(test.key, test.initialValue); err != nil { + t.Fatalf("unable to set env: got %v", err) + } + } else { + os.Unsetenv(test.key) + } + + t.Run(test.name, func(t *testing.T) { + t.Setenv(test.key, test.newValue) + if os.Getenv(test.key) != test.newValue { + t.Fatalf("unexpected value after t.Setenv: got %s, want %s", os.Getenv(test.key), test.newValue) + } + }) + + got, exists := os.LookupEnv(test.key) + if got != test.initialValue { + t.Fatalf("unexpected value after t.Setenv cleanup: got %s, want %s", got, test.initialValue) + } + if exists != test.initialValueExists { + t.Fatalf("unexpected value after t.Setenv cleanup: got %t, want %t", exists, test.initialValueExists) + } + } +} + +func TestSetenvWithParallelAfterSetenv(t *testing.T) { + defer func() { + want := "testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests" + if got := recover(); got != want { + t.Fatalf("expected panic; got %#v want %q", got, want) + } + }() + + t.Setenv("GO_TEST_KEY_1", "value") + + t.Parallel() +} + +func TestSetenvWithParallelBeforeSetenv(t *testing.T) { + defer func() { + want := "testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests" + if got := recover(); got != want { + t.Fatalf("expected panic; got %#v want %q", got, want) + } + }() + + t.Parallel() + + t.Setenv("GO_TEST_KEY_1", "value") +} -- GitLab From 302a400316319501748c0f034464fa70e7815272 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 3 Mar 2021 16:30:22 -0500 Subject: [PATCH 0209/1298] cmd/go/internal/modfetch: detect and recover from missing ziphash file Previously, if an extracted module directory existed in the module cache, but the corresponding ziphash file did not, if the sum was missing from go.sum, we would not verify the sum. This caused 'go get' not to write missing sums. 'go build' in readonly mode (now the default) checks for missing sums and doesn't attempt to fetch modules that can't be verified against go.sum. With this change, when requesting the module directory with modfetch.DownloadDir, if the ziphash file is missing, the go command will re-hash the zip without downloading or re-extracting it again. Note that the go command creates the ziphash file before the module directory, but another program could remove it separately, and it might not be present after a crash. Fixes #44749 Change-Id: I64551e048a3ba17d069de1ec123d5b8b2757543c Reviewed-on: https://go-review.googlesource.com/c/go/+/298352 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/modfetch/cache.go | 17 ++++ src/cmd/go/internal/modfetch/fetch.go | 77 ++++++++++++------- .../script/mod_get_missing_ziphash.txt | 55 +++++++++++++ src/cmd/go/testdata/script/mod_verify.txt | 7 +- 4 files changed, 125 insertions(+), 31 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_get_missing_ziphash.txt diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 9e751931a0..10f774568d 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -80,6 +80,7 @@ func DownloadDir(m module.Version) (string, error) { return "", err } + // Check whether the directory itself exists. dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer) if fi, err := os.Stat(dir); os.IsNotExist(err) { return dir, err @@ -88,6 +89,9 @@ func DownloadDir(m module.Version) (string, error) { } else if !fi.IsDir() { return dir, &DownloadDirPartialError{dir, errors.New("not a directory")} } + + // Check if a .partial file exists. This is created at the beginning of + // a download and removed after the zip is extracted. partialPath, err := CachePath(m, "partial") if err != nil { return dir, err @@ -97,6 +101,19 @@ func DownloadDir(m module.Version) (string, error) { } else if !os.IsNotExist(err) { return dir, err } + + // Check if a .ziphash file exists. It should be created before the + // zip is extracted, but if it was deleted (by another program?), we need + // to re-calculate it. + ziphashPath, err := CachePath(m, "ziphash") + if err != nil { + return dir, err + } + if _, err := os.Stat(ziphashPath); os.IsNotExist(err) { + return dir, &DownloadDirPartialError{dir, errors.New("ziphash file is missing")} + } else if err != nil { + return dir, err + } return dir, nil } diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index d5ad277dd0..7b4ce2154c 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -168,13 +168,16 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e if err != nil { return cached{"", err} } + ziphashfile := zipfile + "hash" - // Skip locking if the zipfile already exists. + // Return without locking if the zip and ziphash files exist. if _, err := os.Stat(zipfile); err == nil { - return cached{zipfile, nil} + if _, err := os.Stat(ziphashfile); err == nil { + return cached{zipfile, nil} + } } - // The zip file does not exist. Acquire the lock and create it. + // The zip or ziphash file does not exist. Acquire the lock and create them. if cfg.CmdName != "mod download" { fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version) } @@ -184,14 +187,6 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e } defer unlock() - // Double-check that the zipfile was not created while we were waiting for - // the lock. - if _, err := os.Stat(zipfile); err == nil { - return cached{zipfile, nil} - } - if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil { - return cached{"", err} - } if err := downloadZip(ctx, mod, zipfile); err != nil { return cached{"", err} } @@ -204,6 +199,25 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile) defer span.Done() + // Double-check that the zipfile was not created while we were waiting for + // the lock in DownloadZip. + ziphashfile := zipfile + "hash" + var zipExists, ziphashExists bool + if _, err := os.Stat(zipfile); err == nil { + zipExists = true + } + if _, err := os.Stat(ziphashfile); err == nil { + ziphashExists = true + } + if zipExists && ziphashExists { + return nil + } + + // Create parent directories. + if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil { + return err + } + // Clean up any remaining tempfiles from previous runs. // This is only safe to do because the lock file ensures that their // writers are no longer active. @@ -215,6 +229,12 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e } } + // If the zip file exists, the ziphash file must have been deleted + // or lost after a file system crash. Re-hash the zip without downloading. + if zipExists { + return hashZip(mod, zipfile, ziphashfile) + } + // From here to the os.Rename call below is functionally almost equivalent to // renameio.WriteToFile, with one key difference: we want to validate the // contents of the file (by hashing it) before we commit it. Because the file @@ -287,15 +307,7 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e } // Hash the zip file and check the sum before renaming to the final location. - hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash) - if err != nil { - return err - } - if err := checkModSum(mod, hash); err != nil { - return err - } - - if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil { + if err := hashZip(mod, f.Name(), ziphashfile); err != nil { return err } if err := os.Rename(f.Name(), zipfile); err != nil { @@ -307,6 +319,22 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e return nil } +// hashZip reads the zip file opened in f, then writes the hash to ziphashfile, +// overwriting that file if it exists. +// +// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns +// an error and does not write ziphashfile. +func hashZip(mod module.Version, zipfile, ziphashfile string) error { + hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash) + if err != nil { + return err + } + if err := checkModSum(mod, hash); err != nil { + return err + } + return renameio.WriteFile(ziphashfile, []byte(hash), 0666) +} + // makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir // and its transitive contents. func makeDirsReadOnly(dir string) { @@ -450,11 +478,6 @@ func HaveSum(mod module.Version) bool { // checkMod checks the given module's checksum. func checkMod(mod module.Version) { - if cfg.GOMODCACHE == "" { - // Do not use current directory. - return - } - // Do the file I/O before acquiring the go.sum lock. ziphash, err := CachePath(mod, "ziphash") if err != nil { @@ -462,10 +485,6 @@ func checkMod(mod module.Version) { } data, err := renameio.ReadFile(ziphash) if err != nil { - if errors.Is(err, fs.ErrNotExist) { - // This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes. - return - } base.Fatalf("verifying %v", module.VersionError(mod, err)) } h := strings.TrimSpace(string(data)) diff --git a/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt new file mode 100644 index 0000000000..8f6793edf5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt @@ -0,0 +1,55 @@ +# Test that if the module cache contains an extracted source directory but not +# a ziphash, 'go build' complains about a missing sum, and 'go get' adds +# the sum. Verifies #44749. + +# With a tidy go.sum, go build succeeds. This also populates the module cache. +cp go.sum.tidy go.sum +go build -n use +env GOPROXY=off +env GOSUMDB=off + +# Control case: if we delete the hash for rsc.io/quote v1.5.2, +# 'go build' reports an error. 'go get' adds the sum. +cp go.sum.bug go.sum +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get -d use +cmp go.sum go.sum.tidy +go build -n use + +# If we delete the hash *and* the ziphash file, we should see the same behavior. +cp go.sum.bug go.sum +rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get -d use +cmp go.sum go.sum.tidy +go build -n use + +-- go.mod -- +module use + +go 1.17 + +require rsc.io/quote v1.5.2 +-- go.sum.tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- go.sum.bug -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_verify.txt b/src/cmd/go/testdata/script/mod_verify.txt index 43812d069f..b5106659a9 100644 --- a/src/cmd/go/testdata/script/mod_verify.txt +++ b/src/cmd/go/testdata/script/mod_verify.txt @@ -48,10 +48,13 @@ go mod tidy grep '^rsc.io/quote v1.1.0/go.mod ' go.sum grep '^rsc.io/quote v1.1.0 ' go.sum -# sync should ignore missing ziphash; verify should not +# verify should fail on a missing ziphash. tidy should restore it. rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash -go mod tidy ! go mod verify +stderr '^rsc.io/quote v1.1.0: missing ziphash: open '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash' +go mod tidy +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +go mod verify # Packages below module root should not be mentioned in go.sum. rm go.sum -- GitLab From c5a1c2276ee41a65cce93b7e443d333dfa29aba7 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 17 Feb 2021 19:28:33 +0000 Subject: [PATCH 0210/1298] reflect: use global variables for register count This change switches reflect to use global variables for ABI-related register counts instead of internal/abi constants. The advantage of doing so is that we can make the internal/abi constants non-zero and enable the runtime register argument spiller/unspiller even if they're not used. It's basically turning two things we need to flip when we switch to the register ABI into one. It also paves the way for testing the reflect register ABI path independently, because now we can switch the global variables at will and run the register-assignment algorithm in tests without having the rest of the runtime be broken. Change-Id: Ie23629a37a5c80aeb24909d4bd9eacbd3f0c06d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/293149 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/internal/abi/abi_amd64.go | 10 +++------- src/reflect/abi.go | 28 ++++++++++++++++++++++++++-- src/runtime/asm_amd64.s | 5 +---- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/internal/abi/abi_amd64.go b/src/internal/abi/abi_amd64.go index 77589d4c34..07c3ec1aab 100644 --- a/src/internal/abi/abi_amd64.go +++ b/src/internal/abi/abi_amd64.go @@ -10,16 +10,12 @@ package abi const ( // See abi_generic.go. - // Currently these values are zero because whatever uses - // them will expect the register ABI, which isn't ready - // yet. - // RAX, RBX, RCX, RDI, RSI, R8, R9, R10, R11. - IntArgRegs = 0 // 9 + IntArgRegs = 9 // X0 -> X14. - FloatArgRegs = 0 // 15 + FloatArgRegs = 15 // We use SSE2 registers which support 64-bit float operations. - EffectiveFloatRegSize = 0 // 8 + EffectiveFloatRegSize = 8 ) diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 36d6b3095b..618efd0980 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -9,6 +9,30 @@ import ( "unsafe" ) +// These variables are used by the register assignment +// algorithm in this file. +// +// They should be modified with care (no other reflect code +// may be executing) and are generally only modified +// when testing this package. +// +// They should never be set higher than their internal/abi +// constant counterparts, because the system relies on a +// structure that is at least large enough to hold the +// registers the system supports. +// +// Currently they're set to zero because using the actual +// constants will break every part of the toolchain that +// uses reflect to call functions (e.g. go test, or anything +// that uses text/template). The values that are currently +// commented out there should be the actual values once +// we're ready to use the register ABI everywhere. +var ( + intArgRegs = 0 // abi.IntArgRegs + floatArgRegs = 0 // abi.FloatArgRegs + floatRegSize = uintptr(0) // uintptr(abi.EffectiveFloatRegSize) +) + // abiStep represents an ABI "instruction." Each instruction // describes one part of how to translate between a Go value // in memory and a call frame. @@ -226,7 +250,7 @@ func (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool { if ptrMap != 0 && size != ptrSize { panic("non-empty pointer map passed for non-pointer-size values") } - if a.iregs+n > abi.IntArgRegs { + if a.iregs+n > intArgRegs { return false } for i := 0; i < n; i++ { @@ -255,7 +279,7 @@ func (a *abiSeq) assignFloatN(offset, size uintptr, n int) bool { if n < 0 { panic("invalid n") } - if a.fregs+n > abi.FloatArgRegs || abi.EffectiveFloatRegSize < size { + if a.fregs+n > floatArgRegs || floatRegSize < size { return false } for i := 0; i < n; i++ { diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 517c5a9d3e..ddd6a5bd5b 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -442,10 +442,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 MOVL $0, DX JMP runtime·morestack(SB) -// REFLECTCALL_USE_REGABI is not defined. It must be defined in conjunction with the -// register constants in the internal/abi package. - -#ifdef REFLECTCALL_USE_REGABI +#ifdef GOEXPERIMENT_REGABI // spillArgs stores return values from registers to a *internal/abi.RegArgs in R12. TEXT spillArgs<>(SB),NOSPLIT,$0-0 MOVQ AX, 0(R12) -- GitLab From a2f70672334ecc71c81bd1f424e1734485d8cb83 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 18 Feb 2021 17:33:01 +0000 Subject: [PATCH 0211/1298] reflect: include the alignment of zero-sized types in stack offsets This change modifies the reflect ABI assignment algorithm to catch zero-sized types at the top level of each argument and faux-stack-assign them. It doesn't actually generate an ABI step, which is unnecessary, but it ensures that the offsets of further stack-assigned arguments are aligned to the alignment of that zero-sized argument. This change is necessary to have the register ABI assignment algorithm gracefully degrade to ABI0 when no registers are present in the ABI. Fixes #44377. Change-Id: Ia95571688a61259302bb3c6d5fb33fbb6b5e8db8 Reviewed-on: https://go-review.googlesource.com/c/go/+/293789 Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: Cherry Zhang Trust: Than McIntosh --- src/reflect/abi.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/reflect/abi.go b/src/reflect/abi.go index 618efd0980..50e6312172 100644 --- a/src/reflect/abi.go +++ b/src/reflect/abi.go @@ -123,6 +123,24 @@ func (a *abiSeq) stepsForValue(i int) []abiStep { func (a *abiSeq) addArg(t *rtype) *abiStep { pStart := len(a.steps) a.valueStart = append(a.valueStart, pStart) + if t.size == 0 { + // If the size of the argument type is zero, then + // in order to degrade gracefully into ABI0, we need + // to stack-assign this type. The reason is that + // although zero-sized types take up no space on the + // stack, they do cause the next argument to be aligned. + // So just do that here, but don't bother actually + // generating a new ABI step for it (there's nothing to + // actually copy). + // + // We cannot handle this in the recursive case of + // regAssign because zero-sized *fields* of a + // non-zero-sized struct do not cause it to be + // stack-assigned. So we need a special case here + // at the top. + a.stackBytes = align(a.stackBytes, uintptr(t.align)) + return nil + } if !a.regAssign(t, 0) { a.steps = a.steps[:pStart] a.stackAssign(t.size, uintptr(t.align)) -- GitLab From 280c735b07af9ea313d73049b0031f466e8d1000 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 4 Mar 2021 23:12:22 -0500 Subject: [PATCH 0212/1298] cmd/go: require a module root in 'go list -m' with an unversioned path Fixes #44803 Change-Id: Ie6ee2e3bca1809c91ecedec75d2c6620da914b29 Reviewed-on: https://go-review.googlesource.com/c/go/+/298752 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/list.go | 9 +++++++-- src/cmd/go/testdata/script/mod_outside.txt | 5 +++++ src/cmd/go/testdata/script/mod_retract_versions.txt | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go index c7ef8c9fb7..44803e960b 100644 --- a/src/cmd/go/internal/modload/list.go +++ b/src/cmd/go/internal/modload/list.go @@ -72,8 +72,13 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted if search.IsRelativePath(arg) { base.Fatalf("go: cannot use relative path %s to specify module", arg) } - if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) { - base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) + if !HasModRoot() { + if arg == "all" || strings.Contains(arg, "...") { + base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) + } + if !listVersions && !strings.Contains(arg, "@") { + base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot) + } } if i := strings.Index(arg, "@"); i >= 0 { path := arg[:i] diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt index 9d4c22c77b..7c57db9f7c 100644 --- a/src/cmd/go/testdata/script/mod_outside.txt +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -61,6 +61,11 @@ stderr 'go: cannot match "all": go.mod file not found in current directory or an stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! stdout 'example.com/version' +# 'go list -m ' should fail if any of the mods lacks an explicit version. +! go list -m example.com/printversion +stderr 'go: cannot match "example.com/printversion" without -versions or an explicit version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! stdout 'example.com/version' + # 'go list -m' with wildcards should fail. Wildcards match modules in the # build list, so they aren't meaningful outside a module. ! go list -m ... diff --git a/src/cmd/go/testdata/script/mod_retract_versions.txt b/src/cmd/go/testdata/script/mod_retract_versions.txt index 961a0a1fa3..012fa15f42 100644 --- a/src/cmd/go/testdata/script/mod_retract_versions.txt +++ b/src/cmd/go/testdata/script/mod_retract_versions.txt @@ -15,3 +15,8 @@ stdout '^example.com/retract/self/pseudo ""$' go list -m -e -f $FMT --versions example.com/retract/self/pseudo@latest stdout '^example.com/retract/self/pseudo: "module example.com/retract/self/pseudo: no matching versions for query \\"latest\\"" "latest"$' + +-- go.mod -- +module test + +go 1.17 -- GitLab From 67b9ecb23b16ed63f974e6741e1f229eab023ff5 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 17 Nov 2020 12:28:40 -0500 Subject: [PATCH 0213/1298] runtime: update paniclk ordering Now that allglock is no longer taken in throw, paniclk can move to the bottom of the lock order where it belongs. There is no fundamental reason that we really need to skip checks on paniclk in lockWithRank (despite the recursive throws that could be caused by lock rank checking, startpanic_m would still allow the crash to complete). However, the partial order of lockRankPanic should be every single lock that may be held before a throw, nil dereference, out-of-bounds access, which our partial order doesn't cover. Updates #42669 Change-Id: Ic3efaea873dc2dd9fd5b0d6ccdd5319730b29a22 Reviewed-on: https://go-review.googlesource.com/c/go/+/270862 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/lockrank.go | 8 ++++---- src/runtime/lockrank_on.go | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go index b3c01ba104..23b727f4d8 100644 --- a/src/runtime/lockrank.go +++ b/src/runtime/lockrank.go @@ -44,7 +44,6 @@ const ( lockRankPollDesc lockRankSched lockRankDeadlock - lockRankPanic lockRankAllg lockRankAllp @@ -92,6 +91,7 @@ const ( // rank, we don't allow any further locks to be acquired other than more // hchan locks. lockRankHchanLeaf + lockRankPanic // Leaf locks with no dependencies, so these constants are not actually used anywhere. // There are other architecture-dependent leaf locks as well. @@ -123,7 +123,6 @@ var lockNames = []string{ lockRankPollDesc: "pollDesc", lockRankSched: "sched", lockRankDeadlock: "deadlock", - lockRankPanic: "panic", lockRankAllg: "allg", lockRankAllp: "allp", @@ -162,6 +161,7 @@ var lockNames = []string{ lockRankGFree: "gFree", lockRankHchanLeaf: "hchanLeaf", + lockRankPanic: "panic", lockRankNewmHandoff: "newmHandoff.lock", lockRankDebugPtrmask: "debugPtrmask.lock", @@ -202,8 +202,7 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankPollDesc: {}, lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc}, lockRankDeadlock: {lockRankDeadlock}, - lockRankPanic: {lockRankDeadlock}, - lockRankAllg: {lockRankSysmon, lockRankSched, lockRankPanic}, + lockRankAllg: {lockRankSysmon, lockRankSched}, lockRankAllp: {lockRankSysmon, lockRankSched}, lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers}, lockRankItab: {}, @@ -237,6 +236,7 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankGFree: {lockRankSched}, lockRankHchanLeaf: {lockRankGscan, lockRankHchanLeaf}, + lockRankPanic: {lockRankDeadlock}, // plus any other lock held on throw. lockRankNewmHandoff: {}, lockRankDebugPtrmask: {}, diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go index 7d45debaca..3958d9eeaa 100644 --- a/src/runtime/lockrank_on.go +++ b/src/runtime/lockrank_on.go @@ -65,12 +65,11 @@ func lockWithRank(l *mutex, rank lockRank) { // rank recording for it, since print/println are used when // printing out a lock ordering problem below. // - // paniclk has an ordering problem, since it can be acquired - // during a panic with any other locks held (especially if the - // panic is because of a directed segv), and yet also allg is - // acquired after paniclk in tracebackothers()). This is a genuine - // problem, so for now we don't do lock rank recording for paniclk - // either. + // paniclk is only used for fatal throw/panic. Don't do lock + // ranking recording for it, since we throw after reporting a + // lock ordering problem. Additionally, paniclk may be taken + // after effectively any lock (anywhere we might panic), which + // the partial order doesn't cover. lock2(l) return } -- GitLab From d4247f516724cae2e84a4d1bef71bd47aa2fd1d8 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 5 Mar 2021 15:59:12 +0000 Subject: [PATCH 0214/1298] text/template: wrap errors returned by template functions instead of stringifying them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #34201 Change-Id: Ic2e2967e4b01167345cf38bd006cabb206a64377 GitHub-Last-Rev: 5d0c4856550614484a8dbfb68c37aa1abcfcc529 GitHub-Pull-Request: golang/go#42398 Reviewed-on: https://go-review.googlesource.com/c/go/+/267838 Reviewed-by: Daniel Martí Trust: Daniel Martí Trust: Pontus Leitzler Trust: Cuong Manh Le Run-TryBot: Daniel Martí TryBot-Result: Go Bot --- src/text/template/exec.go | 2 +- src/text/template/exec_test.go | 22 ++++++++++++++++++++++ src/text/template/funcs.go | 5 ++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 4637b2035f..f1305a29a0 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -727,7 +727,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a // error to the caller. if err != nil { s.at(node) - s.errorf("error calling %s: %v", name, err) + s.errorf("error calling %s: %w", name, err) } if v.Type() == reflectValueType { v = v.Interface().(reflect.Value) diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 1a129ed5af..255b111b34 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -902,6 +902,28 @@ func TestExecError(t *testing.T) { } } +type CustomError struct{} + +func (*CustomError) Error() string { return "heyo !" } + +// Check that a custom error can be returned. +func TestExecError_CustomError(t *testing.T) { + failingFunc := func() (string, error) { + return "", &CustomError{} + } + tmpl := Must(New("top").Funcs(FuncMap{ + "err": failingFunc, + }).Parse("{{ err }}")) + + var b bytes.Buffer + err := tmpl.Execute(&b, nil) + + var e *CustomError + if !errors.As(err, &e) { + t.Fatalf("expected custom error; got %s", err) + } +} + func TestJSEscaping(t *testing.T) { testCases := []struct { in, exp string diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index 1b6940a84a..9dd332c068 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -23,6 +23,9 @@ import ( // return value evaluates to non-nil during execution, execution terminates and // Execute returns that error. // +// Errors returned by Execute wrap the underlying error; call errors.As to +// uncover them. +// // When template execution invokes a function with an argument list, that list // must be assignable to the function's parameter types. Functions meant to // apply to arguments of arbitrary type can use parameters of type interface{} or @@ -344,7 +347,7 @@ func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { var err error if argv[i], err = prepareArg(arg, argType); err != nil { - return reflect.Value{}, fmt.Errorf("arg %d: %s", i, err) + return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err) } } return safeCall(fn, argv) -- GitLab From 70b277cf2e953bb9994b00898280f4659a47471e Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 14:27:36 +0700 Subject: [PATCH 0215/1298] cmd/compile: only check return for valid functions CheckReturn uses fn.Type() unconditionally, so for invalid function, fn.Type() will be nil, causes the compiler crashes. Updates #43311 Change-Id: I4420dd296c72ea83986b38fbf2c7f51fa59757c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/298709 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 2 +- test/fixedbugs/issue17588.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 240f0409e7..030158b1a1 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -2104,7 +2104,7 @@ func CheckUnused(fn *ir.Func) { // CheckReturn makes sure that fn terminates appropriately. func CheckReturn(fn *ir.Func) { - if fn.Type().NumResults() != 0 && len(fn.Body) != 0 { + if fn.Type() != nil && fn.Type().NumResults() != 0 && len(fn.Body) != 0 { markBreak(fn) if !isTermNodes(fn.Body) { base.ErrorfAt(fn.Endlineno, "missing return at end of function") diff --git a/test/fixedbugs/issue17588.go b/test/fixedbugs/issue17588.go index ed5312fa21..5c0787bf1d 100644 --- a/test/fixedbugs/issue17588.go +++ b/test/fixedbugs/issue17588.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,10 +11,10 @@ package p -type F func(b T) // ERROR "T .*is not a type|expected type" +type F func(b T) // ERROR "T .*is not a type|expected type" func T(fn F) { - func() { - fn(nil) // If Decldepth is not initialized properly, typecheckclosure() Fatals here. - }() + func() { + fn(nil) // If Decldepth is not initialized properly, typecheckclosure() Fatals here. + }() } -- GitLab From 80098ef00c1c8a832b2d67d7cbd4dea5f8eff6e9 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 14:40:50 +0700 Subject: [PATCH 0216/1298] cmd/compile: don't expand invalid embedded interface The invalid interface type will be reported already, so don't expand that invalid one, which causes the compiler crashes. Updates #43311 Change-Id: Ic335cfa74f0b9fcfd0929dc5fd31d9156a8f5f5c Reviewed-on: https://go-review.googlesource.com/c/go/+/298710 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/types/size.go | 2 +- test/fixedbugs/issue20245.go | 2 +- test/fixedbugs/issue22921.go | 2 +- test/fixedbugs/issue27938.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index 4c7378560c..ef23cdf5fe 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -100,7 +100,7 @@ func expandiface(t *Type) { } for _, m := range t.Methods().Slice() { - if m.Sym != nil { + if m.Sym != nil || m.Type == nil { continue } diff --git a/test/fixedbugs/issue20245.go b/test/fixedbugs/issue20245.go index b07dbe20de..20258231d1 100644 --- a/test/fixedbugs/issue20245.go +++ b/test/fixedbugs/issue20245.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue22921.go b/test/fixedbugs/issue22921.go index 5336ba3410..cdd77fb24f 100644 --- a/test/fixedbugs/issue22921.go +++ b/test/fixedbugs/issue22921.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue27938.go b/test/fixedbugs/issue27938.go index ed974e642d..2589e1eff8 100644 --- a/test/fixedbugs/issue27938.go +++ b/test/fixedbugs/issue27938.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- GitLab From 51d8d351c1bb2cac74e1bbf8545245cdbc8914c3 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 20:56:01 +0700 Subject: [PATCH 0217/1298] cmd/compile: do not set type for OTYPESW Same as CL 294031, but for OTYPESW. Updates #43311 Change-Id: I996f5938835baff1d830c17ed75652315106bdfd Reviewed-on: https://go-review.googlesource.com/c/go/+/298712 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 2 +- test/fixedbugs/issue24470.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 030158b1a1..647465af4f 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -876,7 +876,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OTYPESW: n := n.(*ir.TypeSwitchGuard) base.Errorf("use of .(type) outside type switch") - n.SetType(nil) + n.SetDiag(true) return n case ir.ODCLFUNC: diff --git a/test/fixedbugs/issue24470.go b/test/fixedbugs/issue24470.go index 2805998cca..5b7b2b5adf 100644 --- a/test/fixedbugs/issue24470.go +++ b/test/fixedbugs/issue24470.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -10,7 +10,7 @@ package p func f(i interface{}) { - if x, ok := i.(type); ok { // ERROR "outside type switch" + if x, ok := i.(type); ok { // ERROR "assignment mismatch|outside type switch" _ = x } } -- GitLab From 9e6b1fcd0a42db0f4699ff17e3b248e563f7eee4 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 22:24:58 +0700 Subject: [PATCH 0218/1298] cmd/compile: do not report error for invalid constant Invalid constant was already reported by noder, so don't re-check in typecheck, which lead to compiler crashing. Updates #43311 Change-Id: I48e2f540601cef725c1ff628c066ed15d848e771 Reviewed-on: https://go-review.googlesource.com/c/go/+/298713 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/noder/noder.go | 2 +- src/cmd/compile/internal/typecheck/typecheck.go | 4 +++- test/char_lit1.go | 2 +- test/fixedbugs/issue20232.go | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 8c456e4561..4c7c9fc322 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -689,7 +689,7 @@ func (p *noder) expr(expr syntax.Expr) ir.Node { if expr.Kind == syntax.RuneLit { n.SetType(types.UntypedRune) } - n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error + n.SetDiag(expr.Bad || n.Val().Kind() == constant.Unknown) // avoid follow-on errors if there was a syntax error return n case *syntax.CompositeLit: n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, p.typeExpr(expr.Type), nil) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 647465af4f..548c1af85c 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -482,7 +482,9 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OLITERAL: if n.Sym() == nil && n.Type() == nil { - base.Fatalf("literal missing type: %v", n) + if !n.Diag() { + base.Fatalf("literal missing type: %v", n) + } } return n diff --git a/test/char_lit1.go b/test/char_lit1.go index 489744b6e9..8899aff83a 100644 --- a/test/char_lit1.go +++ b/test/char_lit1.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue20232.go b/test/fixedbugs/issue20232.go index 7a0300a4c4..846843dccb 100644 --- a/test/fixedbugs/issue20232.go +++ b/test/fixedbugs/issue20232.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- GitLab From fbee173545da4ecbdd80a59edcb93e6c4605241f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 22:27:41 +0700 Subject: [PATCH 0219/1298] cmd/compile: fix wrong condition in tcShift CL 279442 refactored typecheck arithmetic operators, but using wrong condition for checking invalid rhs. Updates #43311 Change-Id: I7a03a5535b82ac4ea4806725776b0a4f7af1b79a Reviewed-on: https://go-review.googlesource.com/c/go/+/298714 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/expr.go | 2 +- test/fixedbugs/bug297.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 339fb00aa4..10a4c1b1dc 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -48,7 +48,7 @@ func tcAddr(n *ir.AddrExpr) ir.Node { } func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) { - if l.Type() == nil || l.Type() == nil { + if l.Type() == nil || r.Type() == nil { return l, r, nil } diff --git a/test/fixedbugs/bug297.go b/test/fixedbugs/bug297.go index c2bd253d05..70eb4ca9b2 100644 --- a/test/fixedbugs/bug297.go +++ b/test/fixedbugs/bug297.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -9,7 +9,8 @@ package main type ByteSize float64 + const ( - _ = iota; // ignore first value by assigning to blank identifier - KB ByteSize = 1<<(10*X) // ERROR "undefined" + _ = iota // ignore first value by assigning to blank identifier + KB ByteSize = 1 << (10 * X) // ERROR "undefined" ) -- GitLab From c082f9fee0e08ac5ea6498ade1153fb6e68f7c72 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 15:06:38 +0700 Subject: [PATCH 0220/1298] cmd/compile: do not set ONAME type when evaluated in type context Updates #43311 Change-Id: I26e397d071b434256dab0cc7fff9d134b80bd6e3 Reviewed-on: https://go-review.googlesource.com/c/go/+/298711 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/typecheck.go | 6 +++++- test/fixedbugs/issue22389.go | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 548c1af85c..30632ac18b 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -446,7 +446,11 @@ func typecheck(n ir.Node, top int) (res ir.Node) { case top&(ctxType|ctxExpr) == ctxType && n.Op() != ir.OTYPE && n.Op() != ir.ONONAME && (t != nil || n.Op() == ir.ONAME): base.Errorf("%v is not a type", n) if t != nil { - n.SetType(nil) + if n.Op() == ir.ONAME { + t.SetBroke(true) + } else { + n.SetType(nil) + } } } diff --git a/test/fixedbugs/issue22389.go b/test/fixedbugs/issue22389.go index 75dc285403..81e6d94e65 100644 --- a/test/fixedbugs/issue22389.go +++ b/test/fixedbugs/issue22389.go @@ -1,4 +1,4 @@ -// errorcheck +// errorcheck -d=panic // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- GitLab From 44721f4565858526545c69b4846daeea40843a98 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 4 Mar 2021 22:31:43 +0700 Subject: [PATCH 0221/1298] test: enable "-d=panic" by default for errorcheck* Fixes #43311 Change-Id: I134d6c0524c198998a3c093dd3a8144052e8f7a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/298715 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- test/run.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/run.go b/test/run.go index 570768e680..4c01886560 100644 --- a/test/run.go +++ b/test/run.go @@ -725,7 +725,7 @@ func (t *test) run() { // Fail if wantError is true and compilation was successful and vice versa. // Match errors produced by gc against errors in comments. // TODO(gri) remove need for -C (disable printing of columns in error messages) - cmdline := []string{goTool(), "tool", "compile", "-C", "-e", "-o", "a.o"} + cmdline := []string{goTool(), "tool", "compile", "-d=panic", "-C", "-e", "-o", "a.o"} // No need to add -dynlink even if linkshared if we're just checking for errors... cmdline = append(cmdline, flags...) cmdline = append(cmdline, long) @@ -830,6 +830,7 @@ func (t *test) run() { } case "errorcheckdir", "errorcheckandrundir": + flags = append(flags, "-d=panic") // Compile and errorCheck all files in the directory as packages in lexicographic order. // If errorcheckdir and wantError, compilation of the last package must fail. // If errorcheckandrundir and wantError, compilation of the package prior the last must fail. @@ -1179,7 +1180,7 @@ func (t *test) run() { t.err = fmt.Errorf("write tempfile:%s", err) return } - cmdline := []string{goTool(), "tool", "compile", "-e", "-o", "a.o"} + cmdline := []string{goTool(), "tool", "compile", "-d=panic", "-e", "-o", "a.o"} cmdline = append(cmdline, flags...) cmdline = append(cmdline, tfile) out, err = runcmd(cmdline...) -- GitLab From 39bdd41d03725878f1fd6f8b500ba6700f03bdad Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Tue, 2 Mar 2021 11:54:36 -0800 Subject: [PATCH 0222/1298] cmd/go/internal/modfetch/codehost: report git errors more accurately Previously, if you attempted to fetch a private repository, or your Git/curl client failed for an unknown reason, codehost would return an UnknownRevisionError, which reported that a given revision in go.mod was "unknown". This is confusing to many users who can go look in their browser for example and see that the commit-ish exists. Instead check whether "git ls-remote" exited with an error, and if so, return that instead of the UnknownRevision message. Fixes #42751. Change-Id: I0dbded878b2818280e61126a4493767d719ad577 Reviewed-on: https://go-review.googlesource.com/c/go/+/297950 Reviewed-by: Bryan C. Mills Trust: Bryan C. Mills Trust: Jay Conrod Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/modfetch/codehost/git.go | 6 ++++ .../testdata/script/mod_get_private_vcs.txt | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 72005e27d5..4d4964edf4 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -296,6 +296,9 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) { // Or maybe it's the prefix of a hash of a named ref. // Try to resolve to both a ref (git name) and full (40-hex-digit) commit hash. r.refsOnce.Do(r.loadRefs) + // loadRefs may return an error if git fails, for example segfaults, or + // could not load a private repo, but defer checking to the else block + // below, in case we already have the rev in question in the local cache. var ref, hash string if r.refs["refs/tags/"+rev] != "" { ref = "refs/tags/" + rev @@ -332,6 +335,9 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) { hash = rev } } else { + if r.refsErr != nil { + return nil, r.refsErr + } return nil, &UnknownRevisionError{Rev: rev} } diff --git a/src/cmd/go/testdata/script/mod_get_private_vcs.txt b/src/cmd/go/testdata/script/mod_get_private_vcs.txt index 514b0a7a53..8b01eac62c 100644 --- a/src/cmd/go/testdata/script/mod_get_private_vcs.txt +++ b/src/cmd/go/testdata/script/mod_get_private_vcs.txt @@ -9,3 +9,33 @@ env GOPROXY=direct stderr 'Confirm the import path was entered correctly.' stderr 'If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.' ! stdout . + +# Fetching a nonexistent commit should return an "unknown revision" +# error message. +! go get github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b +stderr '^go get: github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b: invalid version: unknown revision 86186f3aba07ed0212cfb944f3398997d2d07c6b$' +! stdout . + +! go get github.com/golang/nonexist@master +stderr '^Confirm the import path was entered correctly.$' +stderr '^If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.$' +! stderr 'unknown revision' +! stdout . + +[!linux] stop + +# Test that Git clone errors will be shown to the user instead of a generic +# "unknown revision" error. To do this we want to force git ls-remote to return +# an error we don't already have special handling for. See golang/go#42751. +# +# Set XDG_CONFIG_HOME to tell Git where to look for the git config file listed +# below, which turns on ssh. +env XDG_CONFIG_HOME=$TMPDIR +! go install github.com/golang/nonexist@master +stderr 'fatal: Could not read from remote repository.' +! stderr 'unknown revision' +! stdout . + +-- $TMPDIR/git/config -- +[url "git@github.com:"] + insteadOf = https://github.com/ -- GitLab From d85083911d6ea742901933a544467dad55bb381f Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 23 Dec 2020 15:05:37 -0500 Subject: [PATCH 0223/1298] runtime: encapsulate access to allgs Correctly accessing allgs is a bit hairy. Some paths need to lock allglock, some don't. Those that don't are safest using atomicAllG, but usage is not consistent. Rather than doing this ad-hoc, move all access* through forEachG / forEachGRace, the locking and atomic versions, respectively. This will make it easier to ensure safe access. * markroot is the only exception, as it has a far-removed guarantee of safe access via an atomic load of allglen far before actual use. Change-Id: Ie1c7a8243e155ae2b4bc3143577380c695680e89 Reviewed-on: https://go-review.googlesource.com/c/go/+/279994 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/heapdump.go | 7 ++++--- src/runtime/mgc.go | 8 +++----- src/runtime/mgcmark.go | 32 +++++++++++++++++++------------- src/runtime/mprof.go | 35 +++++++++++++++++++---------------- src/runtime/proc.go | 40 +++++++++++++++++++++++++++++----------- src/runtime/trace.go | 5 +++-- src/runtime/traceback.go | 21 +++++++++------------ 7 files changed, 86 insertions(+), 62 deletions(-) diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 2d531571aa..1b8c19b476 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -403,9 +403,10 @@ func dumpgoroutine(gp *g) { } func dumpgs() { + assertWorldStopped() + // goroutines & stacks - for i := 0; uintptr(i) < allglen; i++ { - gp := allgs[i] + forEachG(func(gp *g) { status := readgstatus(gp) // The world is stopped so gp will not be in a scan state. switch status { default: @@ -418,7 +419,7 @@ func dumpgs() { _Gwaiting: dumpgoroutine(gp) } - } + }) } func finq_callback(fn *funcval, obj unsafe.Pointer, nret uintptr, fint *_type, ot *ptrtype) { diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 7c7239beb8..6927e90daa 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -2229,14 +2229,12 @@ func gcSweep(mode gcMode) { // //go:systemstack func gcResetMarkState() { - // This may be called during a concurrent phase, so make sure + // This may be called during a concurrent phase, so lock to make sure // allgs doesn't change. - lock(&allglock) - for _, gp := range allgs { + forEachG(func(gp *g) { gp.gcscandone = false // set to true in gcphasework gp.gcAssistBytes = 0 - } - unlock(&allglock) + }) // Clear page marks. This is just 1MB per 64GB of heap, so the // time here is pretty trivial. diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 46fae5de72..b3c1e00ca5 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -116,23 +116,26 @@ func gcMarkRootCheck() { throw("left over markroot jobs") } - lock(&allglock) // Check that stacks have been scanned. - var gp *g - for i := 0; i < work.nStackRoots; i++ { - gp = allgs[i] + // + // We only check the first nStackRoots Gs that we should have scanned. + // Since we don't care about newer Gs (see comment in + // gcMarkRootPrepare), no locking is required. + i := 0 + forEachGRace(func(gp *g) { + if i >= work.nStackRoots { + return + } + if !gp.gcscandone { - goto fail + println("gp", gp, "goid", gp.goid, + "status", readgstatus(gp), + "gcscandone", gp.gcscandone) + throw("scan missed a g") } - } - unlock(&allglock) - return -fail: - println("gp", gp, "goid", gp.goid, - "status", readgstatus(gp), - "gcscandone", gp.gcscandone) - throw("scan missed a g") + i++ + }) } // ptrmask for an allocation containing a single pointer. @@ -189,6 +192,9 @@ func markroot(gcw *gcWork, i uint32) { // the rest is scanning goroutine stacks var gp *g if baseStacks <= i && i < end { + // N.B. Atomic read of allglen in gcMarkRootPrepare + // acts as a barrier to ensure that allgs must be large + // enough to contain all relevant Gs. gp = allgs[i-baseStacks] } else { throw("markroot: bad index") diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index 128498d69b..c94b8f7cae 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -731,12 +731,13 @@ func goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int stopTheWorld("profile") + // World is stopped, no locking required. n = 1 - for _, gp1 := range allgs { + forEachGRace(func(gp1 *g) { if isOK(gp1) { n++ } - } + }) if n <= len(p) { ok = true @@ -757,21 +758,23 @@ func goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int } // Save other goroutines. - for _, gp1 := range allgs { - if isOK(gp1) { - if len(r) == 0 { - // Should be impossible, but better to return a - // truncated profile than to crash the entire process. - break - } - saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) - if labels != nil { - lbl[0] = gp1.labels - lbl = lbl[1:] - } - r = r[1:] + forEachGRace(func(gp1 *g) { + if !isOK(gp1) { + return } - } + + if len(r) == 0 { + // Should be impossible, but better to return a + // truncated profile than to crash the entire process. + return + } + saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) + if labels != nil { + lbl[0] = gp1.labels + lbl = lbl[1:] + } + r = r[1:] + }) } startTheWorld() diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 19049d21f3..5f372bb063 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -541,6 +541,30 @@ func atomicAllGIndex(ptr **g, i uintptr) *g { return *(**g)(add(unsafe.Pointer(ptr), i*sys.PtrSize)) } +// forEachG calls fn on every G from allgs. +// +// forEachG takes a lock to exclude concurrent addition of new Gs. +func forEachG(fn func(gp *g)) { + lock(&allglock) + for _, gp := range allgs { + fn(gp) + } + unlock(&allglock) +} + +// forEachGRace calls fn on every G from allgs. +// +// forEachGRace avoids locking, but does not exclude addition of new Gs during +// execution, which may be missed. +func forEachGRace(fn func(gp *g)) { + ptr, length := atomicAllG() + for i := uintptr(0); i < length; i++ { + gp := atomicAllGIndex(ptr, i) + fn(gp) + } + return +} + const ( // Number of goroutine ids to grab from sched.goidgen to local per-P cache at once. // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. @@ -4969,11 +4993,9 @@ func checkdead() { } grunning := 0 - lock(&allglock) - for i := 0; i < len(allgs); i++ { - gp := allgs[i] + forEachG(func(gp *g) { if isSystemGoroutine(gp, false) { - continue + return } s := readgstatus(gp) switch s &^ _Gscan { @@ -4986,8 +5008,7 @@ func checkdead() { print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n") throw("checkdead: runnable g") } - } - unlock(&allglock) + }) if grunning == 0 { // possible if main goroutine calls runtime·Goexit() unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang throw("no goroutines (main called runtime.Goexit) - deadlock!") @@ -5390,9 +5411,7 @@ func schedtrace(detailed bool) { print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=", id3, "\n") } - lock(&allglock) - for gi := 0; gi < len(allgs); gi++ { - gp := allgs[gi] + forEachG(func(gp *g) { mp := gp.m lockedm := gp.lockedm.ptr() id1 := int64(-1) @@ -5404,8 +5423,7 @@ func schedtrace(detailed bool) { id2 = lockedm.id } print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=", id1, " lockedm=", id2, "\n") - } - unlock(&allglock) + }) unlock(&sched.lock) } diff --git a/src/runtime/trace.go b/src/runtime/trace.go index bcd0b9d56c..bfaa00ee58 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -221,7 +221,8 @@ func StartTrace() error { stackID := traceStackID(mp, stkBuf, 2) releasem(mp) - for _, gp := range allgs { + // World is stopped, no need to lock. + forEachGRace(func(gp *g) { status := readgstatus(gp) if status != _Gdead { gp.traceseq = 0 @@ -241,7 +242,7 @@ func StartTrace() error { } else { gp.sysblocktraced = false } - } + }) traceProcStart() traceGoStart() // Note: ticksStart needs to be set after we emit traceEvGoInSyscall events. diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 53eb689848..f8cda83098 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -945,19 +945,16 @@ func tracebackothers(me *g) { traceback(^uintptr(0), ^uintptr(0), 0, curgp) } - // We can't take allglock here because this may be during fatal - // throw/panic, where locking allglock could be out-of-order or a - // direct deadlock. + // We can't call locking forEachG here because this may be during fatal + // throw/panic, where locking could be out-of-order or a direct + // deadlock. // - // Instead, use atomic access to allgs which requires no locking. We - // don't lock against concurrent creation of new Gs, but even with - // allglock we may miss Gs created after this loop. - ptr, length := atomicAllG() - for i := uintptr(0); i < length; i++ { - gp := atomicAllGIndex(ptr, i) - + // Instead, use forEachGRace, which requires no locking. We don't lock + // against concurrent creation of new Gs, but even with allglock we may + // miss Gs created after this loop. + forEachGRace(func(gp *g) { if gp == me || gp == curgp || readgstatus(gp) == _Gdead || isSystemGoroutine(gp, false) && level < 2 { - continue + return } print("\n") goroutineheader(gp) @@ -971,7 +968,7 @@ func tracebackothers(me *g) { } else { traceback(^uintptr(0), ^uintptr(0), 0, gp) } - } + }) } // tracebackHexdump hexdumps part of stk around frame.sp and frame.fp -- GitLab From a829114b21b5a4238dea13dc97b030d650935ed8 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 5 Mar 2021 15:12:37 -0500 Subject: [PATCH 0224/1298] cmd/compile: match Aux and AuxInt explicitly in store combining rule CL 280456 introduced a new store combining rule. On the LHS some of the Aux and AuxInt of the stores are not specified, therefore ignored during the matching. The rule is only correct if they match. This CL adds explict match. TODO: maybe we want the rule matcher require Aux/AuxInt to be always specified on the LHS (using _ to explicitly ignore)? Or maybe we want it to match the zero value if not specified? The current approach is error-prone. Fixes #44823. Change-Id: Ic12b4a0de63117f2f070039737f0c905f28561bc Reviewed-on: https://go-review.googlesource.com/c/go/+/299289 Trust: Cherry Zhang Trust: Josh Bleecher Snyder Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/gen/AMD64.rules | 10 ++++---- src/cmd/compile/internal/ssa/gen/S390X.rules | 10 ++++---- src/cmd/compile/internal/ssa/rewriteAMD64.go | 12 +++++---- src/cmd/compile/internal/ssa/rewriteS390X.go | 12 +++++---- test/fixedbugs/issue44823.go | 26 ++++++++++++++++++++ 5 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 test/fixedbugs/issue44823.go diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index bab9cee88c..7b03034bb7 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -1970,15 +1970,15 @@ && clobber(x) => (MOVQstore [i] {s} p0 w0 mem) -(MOVBstore [7] p1 (SHRQconst [56] w) - x1:(MOVWstore [5] p1 (SHRQconst [40] w) - x2:(MOVLstore [1] p1 (SHRQconst [8] w) - x3:(MOVBstore p1 w mem)))) +(MOVBstore [7] {s} p1 (SHRQconst [56] w) + x1:(MOVWstore [5] {s} p1 (SHRQconst [40] w) + x2:(MOVLstore [1] {s} p1 (SHRQconst [8] w) + x3:(MOVBstore [0] {s} p1 w mem)))) && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) - => (MOVQstore p1 w mem) + => (MOVQstore {s} p1 w mem) (MOVBstore [i] {s} p x1:(MOVBload [j] {s2} p2 mem) diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index e4a1cd6981..1f75f78a71 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -1422,15 +1422,15 @@ && clobber(x) => (MOVDBRstore [i-4] {s} p w0 mem) -(MOVBstore [7] p1 (SRDconst w) - x1:(MOVHBRstore [5] p1 (SRDconst w) - x2:(MOVWBRstore [1] p1 (SRDconst w) - x3:(MOVBstore p1 w mem)))) +(MOVBstore [7] {s} p1 (SRDconst w) + x1:(MOVHBRstore [5] {s} p1 (SRDconst w) + x2:(MOVWBRstore [1] {s} p1 (SRDconst w) + x3:(MOVBstore [0] {s} p1 w mem)))) && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) - => (MOVDBRstore p1 w mem) + => (MOVDBRstore {s} p1 w mem) // Combining byte loads into larger (unaligned) loads. diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 52d0fd095d..8da3b28b5c 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -11415,20 +11415,21 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(p0, w0, mem) return true } - // match: (MOVBstore [7] p1 (SHRQconst [56] w) x1:(MOVWstore [5] p1 (SHRQconst [40] w) x2:(MOVLstore [1] p1 (SHRQconst [8] w) x3:(MOVBstore p1 w mem)))) + // match: (MOVBstore [7] {s} p1 (SHRQconst [56] w) x1:(MOVWstore [5] {s} p1 (SHRQconst [40] w) x2:(MOVLstore [1] {s} p1 (SHRQconst [8] w) x3:(MOVBstore [0] {s} p1 w mem)))) // cond: x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) - // result: (MOVQstore p1 w mem) + // result: (MOVQstore {s} p1 w mem) for { if auxIntToInt32(v.AuxInt) != 7 { break } + s := auxToSym(v.Aux) p1 := v_0 if v_1.Op != OpAMD64SHRQconst || auxIntToInt8(v_1.AuxInt) != 56 { break } w := v_1.Args[0] x1 := v_2 - if x1.Op != OpAMD64MOVWstore || auxIntToInt32(x1.AuxInt) != 5 { + if x1.Op != OpAMD64MOVWstore || auxIntToInt32(x1.AuxInt) != 5 || auxToSym(x1.Aux) != s { break } _ = x1.Args[2] @@ -11440,7 +11441,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } x2 := x1.Args[2] - if x2.Op != OpAMD64MOVLstore || auxIntToInt32(x2.AuxInt) != 1 { + if x2.Op != OpAMD64MOVLstore || auxIntToInt32(x2.AuxInt) != 1 || auxToSym(x2.Aux) != s { break } _ = x2.Args[2] @@ -11452,7 +11453,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } x3 := x2.Args[2] - if x3.Op != OpAMD64MOVBstore { + if x3.Op != OpAMD64MOVBstore || auxIntToInt32(x3.AuxInt) != 0 || auxToSym(x3.Aux) != s { break } mem := x3.Args[2] @@ -11460,6 +11461,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { break } v.reset(OpAMD64MOVQstore) + v.Aux = symToAux(s) v.AddArg3(p1, w, mem) return true } diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index e0a5ff4cbb..85260dace8 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -8883,20 +8883,21 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { v.AddArg3(p, w0, mem) return true } - // match: (MOVBstore [7] p1 (SRDconst w) x1:(MOVHBRstore [5] p1 (SRDconst w) x2:(MOVWBRstore [1] p1 (SRDconst w) x3:(MOVBstore p1 w mem)))) + // match: (MOVBstore [7] {s} p1 (SRDconst w) x1:(MOVHBRstore [5] {s} p1 (SRDconst w) x2:(MOVWBRstore [1] {s} p1 (SRDconst w) x3:(MOVBstore [0] {s} p1 w mem)))) // cond: x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && clobber(x1, x2, x3) - // result: (MOVDBRstore p1 w mem) + // result: (MOVDBRstore {s} p1 w mem) for { if auxIntToInt32(v.AuxInt) != 7 { break } + s := auxToSym(v.Aux) p1 := v_0 if v_1.Op != OpS390XSRDconst { break } w := v_1.Args[0] x1 := v_2 - if x1.Op != OpS390XMOVHBRstore || auxIntToInt32(x1.AuxInt) != 5 { + if x1.Op != OpS390XMOVHBRstore || auxIntToInt32(x1.AuxInt) != 5 || auxToSym(x1.Aux) != s { break } _ = x1.Args[2] @@ -8908,7 +8909,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x2 := x1.Args[2] - if x2.Op != OpS390XMOVWBRstore || auxIntToInt32(x2.AuxInt) != 1 { + if x2.Op != OpS390XMOVWBRstore || auxIntToInt32(x2.AuxInt) != 1 || auxToSym(x2.Aux) != s { break } _ = x2.Args[2] @@ -8920,7 +8921,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x3 := x2.Args[2] - if x3.Op != OpS390XMOVBstore { + if x3.Op != OpS390XMOVBstore || auxIntToInt32(x3.AuxInt) != 0 || auxToSym(x3.Aux) != s { break } mem := x3.Args[2] @@ -8928,6 +8929,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } v.reset(OpS390XMOVDBRstore) + v.Aux = symToAux(s) v.AddArg3(p1, w, mem) return true } diff --git a/test/fixedbugs/issue44823.go b/test/fixedbugs/issue44823.go new file mode 100644 index 0000000000..85811df67d --- /dev/null +++ b/test/fixedbugs/issue44823.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2021 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 44823: miscompilation with store combining. + +package main + +import "encoding/binary" + +//go:noinline +func Id(a [8]byte) (x [8]byte) { + binary.LittleEndian.PutUint64(x[:], binary.LittleEndian.Uint64(a[:])) + return +} + +var a = [8]byte{1, 2, 3, 4, 5, 6, 7, 8} + +func main() { + x := Id(a) + if x != a { + panic("FAIL") + } +} -- GitLab From a22bd3dc73bfcc9bf37cbd651933c54c82799c2a Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 1 Mar 2021 19:23:42 -0500 Subject: [PATCH 0225/1298] cmd/compile: use getcallerpc for racefuncentry Currently, when instrumenting for the race detector, the compiler inserts racefuncentry/racefuncentryfp at the entry of instrumented functions. racefuncentry takes the caller's PC. On AMD64, we synthesize a node which points to -8(FP) which is where the return address is stored. Later this node turns to a special Arg in SSA that is not really an argument. This causes problems in the new ABI work so that special node has to be special-cased. This CL changes the special node to a call to getcallerpc, which lowers to an intrinsic in SSA. This also unifies AMD64 code path and LR machine code path, as getcallerpc works on all platforms. Change-Id: I1377e140b91e0473cfcadfda221f26870c1b124d Reviewed-on: https://go-review.googlesource.com/c/go/+/297929 Trust: Cherry Zhang Reviewed-by: David Chase --- src/cmd/compile/internal/base/base.go | 2 +- src/cmd/compile/internal/ssa/rewrite.go | 6 +- src/cmd/compile/internal/ssagen/ssa.go | 3 + src/cmd/compile/internal/typecheck/builtin.go | 57 ++++++++++--------- .../internal/typecheck/builtin/runtime.go | 4 +- src/cmd/compile/internal/walk/race.go | 27 ++------- 6 files changed, 44 insertions(+), 55 deletions(-) diff --git a/src/cmd/compile/internal/base/base.go b/src/cmd/compile/internal/base/base.go index 3b9bc3a8af..4c2516f60e 100644 --- a/src/cmd/compile/internal/base/base.go +++ b/src/cmd/compile/internal/base/base.go @@ -70,6 +70,6 @@ var NoInstrumentPkgs = []string{ "internal/cpu", } -// Don't insert racefuncenterfp/racefuncexit into the following packages. +// Don't insert racefuncenter/racefuncexit into the following packages. // Memory accesses in the packages are either uninteresting or will cause false positives. var NoRacePkgs = []string{"sync", "sync/atomic"} diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 9243000cef..07bbdb8813 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -1612,18 +1612,18 @@ func needRaceCleanup(sym *AuxCall, v *Value) bool { if !f.Config.Race { return false } - if !isSameCall(sym, "runtime.racefuncenter") && !isSameCall(sym, "runtime.racefuncenterfp") && !isSameCall(sym, "runtime.racefuncexit") { + if !isSameCall(sym, "runtime.racefuncenter") && !isSameCall(sym, "runtime.racefuncexit") { return false } for _, b := range f.Blocks { for _, v := range b.Values { switch v.Op { case OpStaticCall, OpStaticLECall: - // Check for racefuncenter/racefuncenterfp will encounter racefuncexit and vice versa. + // Check for racefuncenter will encounter racefuncexit and vice versa. // Allow calls to panic* s := v.Aux.(*AuxCall).Fn.String() switch s { - case "runtime.racefuncenter", "runtime.racefuncenterfp", "runtime.racefuncexit", + case "runtime.racefuncenter", "runtime.racefuncexit", "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift": continue diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index b590bd4f2f..961cae419a 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -4564,6 +4564,9 @@ func findIntrinsic(sym *types.Sym) intrinsicBuilder { if sym.Pkg == types.LocalPkg { pkg = base.Ctxt.Pkgpath } + if sym.Pkg == ir.Pkgs.Runtime { + pkg = "runtime" + } if base.Flag.Race && pkg == "sync/atomic" { // The race detector needs to be able to intercept these calls. // We can't intrinsify them. diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 3c7776d9ae..ddec26df59 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -177,26 +177,26 @@ var runtimeDecls = [...]struct { {"uint64tofloat64", funcTag, 116}, {"uint32tofloat64", funcTag, 117}, {"complex128div", funcTag, 118}, + {"getcallerpc", funcTag, 119}, {"racefuncenter", funcTag, 31}, - {"racefuncenterfp", funcTag, 9}, {"racefuncexit", funcTag, 9}, {"raceread", funcTag, 31}, {"racewrite", funcTag, 31}, - {"racereadrange", funcTag, 119}, - {"racewriterange", funcTag, 119}, - {"msanread", funcTag, 119}, - {"msanwrite", funcTag, 119}, - {"msanmove", funcTag, 120}, - {"checkptrAlignment", funcTag, 121}, - {"checkptrArithmetic", funcTag, 123}, - {"libfuzzerTraceCmp1", funcTag, 125}, - {"libfuzzerTraceCmp2", funcTag, 127}, - {"libfuzzerTraceCmp4", funcTag, 128}, - {"libfuzzerTraceCmp8", funcTag, 129}, - {"libfuzzerTraceConstCmp1", funcTag, 125}, - {"libfuzzerTraceConstCmp2", funcTag, 127}, - {"libfuzzerTraceConstCmp4", funcTag, 128}, - {"libfuzzerTraceConstCmp8", funcTag, 129}, + {"racereadrange", funcTag, 120}, + {"racewriterange", funcTag, 120}, + {"msanread", funcTag, 120}, + {"msanwrite", funcTag, 120}, + {"msanmove", funcTag, 121}, + {"checkptrAlignment", funcTag, 122}, + {"checkptrArithmetic", funcTag, 124}, + {"libfuzzerTraceCmp1", funcTag, 126}, + {"libfuzzerTraceCmp2", funcTag, 128}, + {"libfuzzerTraceCmp4", funcTag, 129}, + {"libfuzzerTraceCmp8", funcTag, 130}, + {"libfuzzerTraceConstCmp1", funcTag, 126}, + {"libfuzzerTraceConstCmp2", funcTag, 128}, + {"libfuzzerTraceConstCmp4", funcTag, 129}, + {"libfuzzerTraceConstCmp8", funcTag, 130}, {"x86HasPOPCNT", varTag, 6}, {"x86HasSSE41", varTag, 6}, {"x86HasFMA", varTag, 6}, @@ -219,7 +219,7 @@ func params(tlist ...*types.Type) []*types.Field { } func runtimeTypes() []*types.Type { - var typs [130]*types.Type + var typs [131]*types.Type typs[0] = types.ByteType typs[1] = types.NewPtr(typs[0]) typs[2] = types.Types[types.TANY] @@ -339,16 +339,17 @@ func runtimeTypes() []*types.Type { typs[116] = newSig(params(typs[24]), params(typs[20])) typs[117] = newSig(params(typs[65]), params(typs[20])) typs[118] = newSig(params(typs[26], typs[26]), params(typs[26])) - typs[119] = newSig(params(typs[5], typs[5]), nil) - typs[120] = newSig(params(typs[5], typs[5], typs[5]), nil) - typs[121] = newSig(params(typs[7], typs[1], typs[5]), nil) - typs[122] = types.NewSlice(typs[7]) - typs[123] = newSig(params(typs[7], typs[122]), nil) - typs[124] = types.Types[types.TUINT8] - typs[125] = newSig(params(typs[124], typs[124]), nil) - typs[126] = types.Types[types.TUINT16] - typs[127] = newSig(params(typs[126], typs[126]), nil) - typs[128] = newSig(params(typs[65], typs[65]), nil) - typs[129] = newSig(params(typs[24], typs[24]), nil) + typs[119] = newSig(nil, params(typs[5])) + typs[120] = newSig(params(typs[5], typs[5]), nil) + typs[121] = newSig(params(typs[5], typs[5], typs[5]), nil) + typs[122] = newSig(params(typs[7], typs[1], typs[5]), nil) + typs[123] = types.NewSlice(typs[7]) + typs[124] = newSig(params(typs[7], typs[123]), nil) + typs[125] = types.Types[types.TUINT8] + typs[126] = newSig(params(typs[125], typs[125]), nil) + typs[127] = types.Types[types.TUINT16] + typs[128] = newSig(params(typs[127], typs[127]), nil) + typs[129] = newSig(params(typs[65], typs[65]), nil) + typs[130] = newSig(params(typs[24], typs[24]), nil) return typs[:] } diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index d5e00afcf8..8575148b5b 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -6,6 +6,7 @@ // to update builtin.go. This is not done automatically // to avoid depending on having a working compiler binary. +//go:build ignore // +build ignore package runtime @@ -224,9 +225,10 @@ func uint32tofloat64(uint32) float64 func complex128div(num complex128, den complex128) (quo complex128) +func getcallerpc() uintptr + // race detection func racefuncenter(uintptr) -func racefuncenterfp() func racefuncexit() func raceread(uintptr) func racewrite(uintptr) diff --git a/src/cmd/compile/internal/walk/race.go b/src/cmd/compile/internal/walk/race.go index 47cd2fdc22..859e5c57f0 100644 --- a/src/cmd/compile/internal/walk/race.go +++ b/src/cmd/compile/internal/walk/race.go @@ -7,11 +7,8 @@ package walk import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" - "cmd/compile/internal/ssagen" - "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/src" - "cmd/internal/sys" ) func instrument(fn *ir.Func) { @@ -26,26 +23,12 @@ func instrument(fn *ir.Func) { if base.Flag.Race { lno := base.Pos base.Pos = src.NoXPos - if ssagen.Arch.LinkArch.Arch.Family != sys.AMD64 { - fn.Enter.Prepend(mkcallstmt("racefuncenterfp")) - fn.Exit.Append(mkcallstmt("racefuncexit")) - } else { - - // nodpc is the PC of the caller as extracted by - // getcallerpc. We use -widthptr(FP) for x86. - // This only works for amd64. This will not - // work on arm or others that might support - // race in the future. - - nodpc := ir.NewNameAt(src.NoXPos, typecheck.Lookup(".fp")) - nodpc.Class = ir.PPARAM - nodpc.SetUsed(true) - nodpc.SetType(types.Types[types.TUINTPTR]) - nodpc.SetFrameOffset(int64(-types.PtrSize)) - fn.Dcl = append(fn.Dcl, nodpc) - fn.Enter.Prepend(mkcallstmt("racefuncenter", nodpc)) - fn.Exit.Append(mkcallstmt("racefuncexit")) + var init ir.Nodes + fn.Enter.Prepend(mkcallstmt("racefuncenter", mkcall("getcallerpc", types.Types[types.TUINTPTR], &init))) + if len(init) != 0 { + base.Fatalf("race walk: unexpected init for getcallerpc") } + fn.Exit.Append(mkcallstmt("racefuncexit")) base.Pos = lno } } -- GitLab From fb03be9d5577a3d22834a25b3b62916aee30db2a Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 2 Mar 2021 10:27:18 -0500 Subject: [PATCH 0226/1298] cmd/compile: use getcallersp for gorecover "fp" arg Currently, the compiler synthesize a special ".fp" node, which points to the FP of the current frame, be to used to call gorecover. Later that node turns to an Arg in SSA that is not really an arg, causing problems for the new ABI work which changes the handling of Args, so we have to special-case that node. This CL changes the compiler to get the FP by using getcallersp, which is an intrinsic in SSA and works on all platforms. As we need the FP, not the caller SP, one drawback is that we have to add FixedFrameSize for LR machines. But it does allow us to remove that special node. Change-Id: Ie721d51efca8116c9d23cc4f79738fffcf847df8 Reviewed-on: https://go-review.googlesource.com/c/go/+/297930 Trust: Cherry Zhang Reviewed-by: David Chase --- src/cmd/compile/internal/ir/name.go | 2 -- src/cmd/compile/internal/ssagen/pgen.go | 7 +------ src/cmd/compile/internal/ssagen/ssa.go | 4 ---- src/cmd/compile/internal/typecheck/builtin.go | 1 + src/cmd/compile/internal/typecheck/builtin/runtime.go | 1 + src/cmd/compile/internal/typecheck/universe.go | 5 ----- src/cmd/compile/internal/walk/expr.go | 9 ++++++++- 7 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go index 035c9cd3d0..16c30324e5 100644 --- a/src/cmd/compile/internal/ir/name.go +++ b/src/cmd/compile/internal/ir/name.go @@ -509,5 +509,3 @@ func NewPkgName(pos src.XPos, sym *types.Sym, pkg *types.Pkg) *PkgName { p.pos = pos return p } - -var RegFP *Name diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 7e15f54299..d12e12947e 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -93,12 +93,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { for _, v := range b.Values { if n, ok := v.Aux.(*ir.Name); ok { switch n.Class { - case ir.PPARAM, ir.PPARAMOUT: - // Don't modify RegFP; it is a global. - if n != ir.RegFP { - n.SetUsed(true) - } - case ir.PAUTO: + case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO: n.SetUsed(true) } } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 961cae419a..cc79c07af7 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -5176,10 +5176,6 @@ func (s *state) addr(n ir.Node) *ssa.Value { if v != nil { return v } - if n == ir.RegFP { - // Special arg that points to the frame pointer (Used by ORECOVER). - return s.entryNewValue2A(ssa.OpLocalAddr, t, n, s.sp, s.startmem) - } s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) return nil case ir.PAUTO: diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index ddec26df59..3421c44588 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -178,6 +178,7 @@ var runtimeDecls = [...]struct { {"uint32tofloat64", funcTag, 117}, {"complex128div", funcTag, 118}, {"getcallerpc", funcTag, 119}, + {"getcallersp", funcTag, 119}, {"racefuncenter", funcTag, 31}, {"racefuncexit", funcTag, 9}, {"raceread", funcTag, 31}, diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index 8575148b5b..614bd46177 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -226,6 +226,7 @@ func uint32tofloat64(uint32) float64 func complex128div(num complex128, den complex128) (quo complex128) func getcallerpc() uintptr +func getcallersp() uintptr // race detection func racefuncenter(uintptr) diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go index c4c034184b..f04dcb671c 100644 --- a/src/cmd/compile/internal/typecheck/universe.go +++ b/src/cmd/compile/internal/typecheck/universe.go @@ -354,9 +354,4 @@ func DeclareUniverse() { s1.Def = s.Def s1.Block = s.Block } - - ir.RegFP = NewName(Lookup(".fp")) - ir.RegFP.SetType(types.Types[types.TINT32]) - ir.RegFP.Class = ir.PPARAM - ir.RegFP.SetUsed(true) } diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index 7b65db5100..1d90029298 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -158,7 +158,14 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { case ir.ORECOVER: n := n.(*ir.CallExpr) - return mkcall("gorecover", n.Type(), init, typecheck.NodAddr(ir.RegFP)) + // Call gorecover with the FP of this frame. + // FP is equal to caller's SP plus FixedFrameSize(). + var fp ir.Node = mkcall("getcallersp", types.Types[types.TUINTPTR], init) + if off := base.Ctxt.FixedFrameSize(); off != 0 { + fp = ir.NewBinaryExpr(fp.Pos(), ir.OADD, fp, ir.NewInt(off)) + } + fp = ir.NewConvExpr(fp.Pos(), ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp) + return mkcall("gorecover", n.Type(), init, fp) case ir.OCFUNC: return n -- GitLab From 7205a4fbdc98f22fc2f0df7d12a242f9096bebbf Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 2 Mar 2021 13:21:53 -0500 Subject: [PATCH 0227/1298] cmd/internal/goobj: regenerate builtin list Change-Id: Ib8cb5f90e084838f00ecba78641bbb5d48ecac32 Reviewed-on: https://go-review.googlesource.com/c/go/+/297931 Trust: Cherry Zhang Reviewed-by: David Chase --- src/cmd/internal/goobj/builtinlist.go | 7 ++++--- src/cmd/internal/goobj/mkbuiltin.go | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cmd/internal/goobj/builtinlist.go b/src/cmd/internal/goobj/builtinlist.go index 0cca752332..9f248137da 100644 --- a/src/cmd/internal/goobj/builtinlist.go +++ b/src/cmd/internal/goobj/builtinlist.go @@ -41,6 +41,7 @@ var builtins = [...]struct { {"runtime.printcomplex", 1}, {"runtime.printstring", 1}, {"runtime.printpointer", 1}, + {"runtime.printuintptr", 1}, {"runtime.printiface", 1}, {"runtime.printeface", 1}, {"runtime.printslice", 1}, @@ -61,7 +62,6 @@ var builtins = [...]struct { {"runtime.stringtoslicebyte", 1}, {"runtime.stringtoslicerune", 1}, {"runtime.slicecopy", 1}, - {"runtime.slicestringcopy", 1}, {"runtime.decoderune", 1}, {"runtime.countrunes", 1}, {"runtime.convI2I", 1}, @@ -122,7 +122,6 @@ var builtins = [...]struct { {"runtime.typedslicecopy", 1}, {"runtime.selectnbsend", 1}, {"runtime.selectnbrecv", 1}, - {"runtime.selectnbrecv2", 1}, {"runtime.selectsetpc", 1}, {"runtime.selectgo", 1}, {"runtime.block", 1}, @@ -172,8 +171,9 @@ var builtins = [...]struct { {"runtime.uint64tofloat64", 1}, {"runtime.uint32tofloat64", 1}, {"runtime.complex128div", 1}, + {"runtime.getcallerpc", 1}, + {"runtime.getcallersp", 1}, {"runtime.racefuncenter", 1}, - {"runtime.racefuncenterfp", 1}, {"runtime.racefuncexit", 1}, {"runtime.raceread", 1}, {"runtime.racewrite", 1}, @@ -181,6 +181,7 @@ var builtins = [...]struct { {"runtime.racewriterange", 1}, {"runtime.msanread", 1}, {"runtime.msanwrite", 1}, + {"runtime.msanmove", 1}, {"runtime.checkptrAlignment", 1}, {"runtime.checkptrArithmetic", 1}, {"runtime.libfuzzerTraceCmp1", 1}, diff --git a/src/cmd/internal/goobj/mkbuiltin.go b/src/cmd/internal/goobj/mkbuiltin.go index 4e46970648..18b969586c 100644 --- a/src/cmd/internal/goobj/mkbuiltin.go +++ b/src/cmd/internal/goobj/mkbuiltin.go @@ -5,7 +5,7 @@ //go:build ignore // +build ignore -// Generate builtinlist.go from cmd/compile/internal/gc/builtin/runtime.go. +// Generate builtinlist.go from cmd/compile/internal/typecheck/builtin/runtime.go. package main @@ -54,7 +54,7 @@ func main() { func mkbuiltin(w io.Writer) { pkg := "runtime" fset := token.NewFileSet() - path := filepath.Join("..", "..", "compile", "internal", "gc", "builtin", "runtime.go") + path := filepath.Join("..", "..", "compile", "internal", "typecheck", "builtin", "runtime.go") f, err := parser.ParseFile(fset, path, nil, 0) if err != nil { log.Fatal(err) -- GitLab From 87d29939c8f93799ce889d98e0e5579d1eb2ffe5 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 2 Mar 2021 13:22:21 -0500 Subject: [PATCH 0228/1298] runtime: remove racefuncenterfp No longer needed with previous CL. Change-Id: I7c01f9e0e34ecb9553ef1b3d662f33419fd3a244 Reviewed-on: https://go-review.googlesource.com/c/go/+/297932 Trust: Cherry Zhang Reviewed-by: David Chase --- src/runtime/race_amd64.s | 10 +--------- src/runtime/race_arm64.s | 10 +--------- src/runtime/race_ppc64le.s | 12 +----------- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index e10c21c7f3..287bb9fc0a 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -167,21 +167,13 @@ call: ret: RET -// func runtime·racefuncenterfp(fp uintptr) -// Called from instrumented code. -// Like racefuncenter but passes FP, not PC -TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-8 - MOVQ fp+0(FP), R11 - MOVQ -8(R11), R11 - JMP racefuncenter<>(SB) - // func runtime·racefuncenter(pc uintptr) // Called from instrumented code. TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVQ callpc+0(FP), R11 JMP racefuncenter<>(SB) -// Common code for racefuncenter/racefuncenterfp +// Common code for racefuncenter // R11 = caller's return address TEXT racefuncenter<>(SB), NOSPLIT, $0-0 MOVQ DX, BX // save function entry context (for closures) diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index 8aa17742b8..82e3caadc8 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -160,21 +160,13 @@ call: ret: RET -// func runtime·racefuncenterfp(fp uintptr) -// Called from instrumented code. -// Like racefuncenter but doesn't passes an arg, uses the caller pc -// from the first slot on the stack -TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-0 - MOVD 0(RSP), R9 - JMP racefuncenter<>(SB) - // func runtime·racefuncenter(pc uintptr) // Called from instrumented code. TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVD callpc+0(FP), R9 JMP racefuncenter<>(SB) -// Common code for racefuncenter/racefuncenterfp +// Common code for racefuncenter // R9 = caller's return address TEXT racefuncenter<>(SB), NOSPLIT, $0-0 load_g diff --git a/src/runtime/race_ppc64le.s b/src/runtime/race_ppc64le.s index 8961254ea6..b09f37031c 100644 --- a/src/runtime/race_ppc64le.s +++ b/src/runtime/race_ppc64le.s @@ -163,23 +163,13 @@ call: ret: RET -// func runtime·racefuncenterfp() -// Called from instrumented Go code. -// Like racefuncenter but doesn't pass an arg, uses the caller pc -// from the first slot on the stack. -TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-0 - MOVD 0(R1), R8 - BR racefuncenter<>(SB) - // func runtime·racefuncenter(pc uintptr) // Called from instrumented Go code. -// Not used now since gc/racewalk.go doesn't pass the -// correct caller pc and racefuncenterfp can do it. TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVD callpc+0(FP), R8 BR racefuncenter<>(SB) -// Common code for racefuncenter/racefuncenterfp +// Common code for racefuncenter // R11 = caller's return address TEXT racefuncenter<>(SB), NOSPLIT, $0-0 MOVD runtime·tls_g(SB), R10 -- GitLab From f901ea701ddac5a4d600d49007e54caa32b4c9b5 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sun, 8 Nov 2020 11:27:53 -0500 Subject: [PATCH 0229/1298] cmd/internal/goobj: store relocation type as uint16 Currently, relocation type is stored as uint8 in object files, as Go relocations do not exceed 255. In the linker, however, it is used as a 16-bit type, because external relocations can exceed 255. The linker has to store the extra byte in a side table. This complicates many things. Just store it as uint16 in object files. This simplifies things, with a small cost of increasing the object file sizes. before after hello.o 1672 1678 runtime.a 7927784 8056194 Change-Id: I313cf44ad0b8b3b76e35055ae55d911ff35e3158 Reviewed-on: https://go-review.googlesource.com/c/go/+/268477 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/internal/goobj/objfile.go | 34 ++++++------ src/cmd/internal/goobj/objfile_test.go | 4 +- src/cmd/internal/obj/objfile.go | 2 +- src/cmd/link/internal/loader/loader.go | 53 ++++++------------- src/cmd/link/internal/loader/loader_test.go | 3 +- src/cmd/link/internal/loader/symbolbuilder.go | 8 +-- 6 files changed, 40 insertions(+), 64 deletions(-) diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go index 247cc695f0..e2858bd57d 100644 --- a/src/cmd/internal/goobj/objfile.go +++ b/src/cmd/internal/goobj/objfile.go @@ -33,7 +33,7 @@ import ( // New object file format. // // Header struct { -// Magic [...]byte // "\x00go116ld" +// Magic [...]byte // "\x00go117ld" // Fingerprint [8]byte // Flags uint32 // Offsets [...]uint32 // byte offset of each block below @@ -89,7 +89,7 @@ import ( // Relocs [...]struct { // Off int32 // Size uint8 -// Type uint8 +// Type uint16 // Add int64 // Sym symRef // } @@ -219,7 +219,7 @@ type Header struct { Offsets [NBlk]uint32 } -const Magic = "\x00go116ld" +const Magic = "\x00go117ld" func (h *Header) Write(w *Writer) { w.RawString(h.Magic) @@ -373,32 +373,32 @@ const HashSize = sha1.Size // Reloc struct { // Off int32 // Siz uint8 -// Type uint8 +// Type uint16 // Add int64 // Sym SymRef // } type Reloc [RelocSize]byte -const RelocSize = 4 + 1 + 1 + 8 + 8 +const RelocSize = 4 + 1 + 2 + 8 + 8 -func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } -func (r *Reloc) Siz() uint8 { return r[4] } -func (r *Reloc) Type() uint8 { return r[5] } -func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) } +func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } +func (r *Reloc) Siz() uint8 { return r[4] } +func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) } +func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[7:])) } func (r *Reloc) Sym() SymRef { - return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])} + return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])} } -func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } -func (r *Reloc) SetSiz(x uint8) { r[4] = x } -func (r *Reloc) SetType(x uint8) { r[5] = x } -func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) } +func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } +func (r *Reloc) SetSiz(x uint8) { r[4] = x } +func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) } +func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[7:], uint64(x)) } func (r *Reloc) SetSym(x SymRef) { - binary.LittleEndian.PutUint32(r[14:], x.PkgIdx) - binary.LittleEndian.PutUint32(r[18:], x.SymIdx) + binary.LittleEndian.PutUint32(r[15:], x.PkgIdx) + binary.LittleEndian.PutUint32(r[19:], x.SymIdx) } -func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) { +func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) { r.SetOff(off) r.SetSiz(size) r.SetType(typ) diff --git a/src/cmd/internal/goobj/objfile_test.go b/src/cmd/internal/goobj/objfile_test.go index 99d02a1bf1..ad80ede0f3 100644 --- a/src/cmd/internal/goobj/objfile_test.go +++ b/src/cmd/internal/goobj/objfile_test.go @@ -40,7 +40,7 @@ func TestReadWrite(t *testing.T) { var r Reloc r.SetOff(12) r.SetSiz(4) - r.SetType(uint8(objabi.R_ADDR)) + r.SetType(uint16(objabi.R_ADDR)) r.SetAdd(54321) r.SetSym(SymRef{11, 22}) r.Write(w) @@ -63,7 +63,7 @@ func TestReadWrite(t *testing.T) { b = b[SymSize:] var r2 Reloc r2.fromBytes(b) - if r2.Off() != 12 || r2.Siz() != 4 || r2.Type() != uint8(objabi.R_ADDR) || r2.Add() != 54321 || r2.Sym() != (SymRef{11, 22}) { + if r2.Off() != 12 || r2.Siz() != 4 || r2.Type() != uint16(objabi.R_ADDR) || r2.Add() != 54321 || r2.Sym() != (SymRef{11, 22}) { t.Errorf("read Reloc2 mismatch: got %v %v %v %v %v", r2.Off(), r2.Siz(), r2.Type(), r2.Add(), r2.Sym()) } diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index b031afbc36..24fb5a19de 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -498,7 +498,7 @@ func (w *writer) Reloc(r *Reloc) { var o goobj.Reloc o.SetOff(r.Off) o.SetSiz(r.Siz) - o.SetType(uint8(r.Type)) + o.SetType(uint16(r.Type)) o.SetAdd(r.Add) o.SetSym(makeSymRef(r.Sym)) o.Write(w.Writer) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index c05309a141..6d2e7dcabc 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -51,30 +51,13 @@ type Reloc struct { *goobj.Reloc r *oReader l *Loader - - // External reloc types may not fit into a uint8 which the Go object file uses. - // Store it here, instead of in the byte of goobj.Reloc. - // For Go symbols this will always be zero. - // goobj.Reloc.Type() + typ is always the right type, for both Go and external - // symbols. - typ objabi.RelocType } -func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ } -func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) } -func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) } -func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 } - -func (rel Reloc) SetType(t objabi.RelocType) { - if t != objabi.RelocType(uint8(t)) { - panic("SetType: type doesn't fit into Reloc") - } - rel.Reloc.SetType(uint8(t)) - if rel.typ != 0 { - // should use SymbolBuilder.SetRelocType - panic("wrong method to set reloc type") - } -} +func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) } +func (rel Reloc) SetType(t objabi.RelocType) { rel.Reloc.SetType(uint16(t)) } +func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) } +func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) } +func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 } // Aux holds a "handle" to access an aux symbol record from an // object file. @@ -307,15 +290,14 @@ type elfsetstringFunc func(str string, off int) // extSymPayload holds the payload (data + relocations) for linker-synthesized // external symbols (note that symbol value is stored in a separate slice). type extSymPayload struct { - name string // TODO: would this be better as offset into str table? - size int64 - ver int - kind sym.SymKind - objidx uint32 // index of original object if sym made by cloneToExternal - relocs []goobj.Reloc - reltypes []objabi.RelocType // relocation types - data []byte - auxs []goobj.Aux + name string // TODO: would this be better as offset into str table? + size int64 + ver int + kind sym.SymKind + objidx uint32 // index of original object if sym made by cloneToExternal + relocs []goobj.Reloc + data []byte + auxs []goobj.Aux } const ( @@ -1833,10 +1815,9 @@ func (relocs *Relocs) Count() int { return len(relocs.rs) } // At returns the j-th reloc for a global symbol. func (relocs *Relocs) At(j int) Reloc { if relocs.l.isExtReader(relocs.r) { - pp := relocs.l.payloads[relocs.li] - return Reloc{&relocs.rs[j], relocs.r, relocs.l, pp.reltypes[j]} + return Reloc{&relocs.rs[j], relocs.r, relocs.l} } - return Reloc{&relocs.rs[j], relocs.r, relocs.l, 0} + return Reloc{&relocs.rs[j], relocs.r, relocs.l} } // Relocs returns a Relocs object for the given global sym. @@ -2337,13 +2318,11 @@ func (l *Loader) cloneToExternal(symIdx Sym) { // Copy relocations relocs := l.Relocs(symIdx) pp.relocs = make([]goobj.Reloc, relocs.Count()) - pp.reltypes = make([]objabi.RelocType, relocs.Count()) for i := range pp.relocs { // Copy the relocs slice. // Convert local reference to global reference. rel := relocs.At(i) - pp.relocs[i].Set(rel.Off(), rel.Siz(), 0, rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())}) - pp.reltypes[i] = rel.Type() + pp.relocs[i].Set(rel.Off(), rel.Siz(), uint16(rel.Type()), rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())}) } // Copy data diff --git a/src/cmd/link/internal/loader/loader_test.go b/src/cmd/link/internal/loader/loader_test.go index 1371c2a541..15ae830dc9 100644 --- a/src/cmd/link/internal/loader/loader_test.go +++ b/src/cmd/link/internal/loader/loader_test.go @@ -237,7 +237,8 @@ func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool { type addFunc func(l *Loader, s Sym, s2 Sym) Sym func mkReloc(l *Loader, typ objabi.RelocType, off int32, siz uint8, add int64, sym Sym) Reloc { - r := Reloc{&goobj.Reloc{}, l.extReader, l, typ} + r := Reloc{&goobj.Reloc{}, l.extReader, l} + r.SetType(typ) r.SetOff(off) r.SetSiz(siz) r.SetAdd(add) diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go index 5d37da8ac6..204d04412d 100644 --- a/src/cmd/link/internal/loader/symbolbuilder.go +++ b/src/cmd/link/internal/loader/symbolbuilder.go @@ -121,13 +121,11 @@ func (sb *SymbolBuilder) Relocs() Relocs { // ResetRelocs removes all relocations on this symbol. func (sb *SymbolBuilder) ResetRelocs() { sb.relocs = sb.relocs[:0] - sb.reltypes = sb.reltypes[:0] } // SetRelocType sets the type of the 'i'-th relocation on this sym to 't' func (sb *SymbolBuilder) SetRelocType(i int, t objabi.RelocType) { - sb.relocs[i].SetType(0) - sb.reltypes[i] = t + sb.relocs[i].SetType(uint16(t)) } // SetRelocSym sets the target sym of the 'i'-th relocation on this sym to 's' @@ -143,7 +141,6 @@ func (sb *SymbolBuilder) SetRelocAdd(i int, a int64) { // Add n relocations, return a handle to the relocations. func (sb *SymbolBuilder) AddRelocs(n int) Relocs { sb.relocs = append(sb.relocs, make([]goobj.Reloc, n)...) - sb.reltypes = append(sb.reltypes, make([]objabi.RelocType, n)...) return sb.l.Relocs(sb.symIdx) } @@ -152,7 +149,7 @@ func (sb *SymbolBuilder) AddRelocs(n int) Relocs { func (sb *SymbolBuilder) AddRel(typ objabi.RelocType) (Reloc, int) { j := len(sb.relocs) sb.relocs = append(sb.relocs, goobj.Reloc{}) - sb.reltypes = append(sb.reltypes, typ) + sb.relocs[j].SetType(uint16(typ)) relocs := sb.Relocs() return relocs.At(j), j } @@ -169,7 +166,6 @@ func (p *relocsByOff) Len() int { return len(p.relocs) } func (p *relocsByOff) Less(i, j int) bool { return p.relocs[i].Off() < p.relocs[j].Off() } func (p *relocsByOff) Swap(i, j int) { p.relocs[i], p.relocs[j] = p.relocs[j], p.relocs[i] - p.reltypes[i], p.reltypes[j] = p.reltypes[j], p.reltypes[i] } func (sb *SymbolBuilder) Reachable() bool { -- GitLab From 009bfeae866f45549865e554420a05c10e9578ca Mon Sep 17 00:00:00 2001 From: Roger Peppe Date: Fri, 1 Jan 2021 12:14:34 +0000 Subject: [PATCH 0230/1298] reflect: add VisibleFields function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When writing code that reflects over a struct type, it's a common requirement to know the full set of struct fields, including fields available due to embedding of anonymous members while excluding fields that are erased because they're at the same level as another field with the same name. The logic to do this is not that complex, but it's a little subtle and easy to get wrong. This CL adds a new `VisibleFields` function to the reflect package that returns the full set of effective fields that apply in a given struct type. Performance isn't a prime consideration, as it's common to cache results by type. Fixes #42782 Change-Id: I7f1af76cecff9b8a2490f17eec058826e396f660 Reviewed-on: https://go-review.googlesource.com/c/go/+/281233 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Trust: Daniel Martí --- src/reflect/visiblefields.go | 101 +++++++++ src/reflect/visiblefields_test.go | 326 ++++++++++++++++++++++++++++++ 2 files changed, 427 insertions(+) create mode 100644 src/reflect/visiblefields.go create mode 100644 src/reflect/visiblefields_test.go diff --git a/src/reflect/visiblefields.go b/src/reflect/visiblefields.go new file mode 100644 index 0000000000..c068979dcc --- /dev/null +++ b/src/reflect/visiblefields.go @@ -0,0 +1,101 @@ +package reflect + +// VisibleFields returns all the visible fields in t, which must be a +// struct type. A field is defined as visible if it's accessible +// directly with a FieldByName call. The returned fields include fields +// inside anonymous struct members and unexported fields. They follow +// the same order found in the struct, with anonymous fields followed +// immediately by their promoted fields. +// +// For each element e of the returned slice, the corresponding field +// can be retrieved from a value v of type t by calling v.FieldByIndex(e.Index). +func VisibleFields(t Type) []StructField { + if t == nil { + panic("reflect: VisibleFields(nil)") + } + if t.Kind() != Struct { + panic("reflect.VisibleFields of non-struct type") + } + w := &visibleFieldsWalker{ + byName: make(map[string]int), + visiting: make(map[Type]bool), + fields: make([]StructField, 0, t.NumField()), + index: make([]int, 0, 2), + } + w.walk(t) + // Remove all the fields that have been hidden. + // Use an in-place removal that avoids copying in + // the common case that there are no hidden fields. + j := 0 + for i := range w.fields { + f := &w.fields[i] + if f.Name == "" { + continue + } + if i != j { + // A field has been removed. We need to shuffle + // all the subsequent elements up. + w.fields[j] = *f + } + j++ + } + return w.fields[:j] +} + +type visibleFieldsWalker struct { + byName map[string]int + visiting map[Type]bool + fields []StructField + index []int +} + +// walk walks all the fields in the struct type t, visiting +// fields in index preorder and appending them to w.fields +// (this maintains the required ordering). +// Fields that have been overridden have their +// Name field cleared. +func (w *visibleFieldsWalker) walk(t Type) { + if w.visiting[t] { + return + } + w.visiting[t] = true + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + w.index = append(w.index, i) + add := true + if oldIndex, ok := w.byName[f.Name]; ok { + old := &w.fields[oldIndex] + if len(w.index) == len(old.Index) { + // Fields with the same name at the same depth + // cancel one another out. Set the field name + // to empty to signify that has happened, and + // there's no need to add this field. + old.Name = "" + add = false + } else if len(w.index) < len(old.Index) { + // The old field loses because it's deeper than the new one. + old.Name = "" + } else { + // The old field wins because it's shallower than the new one. + add = false + } + } + if add { + // Copy the index so that it's not overwritten + // by the other appends. + f.Index = append([]int(nil), w.index...) + w.byName[f.Name] = len(w.fields) + w.fields = append(w.fields, f) + } + if f.Anonymous { + if f.Type.Kind() == Ptr { + f.Type = f.Type.Elem() + } + if f.Type.Kind() == Struct { + w.walk(f.Type) + } + } + w.index = w.index[:len(w.index)-1] + } + delete(w.visiting, t) +} diff --git a/src/reflect/visiblefields_test.go b/src/reflect/visiblefields_test.go new file mode 100644 index 0000000000..2688b63091 --- /dev/null +++ b/src/reflect/visiblefields_test.go @@ -0,0 +1,326 @@ +package reflect_test + +import ( + . "reflect" + "testing" +) + +type structField struct { + name string + index []int +} + +var fieldsTests = []struct { + testName string + val interface{} + expect []structField +}{{ + testName: "SimpleStruct", + val: struct { + A int + B string + C bool + }{}, + expect: []structField{{ + name: "A", + index: []int{0}, + }, { + name: "B", + index: []int{1}, + }, { + name: "C", + index: []int{2}, + }}, +}, { + testName: "NonEmbeddedStructMember", + val: struct { + A struct { + X int + } + }{}, + expect: []structField{{ + name: "A", + index: []int{0}, + }}, +}, { + testName: "EmbeddedExportedStruct", + val: struct { + SFG + }{}, + expect: []structField{{ + name: "SFG", + index: []int{0}, + }, { + name: "F", + index: []int{0, 0}, + }, { + name: "G", + index: []int{0, 1}, + }}, +}, { + testName: "EmbeddedUnexportedStruct", + val: struct { + sFG + }{}, + expect: []structField{{ + name: "sFG", + index: []int{0}, + }, { + name: "F", + index: []int{0, 0}, + }, { + name: "G", + index: []int{0, 1}, + }}, +}, { + testName: "TwoEmbeddedStructsWithCancellingMembers", + val: struct { + SFG + SF + }{}, + expect: []structField{{ + name: "SFG", + index: []int{0}, + }, { + name: "G", + index: []int{0, 1}, + }, { + name: "SF", + index: []int{1}, + }}, +}, { + testName: "EmbeddedStructsWithSameFieldsAtDifferentDepths", + val: struct { + SFGH3 + SG1 + SFG2 + SF2 + L int + }{}, + expect: []structField{{ + name: "SFGH3", + index: []int{0}, + }, { + name: "SFGH2", + index: []int{0, 0}, + }, { + name: "SFGH1", + index: []int{0, 0, 0}, + }, { + name: "SFGH", + index: []int{0, 0, 0, 0}, + }, { + name: "H", + index: []int{0, 0, 0, 0, 2}, + }, { + name: "SG1", + index: []int{1}, + }, { + name: "SG", + index: []int{1, 0}, + }, { + name: "G", + index: []int{1, 0, 0}, + }, { + name: "SFG2", + index: []int{2}, + }, { + name: "SFG1", + index: []int{2, 0}, + }, { + name: "SFG", + index: []int{2, 0, 0}, + }, { + name: "SF2", + index: []int{3}, + }, { + name: "SF1", + index: []int{3, 0}, + }, { + name: "SF", + index: []int{3, 0, 0}, + }, { + name: "L", + index: []int{4}, + }}, +}, { + testName: "EmbeddedPointerStruct", + val: struct { + *SF + }{}, + expect: []structField{{ + name: "SF", + index: []int{0}, + }, { + name: "F", + index: []int{0, 0}, + }}, +}, { + testName: "EmbeddedNotAPointer", + val: struct { + M + }{}, + expect: []structField{{ + name: "M", + index: []int{0}, + }}, +}, { + testName: "RecursiveEmbedding", + val: Rec1{}, + expect: []structField{{ + name: "Rec2", + index: []int{0}, + }, { + name: "F", + index: []int{0, 0}, + }, { + name: "Rec1", + index: []int{0, 1}, + }}, +}, { + testName: "RecursiveEmbedding2", + val: Rec2{}, + expect: []structField{{ + name: "F", + index: []int{0}, + }, { + name: "Rec1", + index: []int{1}, + }, { + name: "Rec2", + index: []int{1, 0}, + }}, +}, { + testName: "RecursiveEmbedding3", + val: RS3{}, + expect: []structField{{ + name: "RS2", + index: []int{0}, + }, { + name: "RS1", + index: []int{1}, + }, { + name: "i", + index: []int{1, 0}, + }}, +}} + +type SFG struct { + F int + G int +} + +type SFG1 struct { + SFG +} + +type SFG2 struct { + SFG1 +} + +type SFGH struct { + F int + G int + H int +} + +type SFGH1 struct { + SFGH +} + +type SFGH2 struct { + SFGH1 +} + +type SFGH3 struct { + SFGH2 +} + +type SF struct { + F int +} + +type SF1 struct { + SF +} + +type SF2 struct { + SF1 +} + +type SG struct { + G int +} + +type SG1 struct { + SG +} + +type sFG struct { + F int + G int +} + +type RS1 struct { + i int +} + +type RS2 struct { + RS1 +} + +type RS3 struct { + RS2 + RS1 +} + +type M map[string]interface{} + +type Rec1 struct { + *Rec2 +} + +type Rec2 struct { + F string + *Rec1 +} + +func TestFields(t *testing.T) { + for _, test := range fieldsTests { + test := test + t.Run(test.testName, func(t *testing.T) { + typ := TypeOf(test.val) + fields := VisibleFields(typ) + if got, want := len(fields), len(test.expect); got != want { + t.Fatalf("unexpected field count; got %d want %d", got, want) + } + + for j, field := range fields { + expect := test.expect[j] + t.Logf("field %d: %s", j, expect.name) + gotField := typ.FieldByIndex(field.Index) + // Unfortunately, FieldByIndex does not return + // a field with the same index that we passed in, + // so we set it to the expected value so that + // it can be compared later with the result of FieldByName. + gotField.Index = field.Index + expectField := typ.FieldByIndex(expect.index) + // ditto. + expectField.Index = expect.index + if !DeepEqual(gotField, expectField) { + t.Fatalf("unexpected field result\ngot %#v\nwant %#v", gotField, expectField) + } + + // Sanity check that we can actually access the field by the + // expected name. + gotField1, ok := typ.FieldByName(expect.name) + if !ok { + t.Fatalf("field %q not accessible by name", expect.name) + } + if !DeepEqual(gotField1, expectField) { + t.Fatalf("unexpected FieldByName result; got %#v want %#v", gotField1, expectField) + } + } + }) + } +} -- GitLab From 414fa8c35e7c2f65e2c767d6db2f25791e53b5c1 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sun, 8 Nov 2020 11:50:10 -0500 Subject: [PATCH 0231/1298] cmd/internal/objabi: use a separate bit to mark weak relocation Instead of using two relocation types R_XXX and R_WEAKXXX, use a separate bit, R_WEAK, to mark weak relocations. This makes it easier to add more weak relocation types. Change-Id: Iec4195c2aefa65f59e464c83018246e17cd08173 Reviewed-on: https://go-review.googlesource.com/c/go/+/268478 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Jeremy Faller Reviewed-by: Than McIntosh --- src/cmd/internal/objabi/reloctype.go | 13 ++- src/cmd/internal/objabi/reloctype_string.go | 113 ++++++++++---------- src/cmd/link/internal/ld/data.go | 29 ++--- src/cmd/link/internal/ld/deadcode.go | 5 +- src/cmd/link/internal/loader/loader.go | 3 +- 5 files changed, 85 insertions(+), 78 deletions(-) diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go index 649f690194..217d8565f2 100644 --- a/src/cmd/internal/objabi/reloctype.go +++ b/src/cmd/internal/objabi/reloctype.go @@ -50,11 +50,6 @@ const ( // R_ADDROFF resolves to a 32-bit offset from the beginning of the section // holding the data being relocated to the referenced symbol. R_ADDROFF - // R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation. - // A weak relocation does not make the symbol it refers to reachable, - // and is only honored by the linker if the symbol is in some other way - // reachable. - R_WEAKADDROFF R_SIZE R_CALL R_CALLARM @@ -256,6 +251,14 @@ const ( // of a symbol. This isn't a real relocation, it can be placed in anywhere // in a symbol and target any symbols. R_XCOFFREF + + // R_WEAK marks the relocation as a weak reference. + // A weak relocation does not make the symbol it refers to reachable, + // and is only honored by the linker if the symbol is in some other way + // reachable. + R_WEAK = -1 << 15 + + R_WEAKADDROFF = R_WEAK | R_ADDROFF ) // IsDirectCall reports whether r is a relocation for a direct call. diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index 658a44f8b8..8882d19f88 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -13,66 +13,65 @@ func _() { _ = x[R_ADDRARM64-3] _ = x[R_ADDRMIPS-4] _ = x[R_ADDROFF-5] - _ = x[R_WEAKADDROFF-6] - _ = x[R_SIZE-7] - _ = x[R_CALL-8] - _ = x[R_CALLARM-9] - _ = x[R_CALLARM64-10] - _ = x[R_CALLIND-11] - _ = x[R_CALLPOWER-12] - _ = x[R_CALLMIPS-13] - _ = x[R_CALLRISCV-14] - _ = x[R_CONST-15] - _ = x[R_PCREL-16] - _ = x[R_TLS_LE-17] - _ = x[R_TLS_IE-18] - _ = x[R_GOTOFF-19] - _ = x[R_PLT0-20] - _ = x[R_PLT1-21] - _ = x[R_PLT2-22] - _ = x[R_USEFIELD-23] - _ = x[R_USETYPE-24] - _ = x[R_USEIFACE-25] - _ = x[R_USEIFACEMETHOD-26] - _ = x[R_METHODOFF-27] - _ = x[R_POWER_TOC-28] - _ = x[R_GOTPCREL-29] - _ = x[R_JMPMIPS-30] - _ = x[R_DWARFSECREF-31] - _ = x[R_DWARFFILEREF-32] - _ = x[R_ARM64_TLS_LE-33] - _ = x[R_ARM64_TLS_IE-34] - _ = x[R_ARM64_GOTPCREL-35] - _ = x[R_ARM64_GOT-36] - _ = x[R_ARM64_PCREL-37] - _ = x[R_ARM64_LDST8-38] - _ = x[R_ARM64_LDST16-39] - _ = x[R_ARM64_LDST32-40] - _ = x[R_ARM64_LDST64-41] - _ = x[R_ARM64_LDST128-42] - _ = x[R_POWER_TLS_LE-43] - _ = x[R_POWER_TLS_IE-44] - _ = x[R_POWER_TLS-45] - _ = x[R_ADDRPOWER_DS-46] - _ = x[R_ADDRPOWER_GOT-47] - _ = x[R_ADDRPOWER_PCREL-48] - _ = x[R_ADDRPOWER_TOCREL-49] - _ = x[R_ADDRPOWER_TOCREL_DS-50] - _ = x[R_RISCV_PCREL_ITYPE-51] - _ = x[R_RISCV_PCREL_STYPE-52] - _ = x[R_RISCV_TLS_IE_ITYPE-53] - _ = x[R_RISCV_TLS_IE_STYPE-54] - _ = x[R_PCRELDBL-55] - _ = x[R_ADDRMIPSU-56] - _ = x[R_ADDRMIPSTLS-57] - _ = x[R_ADDRCUOFF-58] - _ = x[R_WASMIMPORT-59] - _ = x[R_XCOFFREF-60] + _ = x[R_SIZE-6] + _ = x[R_CALL-7] + _ = x[R_CALLARM-8] + _ = x[R_CALLARM64-9] + _ = x[R_CALLIND-10] + _ = x[R_CALLPOWER-11] + _ = x[R_CALLMIPS-12] + _ = x[R_CALLRISCV-13] + _ = x[R_CONST-14] + _ = x[R_PCREL-15] + _ = x[R_TLS_LE-16] + _ = x[R_TLS_IE-17] + _ = x[R_GOTOFF-18] + _ = x[R_PLT0-19] + _ = x[R_PLT1-20] + _ = x[R_PLT2-21] + _ = x[R_USEFIELD-22] + _ = x[R_USETYPE-23] + _ = x[R_USEIFACE-24] + _ = x[R_USEIFACEMETHOD-25] + _ = x[R_METHODOFF-26] + _ = x[R_POWER_TOC-27] + _ = x[R_GOTPCREL-28] + _ = x[R_JMPMIPS-29] + _ = x[R_DWARFSECREF-30] + _ = x[R_DWARFFILEREF-31] + _ = x[R_ARM64_TLS_LE-32] + _ = x[R_ARM64_TLS_IE-33] + _ = x[R_ARM64_GOTPCREL-34] + _ = x[R_ARM64_GOT-35] + _ = x[R_ARM64_PCREL-36] + _ = x[R_ARM64_LDST8-37] + _ = x[R_ARM64_LDST16-38] + _ = x[R_ARM64_LDST32-39] + _ = x[R_ARM64_LDST64-40] + _ = x[R_ARM64_LDST128-41] + _ = x[R_POWER_TLS_LE-42] + _ = x[R_POWER_TLS_IE-43] + _ = x[R_POWER_TLS-44] + _ = x[R_ADDRPOWER_DS-45] + _ = x[R_ADDRPOWER_GOT-46] + _ = x[R_ADDRPOWER_PCREL-47] + _ = x[R_ADDRPOWER_TOCREL-48] + _ = x[R_ADDRPOWER_TOCREL_DS-49] + _ = x[R_RISCV_PCREL_ITYPE-50] + _ = x[R_RISCV_PCREL_STYPE-51] + _ = x[R_RISCV_TLS_IE_ITYPE-52] + _ = x[R_RISCV_TLS_IE_STYPE-53] + _ = x[R_PCRELDBL-54] + _ = x[R_ADDRMIPSU-55] + _ = x[R_ADDRMIPSTLS-56] + _ = x[R_ADDRCUOFF-57] + _ = x[R_WASMIMPORT-58] + _ = x[R_XCOFFREF-59] } -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 425, 440, 454, 468, 479, 493, 508, 525, 543, 564, 583, 602, 622, 642, 652, 663, 676, 687, 699, 709} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 243, 253, 262, 275, 289, 303, 317, 333, 344, 357, 370, 384, 398, 412, 427, 441, 455, 466, 480, 495, 512, 530, 551, 570, 589, 609, 629, 639, 650, 663, 674, 686, 696} func (i RelocType) String() string { i -= 1 diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 92d38bb63e..a9d17c806e 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -165,6 +165,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { rs := r.Sym() rs = ldr.ResolveABIAlias(rs) rt := r.Type() + weak := r.Weak() if off < 0 || off+siz > int32(len(P)) { rname := "" if rs != 0 { @@ -211,7 +212,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { st.err.Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", ldr.SymName(rs), rst, rst, rt, sym.RelocName(target.Arch, rt)) } } - if rs != 0 && rst != sym.STLSBSS && rt != objabi.R_WEAKADDROFF && rt != objabi.R_METHODOFF && !ldr.AttrReachable(rs) { + if rs != 0 && rst != sym.STLSBSS && !weak && rt != objabi.R_METHODOFF && !ldr.AttrReachable(rs) { st.err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs)) } @@ -387,18 +388,18 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { break } o = ldr.SymValue(rs) + r.Add() - int64(ldr.SymSect(rs).Vaddr) - case objabi.R_WEAKADDROFF, objabi.R_METHODOFF: + case objabi.R_METHODOFF: if !ldr.AttrReachable(rs) { - if rt == objabi.R_METHODOFF { - // Set it to a sentinel value. The runtime knows this is not pointing to - // anything valid. - o = -1 - break - } - continue + // Set it to a sentinel value. The runtime knows this is not pointing to + // anything valid. + o = -1 + break } fallthrough case objabi.R_ADDROFF: + if weak && !ldr.AttrReachable(rs) { + continue + } // The method offset tables using this relocation expect the offset to be relative // to the start of the first text section, even if there are multiple. if ldr.SymSect(rs).Name == ".text" { @@ -635,7 +636,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa return ExtrelocSimple(ldr, r), true // These reloc types don't need external relocations. - case objabi.R_ADDROFF, objabi.R_WEAKADDROFF, objabi.R_METHODOFF, objabi.R_ADDRCUOFF, + case objabi.R_ADDROFF, objabi.R_METHODOFF, objabi.R_ADDRCUOFF, objabi.R_SIZE, objabi.R_CONST, objabi.R_GOTOFF: return rr, false } @@ -710,9 +711,8 @@ func windynrelocsym(ctxt *Link, rel *loader.SymbolBuilder, s loader.Sym) { if targ == 0 { continue } - rt := r.Type() if !ctxt.loader.AttrReachable(targ) { - if rt == objabi.R_WEAKADDROFF { + if r.Weak() { continue } ctxt.Errorf(s, "dynamic relocation to unreachable symbol %s", @@ -786,6 +786,10 @@ func dynrelocsym(ctxt *Link, s loader.Sym) { if r.IsMarker() { continue // skip marker relocations } + rSym := r.Sym() + if r.Weak() && !ldr.AttrReachable(rSym) { + continue + } if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal { // It's expected that some relocations will be done // later by relocsym (R_TLS_LE, R_ADDROFF), so @@ -794,7 +798,6 @@ func dynrelocsym(ctxt *Link, s loader.Sym) { continue } - rSym := r.Sym() if rSym != 0 && ldr.SymType(rSym) == sym.SDYNIMPORT || r.Type() >= objabi.ElfRelocOffset { if rSym != 0 && !ldr.AttrReachable(rSym) { ctxt.Errorf(s, "dynamic relocation to unreachable symbol %s", ldr.SymName(rSym)) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index ebde41499e..ed276b5a99 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -128,10 +128,11 @@ func (d *deadcodePass) flood() { methods = methods[:0] for i := 0; i < relocs.Count(); i++ { r := relocs.At(i) + if r.Weak() { + continue + } t := r.Type() switch t { - case objabi.R_WEAKADDROFF: - continue case objabi.R_METHODOFF: if i+2 >= relocs.Count() { panic("expect three consecutive R_METHODOFF relocs") diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 6d2e7dcabc..5df4348a36 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -53,7 +53,8 @@ type Reloc struct { l *Loader } -func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) } +func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) &^ objabi.R_WEAK } +func (rel Reloc) Weak() bool { return objabi.RelocType(rel.Reloc.Type())&objabi.R_WEAK != 0 } func (rel Reloc) SetType(t objabi.RelocType) { rel.Reloc.SetType(uint16(t)) } func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) } func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) } -- GitLab From b0df92703c89e42592659ae99cded0d5b68382b7 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 4 Jan 2021 13:34:29 -0800 Subject: [PATCH 0232/1298] math/big: add shrVU and shlVU benchmarks Change-Id: Id67d6ac856bd9271de99c3381bde910aa0c166e0 Reviewed-on: https://go-review.googlesource.com/c/go/+/296011 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/math/big/arith_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go index 2aca0effde..7b3427f834 100644 --- a/src/math/big/arith_test.go +++ b/src/math/big/arith_test.go @@ -671,3 +671,27 @@ func BenchmarkDivWVW(b *testing.B) { }) } } + +func BenchmarkNonZeroShifts(b *testing.B) { + for _, n := range benchSizes { + if isRaceBuilder && n > 1e3 { + continue + } + x := rndV(n) + s := uint(rand.Int63n(_W-2)) + 1 // avoid 0 and over-large shifts + z := make([]Word, n) + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.SetBytes(int64(n * _W)) + b.Run("shrVU", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = shrVU(z, x, s) + } + }) + b.Run("shlVU", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = shlVU(z, x, s) + } + }) + }) + } +} -- GitLab From 597b5d192e39d7bba38dd461b96effe6e524984b Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 6 Mar 2021 23:25:25 -0800 Subject: [PATCH 0233/1298] cmd/compile: rename internal-abi.md to abi-internal.md Allows muscle-memoried tab completion of cmd/compile/internal/... paths to work again. Change-Id: Ib54a5f2cc9fabcb876c2e62635828ab28b565501 Reviewed-on: https://go-review.googlesource.com/c/go/+/299530 Reviewed-by: Austin Clements Trust: Matthew Dempsky --- src/cmd/compile/{internal-abi.md => abi-internal.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cmd/compile/{internal-abi.md => abi-internal.md} (100%) diff --git a/src/cmd/compile/internal-abi.md b/src/cmd/compile/abi-internal.md similarity index 100% rename from src/cmd/compile/internal-abi.md rename to src/cmd/compile/abi-internal.md -- GitLab From 125eca0f7210da1bbf1a4a1460a87d1c33366b99 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 6 Mar 2021 04:46:07 +1100 Subject: [PATCH 0234/1298] cmd/compile: improve IsNonNil rule on riscv64 IsNonNil is readily implemented using SNEZ on riscv64, removing over 8,000 instructions from the go binary. Other rules will improve on this sequence, however in this case it makes sense to use a direct simplification. Change-Id: Ib4068599532398afcd05f51d160673ef5fb5e5a0 Reviewed-on: https://go-review.googlesource.com/c/go/+/299230 Trust: Joel Sing Reviewed-by: Michael Munday Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot --- src/cmd/compile/internal/ssa/gen/RISCV64.rules | 2 +- src/cmd/compile/internal/ssa/rewriteRISCV64.go | 18 ++---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules index d7efef039e..dbe04f1d58 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules @@ -423,7 +423,7 @@ (Convert ...) => (MOVconvert ...) // Checks -(IsNonNil p) => (NeqPtr (MOVDconst [0]) p) +(IsNonNil ...) => (SNEZ ...) (IsInBounds ...) => (Less64U ...) (IsSliceInBounds ...) => (Leq64U ...) diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index 7f77477da7..895f380d33 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -239,7 +239,8 @@ func rewriteValueRISCV64(v *Value) bool { v.Op = OpLess64U return true case OpIsNonNil: - return rewriteValueRISCV64_OpIsNonNil(v) + v.Op = OpRISCV64SNEZ + return true case OpIsSliceInBounds: v.Op = OpLeq64U return true @@ -1101,21 +1102,6 @@ func rewriteValueRISCV64_OpHmul32u(v *Value) bool { return true } } -func rewriteValueRISCV64_OpIsNonNil(v *Value) bool { - v_0 := v.Args[0] - b := v.Block - typ := &b.Func.Config.Types - // match: (IsNonNil p) - // result: (NeqPtr (MOVDconst [0]) p) - for { - p := v_0 - v.reset(OpNeqPtr) - v0 := b.NewValue0(v.Pos, OpRISCV64MOVDconst, typ.UInt64) - v0.AuxInt = int64ToAuxInt(0) - v.AddArg2(v0, p) - return true - } -} func rewriteValueRISCV64_OpLeq16(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] -- GitLab From aafad20b617ee63d58fcd4f6e0d98fe27760678c Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Sat, 6 Mar 2021 23:14:21 -0800 Subject: [PATCH 0235/1298] encoding/binary: limit bytes read by Uvarint to <= 10 Limits the number of bytes that can be consumed by Uvarint to MaxVarintLen64 (10) to avoid wasted computations. With this change, if Uvarint reads more than MaxVarintLen64 bytes, it'll return the erroring byte count of n=-(MaxVarintLen64+1) which is -11, as per the function signature. Updated some tests to reflect the new change in expectations of n when the number of bytes to be read exceeds the limits.. Fixes #41185 Change-Id: Ie346457b1ddb0214b60c72e81128e24d604d083d Reviewed-on: https://go-review.googlesource.com/c/go/+/299531 Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Emmanuel Odeke --- src/encoding/binary/varint.go | 7 +++- src/encoding/binary/varint_test.go | 63 ++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/encoding/binary/varint.go b/src/encoding/binary/varint.go index 1fa325dec7..8fe20b5c45 100644 --- a/src/encoding/binary/varint.go +++ b/src/encoding/binary/varint.go @@ -61,8 +61,13 @@ func Uvarint(buf []byte) (uint64, int) { var x uint64 var s uint for i, b := range buf { + if i == MaxVarintLen64 { + // Catch byte reads past MaxVarintLen64. + // See issue https://golang.org/issues/41185 + return 0, -(i + 1) // overflow + } if b < 0x80 { - if i >= MaxVarintLen64 || i == MaxVarintLen64-1 && b > 1 { + if i == MaxVarintLen64-1 && b > 1 { return 0, -(i + 1) // overflow } return x | uint64(b)< Date: Sun, 7 Mar 2021 14:48:08 -0800 Subject: [PATCH 0236/1298] cmd/compile: minor doc improvements These are left over from comments I failed to leave on CL 249463; apparently I never hit "Reply". Change-Id: Ia3f8a900703c347f8f98581ec1ac172c0f72cd9e Reviewed-on: https://go-review.googlesource.com/c/go/+/299589 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/decompose.go | 2 +- src/cmd/compile/internal/ssa/rewrite.go | 2 +- src/cmd/compile/internal/ssa/value.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index ea988e44f6..ba48b6b3b9 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -24,7 +24,7 @@ func decomposeBuiltIn(f *Func) { } // Decompose other values - // Note: deadcode is false because we need to keep the original + // Note: Leave dead values because we need to keep the original // values around so the name component resolution below can still work. applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues) if f.Config.RegSize == 4 { diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 07bbdb8813..5c56b2b346 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -27,7 +27,7 @@ const ( removeDeadValues = true ) -// deadcode indicates that rewrite should try to remove any values that become dead. +// deadcode indicates whether rewrite should try to remove any values that become dead. func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) { // repeat rewrites until we find no more rewrites pendingLines := f.cachedLineStarts // Holds statement boundaries that need to be moved to a new value/block diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index c20fc87e90..6cc2b2ab8b 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -499,7 +499,7 @@ func (v *Value) removeable() bool { return false } if v.Type.IsMemory() { - // All memory ops aren't needed here, but we do need + // We don't need to preserve all memory ops, but we do need // to keep calls at least (because they might have // synchronization operations we can't see). return false -- GitLab From 7419a86c824efc6e2696f29e4dc1ac81756f1dfb Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 7 Mar 2021 20:32:38 -0800 Subject: [PATCH 0237/1298] cmd/link/internal/ld: fix typo in a comment Change-Id: I6d0fafd38f0ad9392f163a9d8cd94d103bf2a059 Reviewed-on: https://go-review.googlesource.com/c/go/+/299669 Reviewed-by: Keith Randall Reviewed-by: Cherry Zhang --- src/cmd/link/internal/ld/deadcode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index ed276b5a99..ea98fea4e5 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -19,7 +19,7 @@ var _ = fmt.Print type deadcodePass struct { ctxt *Link ldr *loader.Loader - wq heap // work queue, using min-heap for beter locality + wq heap // work queue, using min-heap for better locality ifaceMethod map[methodsig]bool // methods declared in reached interfaces markableMethods []methodref // methods of reached types -- GitLab From fee3cd4250843a0a7c056fed3d3e6e1a423f3120 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 9 Mar 2021 01:52:10 +0700 Subject: [PATCH 0238/1298] cmd/compile: fix width not calculated for imported type The compiler currently has problem that some imported type is missing size calculation. The problem is not triggered until CL 283313 merged, due to the compiler can compile the functions immediately when it sees them, so during SSA generation, size calculation is still ok. CL 283313 makes the compiler always push functions to compile queue, then drain from it for compiling function. During this process, the types calculation size is disabled, so calculating size during SSA now make the compiler crashes. To fix this, we can just always calculate type size during typechecking, when importing type from other packages. Fixes #44732 Change-Id: I8d00ea0b5aadd432154908280e55d85c75f3ce92 Reviewed-on: https://go-review.googlesource.com/c/go/+/299689 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/typecheck/iimport.go | 6 ++++++ test/fixedbugs/issue44732.dir/bar/bar.go | 11 +++++++++++ test/fixedbugs/issue44732.dir/foo/foo.go | 13 +++++++++++++ test/fixedbugs/issue44732.dir/main.go | 15 +++++++++++++++ test/fixedbugs/issue44732.go | 7 +++++++ 5 files changed, 52 insertions(+) create mode 100644 test/fixedbugs/issue44732.dir/bar/bar.go create mode 100644 test/fixedbugs/issue44732.dir/foo/foo.go create mode 100644 test/fixedbugs/issue44732.dir/main.go create mode 100644 test/fixedbugs/issue44732.go diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 9355174da8..8df75b2285 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -508,6 +508,12 @@ func (p *iimporter) typAt(off uint64) *types.Type { base.Fatalf("predeclared type missing from cache: %d", off) } t = p.newReader(off-predeclReserved, nil).typ1() + // Ensure size is calculated for imported types. Since CL 283313, the compiler + // does not compile the function immediately when it sees them. Instead, funtions + // are pushed to compile queue, then draining from the queue for compiling. + // During this process, the size calculation is disabled, so it is not safe for + // calculating size during SSA generation anymore. See issue #44732. + types.CheckSize(t) p.typCache[off] = t } return t diff --git a/test/fixedbugs/issue44732.dir/bar/bar.go b/test/fixedbugs/issue44732.dir/bar/bar.go new file mode 100644 index 0000000000..fc14161610 --- /dev/null +++ b/test/fixedbugs/issue44732.dir/bar/bar.go @@ -0,0 +1,11 @@ +// Copyright 2021 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 bar + +import "issue44732.dir/foo" + +type Bar struct { + Foo *foo.Foo +} diff --git a/test/fixedbugs/issue44732.dir/foo/foo.go b/test/fixedbugs/issue44732.dir/foo/foo.go new file mode 100644 index 0000000000..c8afb0e880 --- /dev/null +++ b/test/fixedbugs/issue44732.dir/foo/foo.go @@ -0,0 +1,13 @@ +// Copyright 2021 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 foo + +type Foo struct { + updatecb func() +} + +func NewFoo() *Foo { + return &Foo{updatecb: nil} +} diff --git a/test/fixedbugs/issue44732.dir/main.go b/test/fixedbugs/issue44732.dir/main.go new file mode 100644 index 0000000000..21208ecdd9 --- /dev/null +++ b/test/fixedbugs/issue44732.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2021 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 ( + "issue44732.dir/bar" + "issue44732.dir/foo" +) + +func main() { + _ = bar.Bar{} + _ = foo.NewFoo() +} diff --git a/test/fixedbugs/issue44732.go b/test/fixedbugs/issue44732.go new file mode 100644 index 0000000000..4210671205 --- /dev/null +++ b/test/fixedbugs/issue44732.go @@ -0,0 +1,7 @@ +// runindir + +// Copyright 2021 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 ignored -- GitLab From bd372847849c9187fd6112bd3cc0203c15c3ac72 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 7 Mar 2021 20:52:39 -0800 Subject: [PATCH 0239/1298] cmd/link: use testing.T.TempDir in tests Change-Id: I6fc8c9ee6d2246bfd874eb58b411e34ddbeaf723 Reviewed-on: https://go-review.googlesource.com/c/go/+/299670 Reviewed-by: Cherry Zhang Reviewed-by: Keith Randall --- src/cmd/link/dwarf_test.go | 7 +- src/cmd/link/elf_test.go | 18 +-- src/cmd/link/internal/ld/deadcode_test.go | 8 +- src/cmd/link/internal/ld/dwarf_test.go | 104 ++++---------- src/cmd/link/internal/ld/elf_test.go | 13 +- src/cmd/link/internal/ld/fallocate_test.go | 9 +- src/cmd/link/internal/ld/go_test.go | 7 +- src/cmd/link/internal/ld/issue33808_test.go | 8 +- src/cmd/link/internal/ld/ld_test.go | 26 +--- src/cmd/link/internal/ld/nooptcgolink_test.go | 8 +- src/cmd/link/internal/ld/outbuf_test.go | 8 +- src/cmd/link/link_test.go | 129 ++++-------------- src/cmd/link/linkbig_test.go | 9 +- 13 files changed, 75 insertions(+), 279 deletions(-) diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go index d0284ad4f5..0419613cbe 100644 --- a/src/cmd/link/dwarf_test.go +++ b/src/cmd/link/dwarf_test.go @@ -10,7 +10,6 @@ import ( "cmd/internal/objfile" "debug/dwarf" "internal/testenv" - "io/ioutil" "os" "os/exec" "path" @@ -59,11 +58,7 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) t.Run(prog, func(t *testing.T) { t.Parallel() - tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) + tmpDir := t.TempDir() exe := filepath.Join(tmpDir, prog+".exe") dir := "../../runtime/testdata/" + prog diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index b4441297e6..012c0b5169 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -70,11 +70,7 @@ func TestSectionsWithSameName(t *testing.T) { t.Skipf("can't find objcopy: %v", err) } - dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() gopath := filepath.Join(dir, "GOPATH") env := append(os.Environ(), "GOPATH="+gopath) @@ -144,11 +140,7 @@ func TestMinusRSymsWithSameName(t *testing.T) { testenv.MustHaveCGO(t) t.Parallel() - dir, err := ioutil.TempDir("", "go-link-TestMinusRSymsWithSameName") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() gopath := filepath.Join(dir, "GOPATH") env := append(os.Environ(), "GOPATH="+gopath) @@ -271,11 +263,7 @@ func TestPIESize(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - dir, err := ioutil.TempDir("", "go-link-"+name) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() writeGo(t, dir) diff --git a/src/cmd/link/internal/ld/deadcode_test.go b/src/cmd/link/internal/ld/deadcode_test.go index b756091613..bd74205a1a 100644 --- a/src/cmd/link/internal/ld/deadcode_test.go +++ b/src/cmd/link/internal/ld/deadcode_test.go @@ -7,8 +7,6 @@ package ld import ( "bytes" "internal/testenv" - "io/ioutil" - "os" "os/exec" "path/filepath" "testing" @@ -18,11 +16,7 @@ func TestDeadcode(t *testing.T) { testenv.MustHaveGoBuild(t) t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestDeadcode") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() tests := []struct { src string diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index a66506d392..d16cff911b 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -39,11 +39,7 @@ func TestRuntimeTypesPresent(t *testing.T) { t.Skip("skipping on plan9; no DWARF symbol table in executables") } - dir, err := ioutil.TempDir("", "TestRuntimeTypesPresent") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, `package main; func main() { }`, NoOpt) defer f.Close() @@ -171,11 +167,7 @@ func main() { "main.Baz": {"Foo": true, "name": false}, } - dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, prog, NoOpt) @@ -255,11 +247,8 @@ func main() { y[0] = nil } ` - dir, err := ioutil.TempDir("", "TestSizes") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() + f := gobuild(t, dir, prog, NoOpt) defer f.Close() d, err := f.DWARF() @@ -303,11 +292,7 @@ func main() { c <- "foo" } ` - dir, err := ioutil.TempDir("", "TestFieldOverlap") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, prog, NoOpt) defer f.Close() @@ -351,13 +336,10 @@ func varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFil prog := fmt.Sprintf("package main\n%s\nfunc main() {\n\nvar i int\ni = i\n}\n", directive) - dir, err := ioutil.TempDir("", testpoint) - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, prog, NoOpt) + defer f.Close() d, err := f.DWARF() if err != nil { @@ -653,11 +635,7 @@ func main() { G = x } ` - dir, err := ioutil.TempDir("", "TestInlinedRoutineRecords") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() // Note: this is a build with "-l=4", as opposed to "-l -N". The // test is intended to verify DWARF that is only generated when @@ -665,6 +643,7 @@ func main() { // main.main, however, hence we build with "-gcflags=-l=4" as opposed // to "-gcflags=all=-l=4". f := gobuild(t, dir, prog, OptInl4) + defer f.Close() d, err := f.DWARF() if err != nil { @@ -788,14 +767,11 @@ func main() { func abstractOriginSanity(t *testing.T, pkgDir string, flags string) { t.Parallel() - dir, err := ioutil.TempDir("", "TestAbstractOriginSanity") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() // Build with inlining, to exercise DWARF inlining support. f := gobuildTestdata(t, dir, filepath.Join(pkgDir, "main"), flags) + defer f.Close() d, err := f.DWARF() if err != nil { @@ -973,13 +949,11 @@ func main() { print(p) } ` - dir, err := ioutil.TempDir("", "TestRuntimeType") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, prog, flags) + defer f.Close() + out, err := exec.Command(f.path).CombinedOutput() if err != nil { t.Fatalf("could not run test program: %v", err) @@ -1043,11 +1017,7 @@ func TestIssue27614(t *testing.T) { t.Parallel() - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() const prog = `package main @@ -1161,11 +1131,7 @@ func TestStaticTmp(t *testing.T) { t.Parallel() - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() const prog = `package main @@ -1243,11 +1209,7 @@ func TestPackageNameAttr(t *testing.T) { t.Parallel() - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() const prog = "package main\nfunc main() {\nprintln(\"hello world\")\n}\n" @@ -1307,14 +1269,10 @@ func TestMachoIssue32233(t *testing.T) { t.Skip("skipping; test only interesting on darwin") } - tmpdir, err := ioutil.TempDir("", "TestMachoIssue32233") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() - wd, err2 := os.Getwd() - if err2 != nil { + wd, err := os.Getwd() + if err != nil { t.Fatalf("where am I? %v", err) } pdir := filepath.Join(wd, "testdata", "issue32233", "main") @@ -1328,11 +1286,7 @@ func TestWindowsIssue36495(t *testing.T) { t.Skip("skipping: test only on windows") } - dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() prog := ` package main @@ -1347,6 +1301,7 @@ func main() { if err != nil { t.Fatalf("error opening pe file: %v", err) } + defer exe.Close() dw, err := exe.DWARF() if err != nil { t.Fatalf("error parsing DWARF: %v", err) @@ -1397,17 +1352,14 @@ func TestIssue38192(t *testing.T) { // Build a test program that contains a translation unit whose // text (from am assembly source) contains only a single instruction. - tmpdir, err := ioutil.TempDir("", "TestIssue38192") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() wd, err := os.Getwd() if err != nil { t.Fatalf("where am I? %v", err) } pdir := filepath.Join(wd, "testdata", "issue38192") f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt) + defer f.Close() // Open the resulting binary and examine the DWARF it contains. // Look for the function of interest ("main.singleInstruction") @@ -1520,17 +1472,15 @@ func TestIssue39757(t *testing.T) { // compiler/runtime in ways that aren't happening now, so this // might be something to check for if it does start failing. - tmpdir, err := ioutil.TempDir("", "TestIssue38192") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() + wd, err := os.Getwd() if err != nil { t.Fatalf("where am I? %v", err) } pdir := filepath.Join(wd, "testdata", "issue39757") f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt) + defer f.Close() syms, err := f.Symbols() if err != nil { diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index 70e743fa65..d86ebb89e0 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -22,11 +22,7 @@ import ( func TestDynSymShInfo(t *testing.T) { t.Parallel() testenv.MustHaveGoBuild(t) - dir, err := ioutil.TempDir("", "go-build-issue33358") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() const prog = ` package main @@ -52,6 +48,7 @@ func main() { if err != nil { t.Fatalf("failed to open built file: %v", err) } + defer fi.Close() elfFile, err := elf.NewFile(fi) if err != nil { @@ -96,11 +93,7 @@ func TestNoDuplicateNeededEntries(t *testing.T) { t.Parallel() - dir, err := ioutil.TempDir("", "no-dup-needed") - if err != nil { - t.Fatalf("Failed to create temp dir: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() wd, err := os.Getwd() if err != nil { diff --git a/src/cmd/link/internal/ld/fallocate_test.go b/src/cmd/link/internal/ld/fallocate_test.go index 56d2321826..1ed0eb2ca7 100644 --- a/src/cmd/link/internal/ld/fallocate_test.go +++ b/src/cmd/link/internal/ld/fallocate_test.go @@ -8,7 +8,6 @@ package ld import ( - "io/ioutil" "os" "path/filepath" "syscall" @@ -16,14 +15,10 @@ import ( ) func TestFallocate(t *testing.T) { - dir, err := ioutil.TempDir("", "TestFallocate") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() filename := filepath.Join(dir, "a.out") out := NewOutBuf(nil) - err = out.Open(filename) + err := out.Open(filename) if err != nil { t.Fatalf("Open file failed: %v", err) } diff --git a/src/cmd/link/internal/ld/go_test.go b/src/cmd/link/internal/ld/go_test.go index 0197196023..230f85a0e5 100644 --- a/src/cmd/link/internal/ld/go_test.go +++ b/src/cmd/link/internal/ld/go_test.go @@ -8,7 +8,6 @@ import ( "cmd/internal/objabi" "internal/testenv" "io/ioutil" - "os" "os/exec" "path/filepath" "reflect" @@ -86,11 +85,7 @@ func TestDedupLibrariesOpenBSDLink(t *testing.T) { testenv.MustHaveCGO(t) t.Parallel() - dir, err := ioutil.TempDir("", "dedup-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() // cgo_import_dynamic both the unversioned libraries and pull in the // net package to get a cgo package with a versioned library. diff --git a/src/cmd/link/internal/ld/issue33808_test.go b/src/cmd/link/internal/ld/issue33808_test.go index 92a47faa4a..43f4540a02 100644 --- a/src/cmd/link/internal/ld/issue33808_test.go +++ b/src/cmd/link/internal/ld/issue33808_test.go @@ -6,8 +6,6 @@ package ld import ( "internal/testenv" - "io/ioutil" - "os" "runtime" "strings" "testing" @@ -31,11 +29,7 @@ func TestIssue33808(t *testing.T) { testenv.MustHaveCGO(t) t.Parallel() - dir, err := ioutil.TempDir("", "TestIssue33808") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() f := gobuild(t, dir, prog, "-ldflags=-linkmode=external") f.Close() diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go index cdfaadb17d..836d9bff3d 100644 --- a/src/cmd/link/internal/ld/ld_test.go +++ b/src/cmd/link/internal/ld/ld_test.go @@ -9,7 +9,6 @@ import ( "fmt" "internal/testenv" "io/ioutil" - "os" "os/exec" "path/filepath" "runtime" @@ -25,11 +24,6 @@ func TestUndefinedRelocErrors(t *testing.T) { testenv.MustInternalLink(t) t.Parallel() - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) out, err := exec.Command(testenv.GoToolPath(t), "build", "./testdata/issue10978").CombinedOutput() if err == nil { @@ -108,11 +102,7 @@ func TestArchiveBuildInvokeWithExec(t *testing.T) { case "openbsd", "windows": t.Skip("c-archive unsupported") } - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() srcfile := filepath.Join(dir, "test.go") arfile := filepath.Join(dir, "test.a") @@ -150,11 +140,7 @@ func TestPPC64LargeTextSectionSplitting(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) t.Parallel() - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() // NB: the use of -ldflags=-debugppc64textsize=1048576 tells the linker to // split text sections at a size threshold of 1M instead of the @@ -168,7 +154,7 @@ func TestPPC64LargeTextSectionSplitting(t *testing.T) { } // Result should be runnable. - _, err = exec.Command(exe, "version").CombinedOutput() + _, err := exec.Command(exe, "version").CombinedOutput() if err != nil { t.Fatal(err) } @@ -194,11 +180,7 @@ func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) { t.Parallel() testenv.MustHaveGoBuild(t) - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() srcfile := filepath.Join(dir, "test.go") objfile := filepath.Join(dir, "test.dll") diff --git a/src/cmd/link/internal/ld/nooptcgolink_test.go b/src/cmd/link/internal/ld/nooptcgolink_test.go index 4d2ff1acf2..73548dabd4 100644 --- a/src/cmd/link/internal/ld/nooptcgolink_test.go +++ b/src/cmd/link/internal/ld/nooptcgolink_test.go @@ -6,8 +6,6 @@ package ld import ( "internal/testenv" - "io/ioutil" - "os" "os/exec" "path/filepath" "runtime" @@ -22,11 +20,7 @@ func TestNooptCgoBuild(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", filepath.Join(dir, "a.out")) cmd.Dir = filepath.Join(runtime.GOROOT(), "src", "runtime", "testdata", "testprogcgo") out, err := cmd.CombinedOutput() diff --git a/src/cmd/link/internal/ld/outbuf_test.go b/src/cmd/link/internal/ld/outbuf_test.go index e6643da396..a7b105f887 100644 --- a/src/cmd/link/internal/ld/outbuf_test.go +++ b/src/cmd/link/internal/ld/outbuf_test.go @@ -5,8 +5,6 @@ package ld import ( - "io/ioutil" - "os" "path/filepath" "runtime" "testing" @@ -19,11 +17,7 @@ func TestMMap(t *testing.T) { t.Skip("unsupported OS") case "aix", "darwin", "ios", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "windows": } - dir, err := ioutil.TempDir("", "TestMMap") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() filename := filepath.Join(dir, "foo.out") ob := NewOutBuf(nil) if err := ob.Open(filename); err != nil { diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 9c69ccca43..9369e550f4 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -48,13 +48,9 @@ const X = "\n!\n" func main() {} ` - tmpdir, err := ioutil.TempDir("", "issue21703") - if err != nil { - t.Fatalf("failed to create temp dir: %v\n", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() - err = ioutil.WriteFile(filepath.Join(tmpdir, "main.go"), []byte(source), 0666) + err := ioutil.WriteFile(filepath.Join(tmpdir, "main.go"), []byte(source), 0666) if err != nil { t.Fatalf("failed to write main.go: %v\n", err) } @@ -83,11 +79,7 @@ func TestIssue28429(t *testing.T) { testenv.MustHaveGoBuild(t) - tmpdir, err := ioutil.TempDir("", "issue28429-") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() write := func(name, content string) { err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666) @@ -126,11 +118,7 @@ func TestUnresolved(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "unresolved-") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() write := func(name, content string) { err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666) @@ -195,11 +183,7 @@ func TestIssue33979(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "unresolved-") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() write := func(name, content string) { err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666) @@ -300,11 +284,7 @@ func TestBuildForTvOS(t *testing.T) { "-framework", "CoreFoundation", } lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go") - tmpDir, err := ioutil.TempDir("", "go-link-TestBuildFortvOS") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) + tmpDir := t.TempDir() ar := filepath.Join(tmpDir, "lib.a") cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib) @@ -339,14 +319,10 @@ func TestXFlag(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestXFlag") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "main.go") - err = ioutil.WriteFile(src, []byte(testXFlagSrc), 0666) + err := ioutil.WriteFile(src, []byte(testXFlagSrc), 0666) if err != nil { t.Fatal(err) } @@ -367,14 +343,10 @@ func TestMacOSVersion(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestMacOSVersion") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "main.go") - err = ioutil.WriteFile(src, []byte(testMacOSVersionSrc), 0666) + err := ioutil.WriteFile(src, []byte(testMacOSVersionSrc), 0666) if err != nil { t.Fatal(err) } @@ -393,6 +365,7 @@ func TestMacOSVersion(t *testing.T) { if err != nil { t.Fatal(err) } + defer exef.Close() exem, err := macho.NewFile(exef) if err != nil { t.Fatal(err) @@ -446,14 +419,10 @@ func TestIssue34788Android386TLSSequence(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestIssue34788Android386TLSSequence") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "blah.go") - err = ioutil.WriteFile(src, []byte(Issue34788src), 0666) + err := ioutil.WriteFile(src, []byte(Issue34788src), 0666) if err != nil { t.Fatal(err) } @@ -506,14 +475,10 @@ func TestStrictDup(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestStrictDup") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "x.go") - err = ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666) + err := ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666) if err != nil { t.Fatal(err) } @@ -592,14 +557,10 @@ func TestFuncAlign(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestFuncAlign") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "go.mod") - err = ioutil.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666) + err := ioutil.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666) if err != nil { t.Fatal(err) } @@ -665,14 +626,10 @@ func TestTrampoline(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestTrampoline") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "hello.go") - err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666) + err := ioutil.WriteFile(src, []byte(testTrampSrc), 0666) if err != nil { t.Fatal(err) } @@ -701,11 +658,7 @@ func TestIndexMismatch(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestIndexMismatch") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go") bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go") @@ -764,11 +717,7 @@ func TestPErsrcBinutils(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestPErsrcBinutils") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() pkgdir := filepath.Join("testdata", "pe-binutils") exe := filepath.Join(tmpdir, "a.exe") @@ -800,11 +749,7 @@ func TestPErsrcLLVM(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestPErsrcLLVM") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() pkgdir := filepath.Join("testdata", "pe-llvm") exe := filepath.Join(tmpdir, "a.exe") @@ -832,12 +777,6 @@ func TestContentAddressableSymbols(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestContentAddressableSymbols") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) - src := filepath.Join("testdata", "testHashedSyms", "p.go") cmd := exec.Command(testenv.GoToolPath(t), "run", src) out, err := cmd.CombinedOutput() @@ -881,14 +820,10 @@ func TestIssue38554(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestIssue38554") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "x.go") - err = ioutil.WriteFile(src, []byte(testIssue38554Src), 0666) + err := ioutil.WriteFile(src, []byte(testIssue38554Src), 0666) if err != nil { t.Fatalf("failed to write source file: %v", err) } @@ -935,14 +870,10 @@ func TestIssue42396(t *testing.T) { t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestIssue42396") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "main.go") - err = ioutil.WriteFile(src, []byte(testIssue42396src), 0666) + err := ioutil.WriteFile(src, []byte(testIssue42396src), 0666) if err != nil { t.Fatalf("failed to write source file: %v", err) } @@ -992,14 +923,10 @@ func TestLargeReloc(t *testing.T) { testenv.MustHaveGoBuild(t) t.Parallel() - tmpdir, err := ioutil.TempDir("", "TestIssue42396") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() src := filepath.Join(tmpdir, "x.go") - err = ioutil.WriteFile(src, []byte(testLargeRelocSrc), 0666) + err := ioutil.WriteFile(src, []byte(testLargeRelocSrc), 0666) if err != nil { t.Fatalf("failed to write source file: %v", err) } diff --git a/src/cmd/link/linkbig_test.go b/src/cmd/link/linkbig_test.go index 78d2bc1afe..d5d77d6c72 100644 --- a/src/cmd/link/linkbig_test.go +++ b/src/cmd/link/linkbig_test.go @@ -27,12 +27,7 @@ func TestLargeText(t *testing.T) { var w bytes.Buffer const FN = 4 - tmpdir, err := ioutil.TempDir("", "bigtext") - if err != nil { - t.Fatalf("can't create temp directory: %v\n", err) - } - - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() // Generate the scenario where the total amount of text exceeds the // limit for the jmp/call instruction, on RISC architectures like ppc64le, @@ -79,7 +74,7 @@ func TestLargeText(t *testing.T) { fmt.Fprintf(&w, "\t}\n") fmt.Fprintf(&w, "\tfmt.Printf(\"PASS\\n\")\n") fmt.Fprintf(&w, "}") - err = ioutil.WriteFile(tmpdir+"/bigfn.go", w.Bytes(), 0666) + err := ioutil.WriteFile(tmpdir+"/bigfn.go", w.Bytes(), 0666) if err != nil { t.Fatalf("can't write output: %v\n", err) } -- GitLab From a08adda12c2af7f597dad9d280282c7e70d4a2dc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 3 Mar 2021 08:04:40 -0800 Subject: [PATCH 0240/1298] os/signal: remove comments about SA_RESTART It's no longer necessary for non-Go signal handlers to use SA_RESTART. For #20400 Fixes #44761 Change-Id: Ie3c7fecc631a4a2822331754296ea09b308e1391 Reviewed-on: https://go-review.googlesource.com/c/go/+/298269 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/os/signal/doc.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go index 2229d36954..a210795849 100644 --- a/src/os/signal/doc.go +++ b/src/os/signal/doc.go @@ -129,9 +129,7 @@ If the non-Go code installs any signal handlers, it must use the SA_ONSTACK flag with sigaction. Failing to do so is likely to cause the program to crash if the signal is received. Go programs routinely run with a limited stack, and therefore set up an alternate signal -stack. Also, the Go standard library expects that any signal handlers -will use the SA_RESTART flag. Failing to do so may cause some library -calls to return "interrupted system call" errors. +stack. If the non-Go code installs a signal handler for any of the synchronous signals (SIGBUS, SIGFPE, SIGSEGV), then it should record -- GitLab From b6def6a34e049d5d2cc9225d991c4b84427467ec Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Sat, 6 Mar 2021 23:57:33 -0800 Subject: [PATCH 0241/1298] cmd/vet: bring in sigchanyzer to report unbuffered channels to signal.Notify Brings in the static analyzer "sigchanyzer", that we created at Orijtech, Inc, and already submitted in CL 274352, as golang.org/x/tools/go/analysis/passes/sigchanyzer and add it to cmd/vet as one of the passes. Fixes #9399 Change-Id: I83708b8ea5ca8ede5ee31efab55cbce7419434ab Reviewed-on: https://go-review.googlesource.com/c/go/+/299532 Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Reviewed-by: Bryan C. Mills Reviewed-by: Ian Lance Taylor Trust: Cuong Manh Le Trust: Bryan C. Mills --- .../passes/sigchanyzer/sigchanyzer.go | 129 ++++++++++++++++++ src/cmd/vendor/modules.txt | 1 + src/cmd/vet/main.go | 2 + 3 files changed, 132 insertions(+) create mode 100644 src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go new file mode 100644 index 0000000000..3d89061d17 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go @@ -0,0 +1,129 @@ +// Copyright 2020 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 sigchanyzer defines an Analyzer that detects +// misuse of unbuffered signal as argument to signal.Notify. +package sigchanyzer + +import ( + "bytes" + "go/ast" + "go/format" + "go/token" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const Doc = `check for unbuffered channel of os.Signal + +This checker reports call expression of the form signal.Notify(c <-chan os.Signal, sig ...os.Signal), +where c is an unbuffered channel, which can be at risk of missing the signal.` + +// Analyzer describes sigchanyzer analysis function detector. +var Analyzer = &analysis.Analyzer{ + Name: "sigchanyzer", + Doc: Doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + call := n.(*ast.CallExpr) + if !isSignalNotify(pass.TypesInfo, call) { + return + } + var chanDecl *ast.CallExpr + switch arg := call.Args[0].(type) { + case *ast.Ident: + if decl, ok := findDecl(arg).(*ast.CallExpr); ok { + chanDecl = decl + } + case *ast.CallExpr: + chanDecl = arg + } + if chanDecl == nil || len(chanDecl.Args) != 1 { + return + } + chanDecl.Args = append(chanDecl.Args, &ast.BasicLit{ + Kind: token.INT, + Value: "1", + }) + var buf bytes.Buffer + if err := format.Node(&buf, token.NewFileSet(), chanDecl); err != nil { + return + } + pass.Report(analysis.Diagnostic{ + Pos: call.Pos(), + End: call.End(), + Message: "misuse of unbuffered os.Signal channel as argument to signal.Notify", + SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Change to buffer channel", + TextEdits: []analysis.TextEdit{{ + Pos: chanDecl.Pos(), + End: chanDecl.End(), + NewText: buf.Bytes(), + }}, + }}, + }) + }) + return nil, nil +} + +func isSignalNotify(info *types.Info, call *ast.CallExpr) bool { + check := func(id *ast.Ident) bool { + obj := info.ObjectOf(id) + return obj.Name() == "Notify" && obj.Pkg().Path() == "os/signal" + } + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + return check(fun.Sel) + case *ast.Ident: + if fun, ok := findDecl(fun).(*ast.SelectorExpr); ok { + return check(fun.Sel) + } + return false + default: + return false + } +} + +func findDecl(arg *ast.Ident) ast.Node { + if arg.Obj == nil { + return nil + } + switch as := arg.Obj.Decl.(type) { + case *ast.AssignStmt: + if len(as.Lhs) != len(as.Rhs) { + return nil + } + for i, lhs := range as.Lhs { + lid, ok := lhs.(*ast.Ident) + if !ok { + continue + } + if lid.Obj == arg.Obj { + return as.Rhs[i] + } + } + case *ast.ValueSpec: + if len(as.Names) != len(as.Values) { + return nil + } + for i, name := range as.Names { + if name.Obj == arg.Obj { + return as.Values[i] + } + } + } + return nil +} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index e4dfd32315..b1a2c67581 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -69,6 +69,7 @@ golang.org/x/tools/go/analysis/passes/lostcancel golang.org/x/tools/go/analysis/passes/nilfunc golang.org/x/tools/go/analysis/passes/printf golang.org/x/tools/go/analysis/passes/shift +golang.org/x/tools/go/analysis/passes/sigchanyzer golang.org/x/tools/go/analysis/passes/stdmethods golang.org/x/tools/go/analysis/passes/stringintconv golang.org/x/tools/go/analysis/passes/structtag diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index d50c45d691..a33bba2466 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -22,6 +22,7 @@ import ( "golang.org/x/tools/go/analysis/passes/nilfunc" "golang.org/x/tools/go/analysis/passes/printf" "golang.org/x/tools/go/analysis/passes/shift" + "golang.org/x/tools/go/analysis/passes/sigchanyzer" "golang.org/x/tools/go/analysis/passes/stdmethods" "golang.org/x/tools/go/analysis/passes/stringintconv" "golang.org/x/tools/go/analysis/passes/structtag" @@ -54,6 +55,7 @@ func main() { nilfunc.Analyzer, printf.Analyzer, shift.Analyzer, + sigchanyzer.Analyzer, stdmethods.Analyzer, stringintconv.Analyzer, structtag.Analyzer, -- GitLab From 618b66e16d5adedbeccb7e7ed35b26e439a9f86f Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 2 Mar 2021 06:02:55 +0000 Subject: [PATCH 0242/1298] cmd/compile: remove 4-byte alignment requirement of stack slot on arm This CL applies CL 267999 to arm. Updates #42385 Change-Id: Iad82aafcb7b0a5a77a4bea32f648320f57a17cdd Reviewed-on: https://go-review.googlesource.com/c/go/+/297773 Reviewed-by: eric fang Reviewed-by: Cherry Zhang Trust: eric fang Run-TryBot: eric fang --- src/cmd/compile/internal/ssagen/pgen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index d12e12947e..c2225ce950 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -133,7 +133,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.ARM, sys.PPC64) { + if Arch.LinkArch.InFamily(sys.PPC64) { s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) } n.SetFrameOffset(-s.stksize) -- GitLab From 437d229e2ac4cda4265090375b94d74ca218a846 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 2 Mar 2021 09:10:49 +0100 Subject: [PATCH 0243/1298] runtime: document netpollclose Document that network poller implementations need to define netpollclose. Change-Id: Idc73dea7cfd503d4de7e1d95902f0f102cf5ed8f Reviewed-on: https://go-review.googlesource.com/c/go/+/297809 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/runtime/netpoll.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 202aef593f..6c26fdbbeb 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -23,6 +23,9 @@ import ( // Arm edge-triggered notifications for fd. The pd argument is to pass // back to netpollready when fd is ready. Return an errno value. // +// func netpollclose(fd uintptr) int32 +// Disable notifications for fd. Return an errno value. +// // func netpoll(delta int64) gList // Poll the network. If delta < 0, block indefinitely. If delta == 0, // poll without blocking. If delta > 0, block for up to delta nanoseconds. -- GitLab From b70a2bc9c612de35b765712bd689865f6a1716b6 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Fri, 5 Mar 2021 11:22:13 +0100 Subject: [PATCH 0244/1298] cmd/compile: make ValAndOff.{Val,Off} return an int32 The ValAndOff type is a 64bit integer holding a 32bit value and a 32bit offset in each half, but for historical reasons its Val and Off methods returned an int64. This was convenient when AuxInt was always an int64, but now that AuxInts are typed we can return int32 from Val and Off and get rid of a several casts and now unnecessary range checks. This change: - changes the Val and Off methods to return an int32 (from int64); - adds Val64 and Off64 methods for convenience in the few remaining places (in the ssa.go files) where Val and Off are stored in int64 fields; - deletes makeValAndOff64, renames makeValAndOff32 to makeValAndOff - deletes a few ValAndOff methods that are now unused; - removes several validOff/validValAndOff check that will always return true. Passes: GOARCH=amd64 gotip build -toolexec 'toolstash -cmp' -a std GOARCH=386 gotip build -toolexec 'toolstash -cmp' -a std GOARCH=s390x gotip build -toolexec 'toolstash -cmp' -a std (the three GOARCHs with SSA rules files impacted by the change). Change-Id: I2abbbf42188c798631b94d3a55ca44256f140be7 Reviewed-on: https://go-review.googlesource.com/c/go/+/299149 Trust: Alberto Donizetti Trust: Keith Randall Run-TryBot: Alberto Donizetti TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/amd64/ssa.go | 22 +- src/cmd/compile/internal/s390x/ssa.go | 14 +- src/cmd/compile/internal/ssa/gen/386.rules | 75 ++-- .../internal/ssa/gen/386splitload.rules | 6 +- src/cmd/compile/internal/ssa/gen/AMD64.rules | 95 +++-- .../internal/ssa/gen/AMD64splitload.rules | 32 +- src/cmd/compile/internal/ssa/gen/S390X.rules | 40 +-- src/cmd/compile/internal/ssa/op.go | 42 +-- src/cmd/compile/internal/ssa/rewrite386.go | 184 +++++----- .../internal/ssa/rewrite386splitload.go | 14 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 330 +++++++++--------- .../internal/ssa/rewriteAMD64splitload.go | 100 +++--- src/cmd/compile/internal/ssa/rewriteS390X.go | 96 ++--- src/cmd/compile/internal/x86/ssa.go | 20 +- 14 files changed, 504 insertions(+), 566 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 60baa4270f..af398c814a 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -682,9 +682,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.From, v, sc.Off()) + ssagen.AddAux2(&p.From, v, sc.Off64()) p.To.Type = obj.TYPE_CONST - p.To.Offset = sc.Val() + p.To.Offset = sc.Val64() case ssa.OpAMD64CMPQloadidx8, ssa.OpAMD64CMPQloadidx1, ssa.OpAMD64CMPLloadidx4, ssa.OpAMD64CMPLloadidx1, ssa.OpAMD64CMPWloadidx2, ssa.OpAMD64CMPWloadidx1, ssa.OpAMD64CMPBloadidx1: p := s.Prog(v.Op.Asm()) memIdx(&p.From, v) @@ -695,9 +695,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { sc := v.AuxValAndOff() p := s.Prog(v.Op.Asm()) memIdx(&p.From, v) - ssagen.AddAux2(&p.From, v, sc.Off()) + ssagen.AddAux2(&p.From, v, sc.Off64()) p.To.Type = obj.TYPE_CONST - p.To.Offset = sc.Val() + p.To.Offset = sc.Val64() case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst: x := v.Reg() @@ -769,7 +769,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.To, v) case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify: sc := v.AuxValAndOff() - off := sc.Off() + off := sc.Off64() val := sc.Val() if val == 1 || val == -1 { var asm obj.As @@ -797,8 +797,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64BTCQconstmodify, ssa.OpAMD64BTCLconstmodify, ssa.OpAMD64BTSQconstmodify, ssa.OpAMD64BTSLconstmodify, ssa.OpAMD64BTRQconstmodify, ssa.OpAMD64BTRLconstmodify, ssa.OpAMD64XORQconstmodify, ssa.OpAMD64XORLconstmodify: sc := v.AuxValAndOff() - off := sc.Off() - val := sc.Val() + off := sc.Off64() + val := sc.Val64() p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = val @@ -810,10 +810,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.OpAMD64MOVOstorezero: if s.ABI != obj.ABIInternal { v.Fatalf("MOVOstorezero can be only used in ABIInternal functions") @@ -836,7 +836,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() switch { case p.As == x86.AADDQ && p.From.Offset == 1: p.As = x86.AINCQ @@ -852,7 +852,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_NONE } memIdx(&p.To, v) - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX, ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ, ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS: diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index ca6720bb33..7646be6147 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -480,10 +480,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg, ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg, ssa.OpS390XLDGR, ssa.OpS390XLGDR, @@ -499,10 +499,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.OpCopy: if v.Type.IsMemory() { return @@ -618,15 +618,15 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { vo := v.AuxValAndOff() p := s.Prog(s390x.AMVC) p.From.Type = obj.TYPE_CONST - p.From.Offset = vo.Val() + p.From.Offset = vo.Val64() p.SetFrom3(obj.Addr{ Type: obj.TYPE_MEM, Reg: v.Args[1].Reg(), - Offset: vo.Off(), + Offset: vo.Off64(), }) p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() - p.To.Offset = vo.Off() + p.To.Offset = vo.Off64() case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4, ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4: for i := 2; i < len(v.Args)-1; i++ { diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index d6d122dc78..199b73c42f 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -258,17 +258,17 @@ (Zero [4] destptr mem) => (MOVLstoreconst [0] destptr mem) (Zero [3] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,2)] destptr - (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVBstoreconst [makeValAndOff(0,2)] destptr + (MOVWstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [5] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVBstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [6] destptr mem) => - (MOVWstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVWstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [7] destptr mem) => - (MOVLstoreconst [makeValAndOff32(0,3)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVLstoreconst [makeValAndOff(0,3)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) // Strip off any fractional word zeroing. (Zero [s] destptr mem) && s%4 != 0 && s > 4 => @@ -277,17 +277,17 @@ // Zero small numbers of words directly. (Zero [8] destptr mem) => - (MOVLstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVLstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [12] destptr mem) => - (MOVLstoreconst [makeValAndOff32(0,8)] destptr - (MOVLstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem))) + (MOVLstoreconst [makeValAndOff(0,8)] destptr + (MOVLstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem))) (Zero [16] destptr mem) => - (MOVLstoreconst [makeValAndOff32(0,12)] destptr - (MOVLstoreconst [makeValAndOff32(0,8)] destptr - (MOVLstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)))) + (MOVLstoreconst [makeValAndOff(0,12)] destptr + (MOVLstoreconst [makeValAndOff(0,8)] destptr + (MOVLstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)))) // Medium zeroing uses a duff device. (Zero [s] destptr mem) @@ -621,12 +621,12 @@ ((ADD|AND|OR|XOR)Lconstmodify [valoff1.addOffset32(off2)] {sym} base mem) // Fold constants into stores. -(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(int64(off)) => - (MOVLstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) -(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(int64(off)) => - (MOVWstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) -(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(int64(off)) => - (MOVBstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) +(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) => + (MOVLstoreconst [makeValAndOff(c,off)] {sym} ptr mem) +(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) => + (MOVWstoreconst [makeValAndOff(c,off)] {sym} ptr mem) +(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) => + (MOVBstoreconst [makeValAndOff(c,off)] {sym} ptr mem) // Fold address offsets into constant stores. (MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && sc.canAdd32(off) => @@ -676,8 +676,8 @@ (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, l) => ((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr 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, l) && validValAndOff(int64(c),int64(off)) => - ((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff32(c,off)] {sym} ptr mem) + && y.Uses==1 && l.Uses==1 && clobber(y, l) => + ((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem) // fold LEALs together (LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => @@ -995,49 +995,49 @@ && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - => (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) (MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - => (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) (MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) && x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 1) && clobber(x) - => (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p0 mem) (MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem)) && x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 1) && clobber(x) - => (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p0 mem) (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) && x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - => (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) (MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) && x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - => (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) (MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) && x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 2) && clobber(x) - => (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p0 mem) (MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem)) && x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 2) && clobber(x) - => (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p0 mem) // Combine stores into larger (unaligned) stores. (MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem)) @@ -1099,13 +1099,12 @@ (CMP(L|W|B)const l:(MOV(L|W|B)load {sym} [off] ptr mem) [c]) && l.Uses == 1 - && validValAndOff(int64(c), int64(off)) && clobber(l) => - @l.Block (CMP(L|W|B)constload {sym} [makeValAndOff32(int32(c),int32(off))] ptr mem) + @l.Block (CMP(L|W|B)constload {sym} [makeValAndOff(int32(c),off)] ptr mem) -(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(c),int64(off)) => (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem) -(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int16(c)),int64(off)) => (CMPWconstload {sym} [makeValAndOff32(int32(int16(c)),off)] ptr mem) -(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int8(c)),int64(off)) => (CMPBconstload {sym} [makeValAndOff32(int32(int8(c)),off)] ptr mem) +(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) +(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPWconstload {sym} [makeValAndOff(int32(int16(c)),off)] ptr mem) +(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPBconstload {sym} [makeValAndOff(int32(int8(c)),off)] ptr mem) (MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read8(sym, int64(off)))]) (MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) diff --git a/src/cmd/compile/internal/ssa/gen/386splitload.rules b/src/cmd/compile/internal/ssa/gen/386splitload.rules index ed93b90b73..29d4f8c227 100644 --- a/src/cmd/compile/internal/ssa/gen/386splitload.rules +++ b/src/cmd/compile/internal/ssa/gen/386splitload.rules @@ -6,6 +6,6 @@ (CMP(L|W|B)load {sym} [off] ptr x mem) => (CMP(L|W|B) (MOV(L|W|B)load {sym} [off] ptr mem) x) -(CMPLconstload {sym} [vo] ptr mem) => (CMPLconst (MOVLload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) -(CMPWconstload {sym} [vo] ptr mem) => (CMPWconst (MOVWload {sym} [vo.Off32()] ptr mem) [vo.Val16()]) -(CMPBconstload {sym} [vo] ptr mem) => (CMPBconst (MOVBload {sym} [vo.Off32()] ptr mem) [vo.Val8()]) +(CMPLconstload {sym} [vo] ptr mem) => (CMPLconst (MOVLload {sym} [vo.Off()] ptr mem) [vo.Val()]) +(CMPWconstload {sym} [vo] ptr mem) => (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()]) +(CMPBconstload {sym} [vo] ptr mem) => (CMPBconst (MOVBload {sym} [vo.Off()] ptr mem) [vo.Val8()]) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 7b03034bb7..c61b460a56 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -318,46 +318,46 @@ // Lowering Zero instructions (Zero [0] _ mem) => mem -(Zero [1] destptr mem) => (MOVBstoreconst [makeValAndOff32(0,0)] destptr mem) -(Zero [2] destptr mem) => (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem) -(Zero [4] destptr mem) => (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem) -(Zero [8] destptr mem) => (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem) +(Zero [1] destptr mem) => (MOVBstoreconst [makeValAndOff(0,0)] destptr mem) +(Zero [2] destptr mem) => (MOVWstoreconst [makeValAndOff(0,0)] destptr mem) +(Zero [4] destptr mem) => (MOVLstoreconst [makeValAndOff(0,0)] destptr mem) +(Zero [8] destptr mem) => (MOVQstoreconst [makeValAndOff(0,0)] destptr mem) (Zero [3] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,2)] destptr - (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVBstoreconst [makeValAndOff(0,2)] destptr + (MOVWstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [5] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVBstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [6] destptr mem) => - (MOVWstoreconst [makeValAndOff32(0,4)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVWstoreconst [makeValAndOff(0,4)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [7] destptr mem) => - (MOVLstoreconst [makeValAndOff32(0,3)] destptr - (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVLstoreconst [makeValAndOff(0,3)] destptr + (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) // Strip off any fractional word zeroing. (Zero [s] destptr mem) && s%8 != 0 && s > 8 && !config.useSSE => (Zero [s-s%8] (OffPtr destptr [s%8]) - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) // Zero small numbers of words directly. (Zero [16] destptr mem) && !config.useSSE => - (MOVQstoreconst [makeValAndOff32(0,8)] destptr - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVQstoreconst [makeValAndOff(0,8)] destptr + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [24] destptr mem) && !config.useSSE => - (MOVQstoreconst [makeValAndOff32(0,16)] destptr - (MOVQstoreconst [makeValAndOff32(0,8)] destptr - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem))) + (MOVQstoreconst [makeValAndOff(0,16)] destptr + (MOVQstoreconst [makeValAndOff(0,8)] destptr + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem))) (Zero [32] destptr mem) && !config.useSSE => - (MOVQstoreconst [makeValAndOff32(0,24)] destptr - (MOVQstoreconst [makeValAndOff32(0,16)] destptr - (MOVQstoreconst [makeValAndOff32(0,8)] destptr - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)))) + (MOVQstoreconst [makeValAndOff(0,24)] destptr + (MOVQstoreconst [makeValAndOff(0,16)] destptr + (MOVQstoreconst [makeValAndOff(0,8)] destptr + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)))) (Zero [s] destptr mem) && s > 8 && s < 16 && config.useSSE => - (MOVQstoreconst [makeValAndOff32(0,int32(s-8))] destptr - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVQstoreconst [makeValAndOff(0,int32(s-8))] destptr + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) // Adjust zeros to be a multiple of 16 bytes. (Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE => @@ -366,7 +366,7 @@ (Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE => (Zero [s-s%16] (OffPtr destptr [s%16]) - (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) (Zero [16] destptr mem) && config.useSSE => (MOVOstorezero destptr mem) @@ -1122,13 +1122,13 @@ // Fold constants into stores. (MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) && validVal(c) => - (MOVQstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + (MOVQstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) (MOVLstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) => - (MOVLstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + (MOVLstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) (MOVWstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) => - (MOVWstoreconst [makeValAndOff32(int32(int16(c)),off)] {sym} ptr mem) + (MOVWstoreconst [makeValAndOff(int32(int16(c)),off)] {sym} ptr mem) (MOVBstore [off] {sym} ptr (MOV(L|Q)const [c]) mem) => - (MOVBstoreconst [makeValAndOff32(int32(int8(c)),off)] {sym} ptr mem) + (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem) // Fold address offsets into constant stores. (MOV(Q|L|W|B)storeconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd32(off) => @@ -1868,32 +1868,32 @@ && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - => (MOVWstoreconst [makeValAndOff64(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) (MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - => (MOVWstoreconst [makeValAndOff64(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) + => (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) && x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - => (MOVLstoreconst [makeValAndOff64(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) (MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) && x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - => (MOVLstoreconst [makeValAndOff64(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) + => (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem)) && x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - => (MOVQstore [a.Off32()] {s} p (MOVQconst [a.Val()&0xffffffff | c.Val()<<32]) mem) + => (MOVQstore [a.Off()] {s} p (MOVQconst [a.Val64()&0xffffffff | c.Val64()<<32]) mem) (MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem)) && x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - => (MOVQstore [a.Off32()] {s} p (MOVQconst [a.Val()&0xffffffff | c.Val()<<32]) mem) + => (MOVQstore [a.Off()] {s} p (MOVQconst [a.Val64()&0xffffffff | c.Val64()<<32]) mem) (MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem)) && config.useSSE && x.Uses == 1 @@ -1901,7 +1901,7 @@ && c.Val() == 0 && c2.Val() == 0 && clobber(x) - => (MOVOstorezero [c2.Off32()] {s} p mem) + => (MOVOstorezero [c2.Off()] {s} p mem) // Combine stores into larger (unaligned) stores. Little endian. (MOVBstore [i] {s} p (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p w mem)) @@ -2120,11 +2120,11 @@ (MOVBQZX (MOVBQZX x)) => (MOVBQZX x) (MOVQstore [off] {sym} ptr a:((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) => - ((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) => + ((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) (MOVLstore [off] {sym} ptr a:((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) => - ((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) => + ((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) // float <-> int register moves, with no conversion. // These come up when compiling math.{Float{32,64}bits,Float{32,64}frombits}. @@ -2184,23 +2184,22 @@ (CMP(Q|L)const l:(MOV(Q|L)load {sym} [off] ptr mem) [c]) && l.Uses == 1 && clobber(l) => -@l.Block (CMP(Q|L)constload {sym} [makeValAndOff32(c,off)] ptr mem) +@l.Block (CMP(Q|L)constload {sym} [makeValAndOff(c,off)] ptr mem) (CMP(W|B)const l:(MOV(W|B)load {sym} [off] ptr mem) [c]) && l.Uses == 1 && clobber(l) => -@l.Block (CMP(W|B)constload {sym} [makeValAndOff32(int32(c),off)] ptr mem) +@l.Block (CMP(W|B)constload {sym} [makeValAndOff(int32(c),off)] ptr mem) -(CMPQload {sym} [off] ptr (MOVQconst [c]) mem) && validValAndOff(c,int64(off)) => (CMPQconstload {sym} [makeValAndOff64(c,int64(off))] ptr mem) -(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(c),int64(off)) => (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem) -(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int16(c)),int64(off)) => (CMPWconstload {sym} [makeValAndOff32(int32(int16(c)),off)] ptr mem) -(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int8(c)),int64(off)) => (CMPBconstload {sym} [makeValAndOff32(int32(int8(c)),off)] ptr mem) +(CMPQload {sym} [off] ptr (MOVQconst [c]) mem) && validVal(c) => (CMPQconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) +(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) +(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPWconstload {sym} [makeValAndOff(int32(int16(c)),off)] ptr mem) +(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) => (CMPBconstload {sym} [makeValAndOff(int32(int8(c)),off)] ptr mem) (TEST(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) l2) && l == l2 && l.Uses == 2 - && validValAndOff(0, int64(off)) && clobber(l) => - @l.Block (CMP(Q|L|W|B)constload {sym} [makeValAndOff64(0, int64(off))] ptr mem) + @l.Block (CMP(Q|L|W|B)constload {sym} [makeValAndOff(0, off)] ptr mem) // Convert ANDload to MOVload when we can do the AND in a containing TEST op. // Only do when it's within the same block, so we don't have flags live across basic block boundaries. diff --git a/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules b/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules index a50d509d0d..dd8f8ac4a1 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64splitload.rules @@ -18,28 +18,28 @@ (CMP(Q|L|W|B)load {sym} [off] ptr x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)load {sym} [off] ptr mem) x) -(CMP(Q|L|W|B)constload {sym} [vo] ptr mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)load {sym} [vo.Off32()] ptr mem) x) +(CMP(Q|L|W|B)constload {sym} [vo] ptr mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)load {sym} [vo.Off()] ptr mem) x) -(CMPQconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPQconst (MOVQload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) -(CMPLconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPLconst (MOVLload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) -(CMPWconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPWconst (MOVWload {sym} [vo.Off32()] ptr mem) [vo.Val16()]) -(CMPBconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPBconst (MOVBload {sym} [vo.Off32()] ptr mem) [vo.Val8()]) +(CMPQconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPQconst (MOVQload {sym} [vo.Off()] ptr mem) [vo.Val()]) +(CMPLconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPLconst (MOVLload {sym} [vo.Off()] ptr mem) [vo.Val()]) +(CMPWconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()]) +(CMPBconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPBconst (MOVBload {sym} [vo.Off()] ptr mem) [vo.Val8()]) (CMP(Q|L|W|B)loadidx1 {sym} [off] ptr idx x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)loadidx1 {sym} [off] ptr idx mem) x) (CMPQloadidx8 {sym} [off] ptr idx x mem) => (CMPQ (MOVQloadidx8 {sym} [off] ptr idx mem) x) (CMPLloadidx4 {sym} [off] ptr idx x mem) => (CMPL (MOVLloadidx4 {sym} [off] ptr idx mem) x) (CMPWloadidx2 {sym} [off] ptr idx x mem) => (CMPW (MOVWloadidx2 {sym} [off] ptr idx mem) x) -(CMP(Q|L|W|B)constloadidx1 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)loadidx1 {sym} [vo.Off32()] ptr idx mem) x) -(CMPQconstloadidx8 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTQ x:(MOVQloadidx8 {sym} [vo.Off32()] ptr idx mem) x) -(CMPLconstloadidx4 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTL x:(MOVLloadidx4 {sym} [vo.Off32()] ptr idx mem) x) -(CMPWconstloadidx2 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTW x:(MOVWloadidx2 {sym} [vo.Off32()] ptr idx mem) x) +(CMP(Q|L|W|B)constloadidx1 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)loadidx1 {sym} [vo.Off()] ptr idx mem) x) +(CMPQconstloadidx8 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTQ x:(MOVQloadidx8 {sym} [vo.Off()] ptr idx mem) x) +(CMPLconstloadidx4 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTL x:(MOVLloadidx4 {sym} [vo.Off()] ptr idx mem) x) +(CMPWconstloadidx2 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTW x:(MOVWloadidx2 {sym} [vo.Off()] ptr idx mem) x) -(CMPQconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPQconst (MOVQloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) -(CMPLconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPLconst (MOVLloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) -(CMPWconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPWconst (MOVWloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val16()]) -(CMPBconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPBconst (MOVBloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val8()]) +(CMPQconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPQconst (MOVQloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) +(CMPLconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPLconst (MOVLloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) +(CMPWconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPWconst (MOVWloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val16()]) +(CMPBconstloadidx1 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPBconst (MOVBloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val8()]) -(CMPQconstloadidx8 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPQconst (MOVQloadidx8 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) -(CMPLconstloadidx4 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPLconst (MOVLloadidx4 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) -(CMPWconstloadidx2 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPWconst (MOVWloadidx2 {sym} [vo.Off32()] ptr idx mem) [vo.Val16()]) +(CMPQconstloadidx8 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPQconst (MOVQloadidx8 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) +(CMPLconstloadidx4 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPLconst (MOVLloadidx4 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) +(CMPWconstloadidx2 {sym} [vo] ptr idx mem) && vo.Val() != 0 => (CMPWconst (MOVWloadidx2 {sym} [vo.Off()] ptr idx mem) [vo.Val16()]) diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index 1f75f78a71..0fdd231d71 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -386,13 +386,13 @@ // MVC for other moves. Use up to 4 instructions (sizes up to 1024 bytes). (Move [s] dst src mem) && s > 0 && s <= 256 && logLargeCopy(v, s) => - (MVC [makeValAndOff32(int32(s), 0)] dst src mem) + (MVC [makeValAndOff(int32(s), 0)] dst src mem) (Move [s] dst src mem) && s > 256 && s <= 512 && logLargeCopy(v, s) => - (MVC [makeValAndOff32(int32(s)-256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem)) + (MVC [makeValAndOff(int32(s)-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)) (Move [s] dst src mem) && s > 512 && s <= 768 && logLargeCopy(v, s) => - (MVC [makeValAndOff32(int32(s)-512, 512)] dst src (MVC [makeValAndOff32(256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem))) + (MVC [makeValAndOff(int32(s)-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))) (Move [s] dst src mem) && s > 768 && s <= 1024 && logLargeCopy(v, s) => - (MVC [makeValAndOff32(int32(s)-768, 768)] dst src (MVC [makeValAndOff32(256, 512)] dst src (MVC [makeValAndOff32(256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem)))) + (MVC [makeValAndOff(int32(s)-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))) // Move more than 1024 bytes using a loop. (Move [s] dst src mem) && s > 1024 && logLargeCopy(v, s) => @@ -405,20 +405,20 @@ (Zero [4] destptr mem) => (MOVWstoreconst [0] destptr mem) (Zero [8] destptr mem) => (MOVDstoreconst [0] destptr mem) (Zero [3] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,2)] destptr + (MOVBstoreconst [makeValAndOff(0,2)] destptr (MOVHstoreconst [0] destptr mem)) (Zero [5] destptr mem) => - (MOVBstoreconst [makeValAndOff32(0,4)] destptr + (MOVBstoreconst [makeValAndOff(0,4)] destptr (MOVWstoreconst [0] destptr mem)) (Zero [6] destptr mem) => - (MOVHstoreconst [makeValAndOff32(0,4)] destptr + (MOVHstoreconst [makeValAndOff(0,4)] destptr (MOVWstoreconst [0] destptr mem)) (Zero [7] destptr mem) => - (MOVWstoreconst [makeValAndOff32(0,3)] destptr + (MOVWstoreconst [makeValAndOff(0,3)] destptr (MOVWstoreconst [0] destptr mem)) (Zero [s] destptr mem) && s > 0 && s <= 1024 => - (CLEAR [makeValAndOff32(int32(s), 0)] destptr mem) + (CLEAR [makeValAndOff(int32(s), 0)] destptr mem) // Zero more than 1024 bytes using a loop. (Zero [s] destptr mem) && s > 1024 => @@ -948,22 +948,22 @@ // Fold constants into stores. (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(int64(off)) && ptr.Op != OpSB => - (MOVDstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + (MOVDstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && is16Bit(c) && isU12Bit(int64(off)) && ptr.Op != OpSB => - (MOVWstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + (MOVWstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && isU12Bit(int64(off)) && ptr.Op != OpSB => - (MOVHstoreconst [makeValAndOff32(int32(int16(c)),off)] {sym} ptr mem) + (MOVHstoreconst [makeValAndOff(int32(int16(c)),off)] {sym} ptr mem) (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && is20Bit(int64(off)) && ptr.Op != OpSB => - (MOVBstoreconst [makeValAndOff32(int32(int8(c)),off)] {sym} ptr mem) + (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem) // Fold address offsets into constant stores. -(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off()+int64(off)) => +(MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off64()+int64(off)) => (MOVDstoreconst [sc.addOffset32(off)] {s} ptr mem) -(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off()+int64(off)) => +(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off64()+int64(off)) => (MOVWstoreconst [sc.addOffset32(off)] {s} ptr mem) -(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off()+int64(off)) => +(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && isU12Bit(sc.Off64()+int64(off)) => (MOVHstoreconst [sc.addOffset32(off)] {s} ptr mem) -(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && is20Bit(sc.Off()+int64(off)) => +(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && is20Bit(sc.Off64()+int64(off)) => (MOVBstoreconst [sc.addOffset32(off)] {s} ptr mem) // Merge address calculations into loads and stores. @@ -1306,19 +1306,19 @@ && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - => (MOVHstoreconst [makeValAndOff32(c.Val32()&0xff | a.Val32()<<8, a.Off32())] {s} p mem) + => (MOVHstoreconst [makeValAndOff(c.Val()&0xff | a.Val()<<8, a.Off())] {s} p mem) (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem)) && p.Op != OpSB && x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - => (MOVWstore [a.Off32()] {s} p (MOVDconst [int64(c.Val32()&0xffff | a.Val32()<<16)]) mem) + => (MOVWstore [a.Off()] {s} p (MOVDconst [int64(c.Val()&0xffff | a.Val()<<16)]) mem) (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) && p.Op != OpSB && x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - => (MOVDstore [a.Off32()] {s} p (MOVDconst [c.Val()&0xffffffff | a.Val()<<32]) mem) + => (MOVDstore [a.Off()] {s} p (MOVDconst [c.Val64()&0xffffffff | a.Val64()<<32]) mem) // Combine stores into larger (unaligned) stores. // It doesn't work on global data (based on SB) because stores with relative addressing diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 574377a33d..342df73d02 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -382,13 +382,13 @@ type Sym interface { // The low 32 bits hold a pointer offset. type ValAndOff int64 -func (x ValAndOff) Val() int64 { return int64(x) >> 32 } -func (x ValAndOff) Val32() int32 { return int32(int64(x) >> 32) } +func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) } +func (x ValAndOff) Val64() int64 { return int64(x) >> 32 } func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) } func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) } -func (x ValAndOff) Off() int64 { return int64(int32(x)) } -func (x ValAndOff) Off32() int32 { return int32(x) } +func (x ValAndOff) Off64() int64 { return int64(int32(x)) } +func (x ValAndOff) Off() int32 { return int32(x) } func (x ValAndOff) String() string { return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off()) @@ -400,40 +400,16 @@ func validVal(val int64) bool { return val == int64(int32(val)) } -// validOff reports whether the offset can be used -// as an argument to makeValAndOff. -func validOff(off int64) bool { - return off == int64(int32(off)) -} - -// validValAndOff reports whether we can fit the value and offset into -// a ValAndOff value. -func validValAndOff(val, off int64) bool { - if !validVal(val) { - return false - } - if !validOff(off) { - return false - } - return true -} - -func makeValAndOff32(val, off int32) ValAndOff { +func makeValAndOff(val, off int32) ValAndOff { return ValAndOff(int64(val)<<32 + int64(uint32(off))) } -func makeValAndOff64(val, off int64) ValAndOff { - if !validValAndOff(val, off) { - panic("invalid makeValAndOff64") - } - return ValAndOff(val<<32 + int64(uint32(off))) -} func (x ValAndOff) canAdd32(off int32) bool { - newoff := x.Off() + int64(off) + newoff := x.Off64() + int64(off) return newoff == int64(int32(newoff)) } func (x ValAndOff) canAdd64(off int64) bool { - newoff := x.Off() + off + newoff := x.Off64() + off return newoff == int64(int32(newoff)) } @@ -441,13 +417,13 @@ func (x ValAndOff) addOffset32(off int32) ValAndOff { if !x.canAdd32(off) { panic("invalid ValAndOff.addOffset32") } - return makeValAndOff64(x.Val(), x.Off()+int64(off)) + return makeValAndOff(x.Val(), x.Off()+off) } func (x ValAndOff) addOffset64(off int64) ValAndOff { if !x.canAdd64(off) { panic("invalid ValAndOff.addOffset64") } - return makeValAndOff64(x.Val(), x.Off()+off) + return makeValAndOff(x.Val(), x.Off()+int32(off)) } // int128 is a type that stores a 128-bit constant. diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 726d68e243..1ec2d26f75 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -1996,8 +1996,8 @@ func rewriteValue386_Op386CMPBconst(v *Value) bool { return true } // match: (CMPBconst l:(MOVBload {sym} [off] ptr mem) [c]) - // cond: l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l) - // result: @l.Block (CMPBconstload {sym} [makeValAndOff32(int32(c),int32(off))] ptr mem) + // cond: l.Uses == 1 && clobber(l) + // result: @l.Block (CMPBconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { c := auxIntToInt8(v.AuxInt) l := v_0 @@ -2008,13 +2008,13 @@ func rewriteValue386_Op386CMPBconst(v *Value) bool { sym := auxToSym(l.Aux) mem := l.Args[1] ptr := l.Args[0] - if !(l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l)) { + if !(l.Uses == 1 && clobber(l)) { break } b = l.Block v0 := b.NewValue0(l.Pos, Op386CMPBconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), int32(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -2026,8 +2026,7 @@ func rewriteValue386_Op386CMPBload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (CMPBload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(int8(c)),int64(off)) - // result: (CMPBconstload {sym} [makeValAndOff32(int32(int8(c)),off)] ptr mem) + // result: (CMPBconstload {sym} [makeValAndOff(int32(int8(c)),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -2037,11 +2036,8 @@ func rewriteValue386_Op386CMPBload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(int8(c)), int64(off))) { - break - } v.reset(Op386CMPBconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int8(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int8(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -2304,8 +2300,8 @@ func rewriteValue386_Op386CMPLconst(v *Value) bool { return true } // match: (CMPLconst l:(MOVLload {sym} [off] ptr mem) [c]) - // cond: l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l) - // result: @l.Block (CMPLconstload {sym} [makeValAndOff32(int32(c),int32(off))] ptr mem) + // cond: l.Uses == 1 && clobber(l) + // result: @l.Block (CMPLconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { c := auxIntToInt32(v.AuxInt) l := v_0 @@ -2316,13 +2312,13 @@ func rewriteValue386_Op386CMPLconst(v *Value) bool { sym := auxToSym(l.Aux) mem := l.Args[1] ptr := l.Args[0] - if !(l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l)) { + if !(l.Uses == 1 && clobber(l)) { break } b = l.Block v0 := b.NewValue0(l.Pos, Op386CMPLconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), int32(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -2334,8 +2330,7 @@ func rewriteValue386_Op386CMPLload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (CMPLload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(c),int64(off)) - // result: (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem) + // result: (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -2345,11 +2340,8 @@ func rewriteValue386_Op386CMPLload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(c), int64(off))) { - break - } v.reset(Op386CMPLconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -2597,8 +2589,8 @@ func rewriteValue386_Op386CMPWconst(v *Value) bool { return true } // match: (CMPWconst l:(MOVWload {sym} [off] ptr mem) [c]) - // cond: l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l) - // result: @l.Block (CMPWconstload {sym} [makeValAndOff32(int32(c),int32(off))] ptr mem) + // cond: l.Uses == 1 && clobber(l) + // result: @l.Block (CMPWconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { c := auxIntToInt16(v.AuxInt) l := v_0 @@ -2609,13 +2601,13 @@ func rewriteValue386_Op386CMPWconst(v *Value) bool { sym := auxToSym(l.Aux) mem := l.Args[1] ptr := l.Args[0] - if !(l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l)) { + if !(l.Uses == 1 && clobber(l)) { break } b = l.Block v0 := b.NewValue0(l.Pos, Op386CMPWconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), int32(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -2627,8 +2619,7 @@ func rewriteValue386_Op386CMPWload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (CMPWload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(int16(c)),int64(off)) - // result: (CMPWconstload {sym} [makeValAndOff32(int32(int16(c)),off)] ptr mem) + // result: (CMPWconstload {sym} [makeValAndOff(int32(int16(c)),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -2638,11 +2629,8 @@ func rewriteValue386_Op386CMPWload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(int16(c)), int64(off))) { - break - } v.reset(Op386CMPWconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int16(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int16(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -3735,8 +3723,7 @@ func rewriteValue386_Op386MOVBstore(v *Value) bool { return true } // match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) - // cond: validOff(int64(off)) - // result: (MOVBstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) + // result: (MOVBstoreconst [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -3746,11 +3733,8 @@ func rewriteValue386_Op386MOVBstore(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validOff(int64(off))) { - break - } v.reset(Op386MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -4090,7 +4074,7 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { } // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -4108,14 +4092,14 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { break } v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xff|c.Val()<<8), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -4133,14 +4117,14 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { break } v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xff|c.Val()<<8), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem)) // cond: x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 1) && clobber(x) - // result: (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p0 mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -4159,14 +4143,14 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { break } v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xff|c.Val()<<8), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p0, mem) return true } // match: (MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem)) // cond: x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 1) && clobber(x) - // result: (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p0 mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -4185,7 +4169,7 @@ func rewriteValue386_Op386MOVBstoreconst(v *Value) bool { break } v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xff|c.Val()<<8), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p0, mem) return true @@ -4304,8 +4288,7 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { return true } // match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) - // cond: validOff(int64(off)) - // result: (MOVLstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) + // result: (MOVLstoreconst [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4315,11 +4298,8 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validOff(int64(off))) { - break - } v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -4602,8 +4582,8 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { break } // match: (MOVLstore {sym} [off] ptr y:(ADDLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(int64(c),int64(off)) - // result: (ADDLconstmodify [makeValAndOff32(c,off)] {sym} ptr mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) + // result: (ADDLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4618,18 +4598,18 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { break } mem := l.Args[1] - if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(int64(c), int64(off))) { + if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { break } v.reset(Op386ADDLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore {sym} [off] ptr y:(ANDLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(int64(c),int64(off)) - // result: (ANDLconstmodify [makeValAndOff32(c,off)] {sym} ptr mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) + // result: (ANDLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4644,18 +4624,18 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { break } mem := l.Args[1] - if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(int64(c), int64(off))) { + if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { break } v.reset(Op386ANDLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore {sym} [off] ptr y:(ORLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(int64(c),int64(off)) - // result: (ORLconstmodify [makeValAndOff32(c,off)] {sym} ptr mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) + // result: (ORLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4670,18 +4650,18 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { break } mem := l.Args[1] - if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(int64(c), int64(off))) { + if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { break } v.reset(Op386ORLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore {sym} [off] ptr y:(XORLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) - // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(int64(c),int64(off)) - // result: (XORLconstmodify [makeValAndOff32(c,off)] {sym} ptr mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y, l) + // result: (XORLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4696,11 +4676,11 @@ func rewriteValue386_Op386MOVLstore(v *Value) bool { break } mem := l.Args[1] - if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l) && validValAndOff(int64(c), int64(off))) { + if ptr != l.Args[0] || mem != v_2 || !(y.Uses == 1 && l.Uses == 1 && clobber(y, l)) { break } v.reset(Op386XORLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -5286,8 +5266,7 @@ func rewriteValue386_Op386MOVWstore(v *Value) bool { return true } // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) - // cond: validOff(int64(off)) - // result: (MOVWstoreconst [makeValAndOff32(c,off)] {sym} ptr mem) + // result: (MOVWstoreconst [makeValAndOff(c,off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -5297,11 +5276,8 @@ func rewriteValue386_Op386MOVWstore(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validOff(int64(off))) { - break - } v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -5490,7 +5466,7 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { } // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -5508,14 +5484,14 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { break } v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xffff|c.Val()<<16), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -5533,14 +5509,14 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { break } v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xffff|c.Val()<<16), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem)) // cond: x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 2) && clobber(x) - // result: (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p0 mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -5559,14 +5535,14 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { break } v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xffff|c.Val()<<16), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p0, mem) return true } // match: (MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem)) // cond: x.Uses == 1 && a.Off() == c.Off() && sequentialAddresses(p0, p1, 2) && clobber(x) - // result: (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p0 mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -5585,7 +5561,7 @@ func rewriteValue386_Op386MOVWstoreconst(v *Value) bool { break } v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(a.Val()&0xffff|c.Val()<<16), a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p0, mem) return true @@ -11574,7 +11550,7 @@ func rewriteValue386_OpZero(v *Value) bool { return true } // match: (Zero [3] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,2)] destptr (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,2)] destptr (MOVWstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 3 { break @@ -11582,15 +11558,15 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 2)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 2)) v0 := b.NewValue0(v.Pos, Op386MOVWstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [5] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 5 { break @@ -11598,15 +11574,15 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [6] destptr mem) - // result: (MOVWstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVWstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 6 { break @@ -11614,15 +11590,15 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [7] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,3)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVLstoreconst [makeValAndOff(0,3)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 7 { break @@ -11630,9 +11606,9 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 3)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 3)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true @@ -11659,7 +11635,7 @@ func rewriteValue386_OpZero(v *Value) bool { return true } // match: (Zero [8] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVLstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 8 { break @@ -11667,15 +11643,15 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [12] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,8)] destptr (MOVLstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem))) + // result: (MOVLstoreconst [makeValAndOff(0,8)] destptr (MOVLstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem))) for { if auxIntToInt64(v.AuxInt) != 12 { break @@ -11683,18 +11659,18 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 8)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 8)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v1 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v1.AddArg2(destptr, mem) v0.AddArg2(destptr, v1) v.AddArg2(destptr, v0) return true } // match: (Zero [16] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,12)] destptr (MOVLstoreconst [makeValAndOff32(0,8)] destptr (MOVLstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)))) + // result: (MOVLstoreconst [makeValAndOff(0,12)] destptr (MOVLstoreconst [makeValAndOff(0,8)] destptr (MOVLstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)))) for { if auxIntToInt64(v.AuxInt) != 16 { break @@ -11702,13 +11678,13 @@ func rewriteValue386_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(Op386MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 12)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 12)) v0 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 8)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 8)) v1 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v2 := b.NewValue0(v.Pos, Op386MOVLstoreconst, types.TypeMem) - v2.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v2.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v2.AddArg2(destptr, mem) v1.AddArg2(destptr, v2) v0.AddArg2(destptr, v1) diff --git a/src/cmd/compile/internal/ssa/rewrite386splitload.go b/src/cmd/compile/internal/ssa/rewrite386splitload.go index fff26fa77e..90b5df8ae0 100644 --- a/src/cmd/compile/internal/ssa/rewrite386splitload.go +++ b/src/cmd/compile/internal/ssa/rewrite386splitload.go @@ -26,7 +26,7 @@ func rewriteValue386splitload_Op386CMPBconstload(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (CMPBconstload {sym} [vo] ptr mem) - // result: (CMPBconst (MOVBload {sym} [vo.Off32()] ptr mem) [vo.Val8()]) + // result: (CMPBconst (MOVBload {sym} [vo.Off()] ptr mem) [vo.Val8()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -35,7 +35,7 @@ func rewriteValue386splitload_Op386CMPBconstload(v *Value) bool { v.reset(Op386CMPBconst) v.AuxInt = int8ToAuxInt(vo.Val8()) v0 := b.NewValue0(v.Pos, Op386MOVBload, typ.UInt8) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -71,16 +71,16 @@ func rewriteValue386splitload_Op386CMPLconstload(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (CMPLconstload {sym} [vo] ptr mem) - // result: (CMPLconst (MOVLload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) + // result: (CMPLconst (MOVLload {sym} [vo.Off()] ptr mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) ptr := v_0 mem := v_1 v.reset(Op386CMPLconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -116,7 +116,7 @@ func rewriteValue386splitload_Op386CMPWconstload(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (CMPWconstload {sym} [vo] ptr mem) - // result: (CMPWconst (MOVWload {sym} [vo.Off32()] ptr mem) [vo.Val16()]) + // result: (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -125,7 +125,7 @@ func rewriteValue386splitload_Op386CMPWconstload(v *Value) bool { v.reset(Op386CMPWconst) v.AuxInt = int16ToAuxInt(vo.Val16()) v0 := b.NewValue0(v.Pos, Op386MOVWload, typ.UInt16) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 8da3b28b5c..d208624d0e 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -6962,7 +6962,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool { } // match: (CMPBconst l:(MOVBload {sym} [off] ptr mem) [c]) // cond: l.Uses == 1 && clobber(l) - // result: @l.Block (CMPBconstload {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // result: @l.Block (CMPBconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { c := auxIntToInt8(v.AuxInt) l := v_0 @@ -6979,7 +6979,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool { b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPBconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -7084,8 +7084,7 @@ func rewriteValueAMD64_OpAMD64CMPBload(v *Value) bool { return true } // match: (CMPBload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(int8(c)),int64(off)) - // result: (CMPBconstload {sym} [makeValAndOff32(int32(int8(c)),off)] ptr mem) + // result: (CMPBconstload {sym} [makeValAndOff(int32(int8(c)),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -7095,11 +7094,8 @@ func rewriteValueAMD64_OpAMD64CMPBload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(int8(c)), int64(off))) { - break - } v.reset(OpAMD64CMPBconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int8(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int8(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -7363,7 +7359,7 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value) bool { } // match: (CMPLconst l:(MOVLload {sym} [off] ptr mem) [c]) // cond: l.Uses == 1 && clobber(l) - // result: @l.Block (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem) + // result: @l.Block (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) for { c := auxIntToInt32(v.AuxInt) l := v_0 @@ -7380,7 +7376,7 @@ func rewriteValueAMD64_OpAMD64CMPLconst(v *Value) bool { b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPLconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -7485,8 +7481,7 @@ func rewriteValueAMD64_OpAMD64CMPLload(v *Value) bool { return true } // match: (CMPLload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(c),int64(off)) - // result: (CMPLconstload {sym} [makeValAndOff32(c,off)] ptr mem) + // result: (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -7496,11 +7491,8 @@ func rewriteValueAMD64_OpAMD64CMPLload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(c), int64(off))) { - break - } v.reset(OpAMD64CMPLconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -7933,7 +7925,7 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value) bool { } // match: (CMPQconst l:(MOVQload {sym} [off] ptr mem) [c]) // cond: l.Uses == 1 && clobber(l) - // result: @l.Block (CMPQconstload {sym} [makeValAndOff32(c,off)] ptr mem) + // result: @l.Block (CMPQconstload {sym} [makeValAndOff(c,off)] ptr mem) for { c := auxIntToInt32(v.AuxInt) l := v_0 @@ -7950,7 +7942,7 @@ func rewriteValueAMD64_OpAMD64CMPQconst(v *Value) bool { b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPQconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(c, off)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(c, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -8055,8 +8047,8 @@ func rewriteValueAMD64_OpAMD64CMPQload(v *Value) bool { return true } // match: (CMPQload {sym} [off] ptr (MOVQconst [c]) mem) - // cond: validValAndOff(c,int64(off)) - // result: (CMPQconstload {sym} [makeValAndOff64(c,int64(off))] ptr mem) + // cond: validVal(c) + // result: (CMPQconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -8066,11 +8058,11 @@ func rewriteValueAMD64_OpAMD64CMPQload(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) mem := v_2 - if !(validValAndOff(c, int64(off))) { + if !(validVal(c)) { break } v.reset(OpAMD64CMPQconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff64(c, int64(off))) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -8319,7 +8311,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool { } // match: (CMPWconst l:(MOVWload {sym} [off] ptr mem) [c]) // cond: l.Uses == 1 && clobber(l) - // result: @l.Block (CMPWconstload {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // result: @l.Block (CMPWconstload {sym} [makeValAndOff(int32(c),off)] ptr mem) for { c := auxIntToInt16(v.AuxInt) l := v_0 @@ -8336,7 +8328,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool { b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPWconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -8441,8 +8433,7 @@ func rewriteValueAMD64_OpAMD64CMPWload(v *Value) bool { return true } // match: (CMPWload {sym} [off] ptr (MOVLconst [c]) mem) - // cond: validValAndOff(int64(int16(c)),int64(off)) - // result: (CMPWconstload {sym} [makeValAndOff32(int32(int16(c)),off)] ptr mem) + // result: (CMPWconstload {sym} [makeValAndOff(int32(int16(c)),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -8452,11 +8443,8 @@ func rewriteValueAMD64_OpAMD64CMPWload(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) mem := v_2 - if !(validValAndOff(int64(int16(c)), int64(off))) { - break - } v.reset(OpAMD64CMPWconstload) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int16(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int16(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -10600,7 +10588,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { return true } // match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) - // result: (MOVBstoreconst [makeValAndOff32(int32(int8(c)),off)] {sym} ptr mem) + // result: (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -10611,13 +10599,13 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { c := auxIntToInt32(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int8(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int8(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVBstore [off] {sym} ptr (MOVQconst [c]) mem) - // result: (MOVBstoreconst [makeValAndOff32(int32(int8(c)),off)] {sym} ptr mem) + // result: (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -10628,7 +10616,7 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { c := auxIntToInt64(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int8(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int8(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -11601,7 +11589,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { } // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff64(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -11619,14 +11607,14 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff64(a.Val()&0xff|c.Val()<<8, a.Off())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - // result: (MOVWstoreconst [makeValAndOff64(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) + // result: (MOVWstoreconst [makeValAndOff(a.Val()&0xff | c.Val()<<8, a.Off())] {s} p mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -11644,7 +11632,7 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff64(a.Val()&0xff|c.Val()<<8, a.Off())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xff|c.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true @@ -12258,7 +12246,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { return true } // match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) - // result: (MOVLstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + // result: (MOVLstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12269,13 +12257,13 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { c := auxIntToInt32(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr (MOVQconst [c]) mem) - // result: (MOVLstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + // result: (MOVLstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12286,7 +12274,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { c := auxIntToInt64(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -12842,8 +12830,8 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { return true } // 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(int64(c),int64(off)) && clobber(l, a) - // result: (ADDLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ADDLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12859,18 +12847,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ADDLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (ANDLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ANDLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12886,18 +12874,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ANDLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(ORLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (ORLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ORLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12913,18 +12901,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ORLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(XORLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (XORLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (XORLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12940,18 +12928,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64XORLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(BTCLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTCLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTCLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12967,18 +12955,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTCLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(BTRLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTRLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTRLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -12994,18 +12982,18 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTRLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVLstore [off] {sym} ptr a:(BTSLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTSLconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTSLconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -13021,11 +13009,11 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTSLconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -13099,7 +13087,7 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { } // match: (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - // result: (MOVQstore [a.Off32()] {s} p (MOVQconst [a.Val()&0xffffffff | c.Val()<<32]) mem) + // result: (MOVQstore [a.Off()] {s} p (MOVQconst [a.Val64()&0xffffffff | c.Val64()<<32]) mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -13117,16 +13105,16 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVQstore) - v.AuxInt = int32ToAuxInt(a.Off32()) + v.AuxInt = int32ToAuxInt(a.Off()) v.Aux = symToAux(s) v0 := b.NewValue0(x.Pos, OpAMD64MOVQconst, typ.UInt64) - v0.AuxInt = int64ToAuxInt(a.Val()&0xffffffff | c.Val()<<32) + v0.AuxInt = int64ToAuxInt(a.Val64()&0xffffffff | c.Val64()<<32) v.AddArg3(p, v0, mem) return true } // match: (MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - // result: (MOVQstore [a.Off32()] {s} p (MOVQconst [a.Val()&0xffffffff | c.Val()<<32]) mem) + // result: (MOVQstore [a.Off()] {s} p (MOVQconst [a.Val64()&0xffffffff | c.Val64()<<32]) mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -13144,10 +13132,10 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVQstore) - v.AuxInt = int32ToAuxInt(a.Off32()) + v.AuxInt = int32ToAuxInt(a.Off()) v.Aux = symToAux(s) v0 := b.NewValue0(x.Pos, OpAMD64MOVQconst, typ.UInt64) - v0.AuxInt = int64ToAuxInt(a.Val()&0xffffffff | c.Val()<<32) + v0.AuxInt = int64ToAuxInt(a.Val64()&0xffffffff | c.Val64()<<32) v.AddArg3(p, v0, mem) return true } @@ -13603,7 +13591,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } // match: (MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) // cond: validVal(c) - // result: (MOVQstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + // result: (MOVQstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -13617,7 +13605,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { break } v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -14023,8 +14011,8 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { return true } // match: (MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (ADDQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ADDQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14040,18 +14028,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ADDQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(ANDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (ANDQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ANDQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14067,18 +14055,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ANDQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(ORQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (ORQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (ORQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14094,18 +14082,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64ORQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(XORQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (XORQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (XORQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14121,18 +14109,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64XORQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(BTCQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTCQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTCQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14148,18 +14136,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTCQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(BTRQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTRQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTRQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14175,18 +14163,18 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTRQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVQstore [off] {sym} ptr a:(BTSQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) - // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c),int64(off)) && clobber(l, a) - // result: (BTSQconstmodify {sym} [makeValAndOff32(int32(c),off)] ptr mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) + // result: (BTSQconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -14202,11 +14190,11 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool { } mem := l.Args[1] ptr2 := l.Args[0] - if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(int64(c), int64(off)) && clobber(l, a)) { + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a)) { break } v.reset(OpAMD64BTSQconstmodify) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -14280,7 +14268,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool { } // match: (MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem)) // cond: config.useSSE && x.Uses == 1 && c2.Off() + 8 == c.Off() && c.Val() == 0 && c2.Val() == 0 && clobber(x) - // result: (MOVOstorezero [c2.Off32()] {s} p mem) + // result: (MOVOstorezero [c2.Off()] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -14298,7 +14286,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVOstorezero) - v.AuxInt = int32ToAuxInt(c2.Off32()) + v.AuxInt = int32ToAuxInt(c2.Off()) v.Aux = symToAux(s) v.AddArg2(p, mem) return true @@ -15085,7 +15073,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { return true } // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) - // result: (MOVWstoreconst [makeValAndOff32(int32(int16(c)),off)] {sym} ptr mem) + // result: (MOVWstoreconst [makeValAndOff(int32(int16(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -15096,13 +15084,13 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { c := auxIntToInt32(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int16(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int16(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true } // match: (MOVWstore [off] {sym} ptr (MOVQconst [c]) mem) - // result: (MOVWstoreconst [makeValAndOff32(int32(int16(c)),off)] {sym} ptr mem) + // result: (MOVWstoreconst [makeValAndOff(int32(int16(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -15113,7 +15101,7 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { c := auxIntToInt64(v_1.AuxInt) mem := v_2 v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int16(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int16(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -15495,7 +15483,7 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { } // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff64(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -15513,14 +15501,14 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff64(a.Val()&0xffff|c.Val()<<16, a.Off())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true } // match: (MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem)) // cond: x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - // result: (MOVLstoreconst [makeValAndOff64(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) + // result: (MOVLstoreconst [makeValAndOff(a.Val()&0xffff | c.Val()<<16, a.Off())] {s} p mem) for { a := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -15538,7 +15526,7 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool { break } v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff64(a.Val()&0xffff|c.Val()<<16, a.Off())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(a.Val()&0xffff|c.Val()<<16, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true @@ -27100,8 +27088,8 @@ func rewriteValueAMD64_OpAMD64TESTB(v *Value) bool { break } // match: (TESTB l:(MOVBload {sym} [off] ptr mem) l2) - // cond: l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l) - // result: @l.Block (CMPBconstload {sym} [makeValAndOff64(0, int64(off))] ptr mem) + // cond: l == l2 && l.Uses == 2 && clobber(l) + // result: @l.Block (CMPBconstload {sym} [makeValAndOff(0, off)] ptr mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { l := v_0 @@ -27113,13 +27101,13 @@ func rewriteValueAMD64_OpAMD64TESTB(v *Value) bool { mem := l.Args[1] ptr := l.Args[0] l2 := v_1 - if !(l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l)) { + if !(l == l2 && l.Uses == 2 && clobber(l)) { continue } b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPBconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff64(0, int64(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -27168,8 +27156,8 @@ func rewriteValueAMD64_OpAMD64TESTL(v *Value) bool { break } // match: (TESTL l:(MOVLload {sym} [off] ptr mem) l2) - // cond: l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l) - // result: @l.Block (CMPLconstload {sym} [makeValAndOff64(0, int64(off))] ptr mem) + // cond: l == l2 && l.Uses == 2 && clobber(l) + // result: @l.Block (CMPLconstload {sym} [makeValAndOff(0, off)] ptr mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { l := v_0 @@ -27181,13 +27169,13 @@ func rewriteValueAMD64_OpAMD64TESTL(v *Value) bool { mem := l.Args[1] ptr := l.Args[0] l2 := v_1 - if !(l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l)) { + if !(l == l2 && l.Uses == 2 && clobber(l)) { continue } b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPLconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff64(0, int64(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -27300,8 +27288,8 @@ func rewriteValueAMD64_OpAMD64TESTQ(v *Value) bool { break } // match: (TESTQ l:(MOVQload {sym} [off] ptr mem) l2) - // cond: l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l) - // result: @l.Block (CMPQconstload {sym} [makeValAndOff64(0, int64(off))] ptr mem) + // cond: l == l2 && l.Uses == 2 && clobber(l) + // result: @l.Block (CMPQconstload {sym} [makeValAndOff(0, off)] ptr mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { l := v_0 @@ -27313,13 +27301,13 @@ func rewriteValueAMD64_OpAMD64TESTQ(v *Value) bool { mem := l.Args[1] ptr := l.Args[0] l2 := v_1 - if !(l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l)) { + if !(l == l2 && l.Uses == 2 && clobber(l)) { continue } b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPQconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff64(0, int64(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -27440,8 +27428,8 @@ func rewriteValueAMD64_OpAMD64TESTW(v *Value) bool { break } // match: (TESTW l:(MOVWload {sym} [off] ptr mem) l2) - // cond: l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l) - // result: @l.Block (CMPWconstload {sym} [makeValAndOff64(0, int64(off))] ptr mem) + // cond: l == l2 && l.Uses == 2 && clobber(l) + // result: @l.Block (CMPWconstload {sym} [makeValAndOff(0, off)] ptr mem) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { l := v_0 @@ -27453,13 +27441,13 @@ func rewriteValueAMD64_OpAMD64TESTW(v *Value) bool { mem := l.Args[1] ptr := l.Args[0] l2 := v_1 - if !(l == l2 && l.Uses == 2 && validValAndOff(0, int64(off)) && clobber(l)) { + if !(l == l2 && l.Uses == 2 && clobber(l)) { continue } b = l.Block v0 := b.NewValue0(l.Pos, OpAMD64CMPWconstload, types.TypeFlags) v.copyOf(v0) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff64(0, int64(off))) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, off)) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) return true @@ -34060,7 +34048,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool { return true } // match: (Zero [1] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,0)] destptr mem) + // result: (MOVBstoreconst [makeValAndOff(0,0)] destptr mem) for { if auxIntToInt64(v.AuxInt) != 1 { break @@ -34068,12 +34056,12 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v.AddArg2(destptr, mem) return true } // match: (Zero [2] destptr mem) - // result: (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem) + // result: (MOVWstoreconst [makeValAndOff(0,0)] destptr mem) for { if auxIntToInt64(v.AuxInt) != 2 { break @@ -34081,12 +34069,12 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v.AddArg2(destptr, mem) return true } // match: (Zero [4] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem) + // result: (MOVLstoreconst [makeValAndOff(0,0)] destptr mem) for { if auxIntToInt64(v.AuxInt) != 4 { break @@ -34094,12 +34082,12 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v.AddArg2(destptr, mem) return true } // match: (Zero [8] destptr mem) - // result: (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem) + // result: (MOVQstoreconst [makeValAndOff(0,0)] destptr mem) for { if auxIntToInt64(v.AuxInt) != 8 { break @@ -34107,12 +34095,12 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v.AddArg2(destptr, mem) return true } // match: (Zero [3] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,2)] destptr (MOVWstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,2)] destptr (MOVWstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 3 { break @@ -34120,15 +34108,15 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 2)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 2)) v0 := b.NewValue0(v.Pos, OpAMD64MOVWstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [5] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 5 { break @@ -34136,15 +34124,15 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [6] destptr mem) - // result: (MOVWstoreconst [makeValAndOff32(0,4)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVWstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 6 { break @@ -34152,15 +34140,15 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [7] destptr mem) - // result: (MOVLstoreconst [makeValAndOff32(0,3)] destptr (MOVLstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVLstoreconst [makeValAndOff(0,3)] destptr (MOVLstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 7 { break @@ -34168,16 +34156,16 @@ func rewriteValueAMD64_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpAMD64MOVLstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 3)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 3)) v0 := b.NewValue0(v.Pos, OpAMD64MOVLstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [s] destptr mem) // cond: s%8 != 0 && s > 8 && !config.useSSE - // result: (Zero [s-s%8] (OffPtr destptr [s%8]) (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (Zero [s-s%8] (OffPtr destptr [s%8]) (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) for { s := auxIntToInt64(v.AuxInt) destptr := v_0 @@ -34191,14 +34179,14 @@ func rewriteValueAMD64_OpZero(v *Value) bool { v0.AuxInt = int64ToAuxInt(s % 8) v0.AddArg(destptr) v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v1.AddArg2(destptr, mem) v.AddArg2(v0, v1) return true } // match: (Zero [16] destptr mem) // cond: !config.useSSE - // result: (MOVQstoreconst [makeValAndOff32(0,8)] destptr (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVQstoreconst [makeValAndOff(0,8)] destptr (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 16 { break @@ -34209,16 +34197,16 @@ func rewriteValueAMD64_OpZero(v *Value) bool { break } v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 8)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 8)) v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true } // match: (Zero [24] destptr mem) // cond: !config.useSSE - // result: (MOVQstoreconst [makeValAndOff32(0,16)] destptr (MOVQstoreconst [makeValAndOff32(0,8)] destptr (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem))) + // result: (MOVQstoreconst [makeValAndOff(0,16)] destptr (MOVQstoreconst [makeValAndOff(0,8)] destptr (MOVQstoreconst [makeValAndOff(0,0)] destptr mem))) for { if auxIntToInt64(v.AuxInt) != 24 { break @@ -34229,11 +34217,11 @@ func rewriteValueAMD64_OpZero(v *Value) bool { break } v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 16)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 16)) v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 8)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 8)) v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v1.AddArg2(destptr, mem) v0.AddArg2(destptr, v1) v.AddArg2(destptr, v0) @@ -34241,7 +34229,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool { } // match: (Zero [32] destptr mem) // cond: !config.useSSE - // result: (MOVQstoreconst [makeValAndOff32(0,24)] destptr (MOVQstoreconst [makeValAndOff32(0,16)] destptr (MOVQstoreconst [makeValAndOff32(0,8)] destptr (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)))) + // result: (MOVQstoreconst [makeValAndOff(0,24)] destptr (MOVQstoreconst [makeValAndOff(0,16)] destptr (MOVQstoreconst [makeValAndOff(0,8)] destptr (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)))) for { if auxIntToInt64(v.AuxInt) != 32 { break @@ -34252,13 +34240,13 @@ func rewriteValueAMD64_OpZero(v *Value) bool { break } v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 24)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 24)) v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 16)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 16)) v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 8)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 8)) v2 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v2.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v2.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v2.AddArg2(destptr, mem) v1.AddArg2(destptr, v2) v0.AddArg2(destptr, v1) @@ -34267,7 +34255,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool { } // match: (Zero [s] destptr mem) // cond: s > 8 && s < 16 && config.useSSE - // result: (MOVQstoreconst [makeValAndOff32(0,int32(s-8))] destptr (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (MOVQstoreconst [makeValAndOff(0,int32(s-8))] destptr (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) for { s := auxIntToInt64(v.AuxInt) destptr := v_0 @@ -34276,9 +34264,9 @@ func rewriteValueAMD64_OpZero(v *Value) bool { break } v.reset(OpAMD64MOVQstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, int32(s-8))) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, int32(s-8))) v0 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v0.AddArg2(destptr, mem) v.AddArg2(destptr, v0) return true @@ -34305,7 +34293,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool { } // match: (Zero [s] destptr mem) // cond: s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE - // result: (Zero [s-s%16] (OffPtr destptr [s%16]) (MOVQstoreconst [makeValAndOff32(0,0)] destptr mem)) + // result: (Zero [s-s%16] (OffPtr destptr [s%16]) (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) for { s := auxIntToInt64(v.AuxInt) destptr := v_0 @@ -34319,7 +34307,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool { v0.AuxInt = int64ToAuxInt(s % 16) v0.AddArg(destptr) v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 0)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) v1.AddArg2(destptr, mem) v.AddArg2(v0, v1) return true diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go index 65bfec0f68..1b8680c052 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go @@ -59,7 +59,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstload(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPBconstload {sym} [vo] ptr mem) // cond: vo.Val() == 0 - // result: (TESTB x:(MOVBload {sym} [vo.Off32()] ptr mem) x) + // result: (TESTB x:(MOVBload {sym} [vo.Off()] ptr mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -70,7 +70,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstload(v *Value) bool { } v.reset(OpAMD64TESTB) x := b.NewValue0(v.Pos, OpAMD64MOVBload, typ.UInt8) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg2(ptr, mem) v.AddArg2(x, x) @@ -78,7 +78,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstload(v *Value) bool { } // match: (CMPBconstload {sym} [vo] ptr mem) // cond: vo.Val() != 0 - // result: (CMPBconst (MOVBload {sym} [vo.Off32()] ptr mem) [vo.Val8()]) + // result: (CMPBconst (MOVBload {sym} [vo.Off()] ptr mem) [vo.Val8()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -90,7 +90,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstload(v *Value) bool { v.reset(OpAMD64CMPBconst) v.AuxInt = int8ToAuxInt(vo.Val8()) v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, typ.UInt8) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -106,7 +106,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPBconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTB x:(MOVBloadidx1 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTB x:(MOVBloadidx1 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -118,7 +118,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v *Value) bool { } v.reset(OpAMD64TESTB) x := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, typ.UInt8) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -126,7 +126,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v *Value) bool { } // match: (CMPBconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPBconst (MOVBloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val8()]) + // result: (CMPBconst (MOVBloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val8()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -139,7 +139,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBconstloadidx1(v *Value) bool { v.reset(OpAMD64CMPBconst) v.AuxInt = int8ToAuxInt(vo.Val8()) v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, typ.UInt8) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -202,7 +202,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPLconstload {sym} [vo] ptr mem) // cond: vo.Val() == 0 - // result: (TESTL x:(MOVLload {sym} [vo.Off32()] ptr mem) x) + // result: (TESTL x:(MOVLload {sym} [vo.Off()] ptr mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -213,7 +213,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { } v.reset(OpAMD64TESTL) x := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg2(ptr, mem) v.AddArg2(x, x) @@ -221,7 +221,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { } // match: (CMPLconstload {sym} [vo] ptr mem) // cond: vo.Val() != 0 - // result: (CMPLconst (MOVLload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) + // result: (CMPLconst (MOVLload {sym} [vo.Off()] ptr mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -231,9 +231,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstload(v *Value) bool { break } v.reset(OpAMD64CMPLconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -249,7 +249,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPLconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTL x:(MOVLloadidx1 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTL x:(MOVLloadidx1 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -261,7 +261,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v *Value) bool { } v.reset(OpAMD64TESTL) x := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -269,7 +269,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v *Value) bool { } // match: (CMPLconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPLconst (MOVLloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) + // result: (CMPLconst (MOVLloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -280,9 +280,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx1(v *Value) bool { break } v.reset(OpAMD64CMPLconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -298,7 +298,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPLconstloadidx4 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTL x:(MOVLloadidx4 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTL x:(MOVLloadidx4 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -310,7 +310,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v *Value) bool { } v.reset(OpAMD64TESTL) x := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, typ.UInt32) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -318,7 +318,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v *Value) bool { } // match: (CMPLconstloadidx4 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPLconst (MOVLloadidx4 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) + // result: (CMPLconst (MOVLloadidx4 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -329,9 +329,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPLconstloadidx4(v *Value) bool { break } v.reset(OpAMD64CMPLconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, typ.UInt32) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -419,7 +419,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPQconstload {sym} [vo] ptr mem) // cond: vo.Val() == 0 - // result: (TESTQ x:(MOVQload {sym} [vo.Off32()] ptr mem) x) + // result: (TESTQ x:(MOVQload {sym} [vo.Off()] ptr mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -430,7 +430,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { } v.reset(OpAMD64TESTQ) x := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg2(ptr, mem) v.AddArg2(x, x) @@ -438,7 +438,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { } // match: (CMPQconstload {sym} [vo] ptr mem) // cond: vo.Val() != 0 - // result: (CMPQconst (MOVQload {sym} [vo.Off32()] ptr mem) [vo.Val32()]) + // result: (CMPQconst (MOVQload {sym} [vo.Off()] ptr mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -448,9 +448,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstload(v *Value) bool { break } v.reset(OpAMD64CMPQconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -466,7 +466,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPQconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTQ x:(MOVQloadidx1 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTQ x:(MOVQloadidx1 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -478,7 +478,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v *Value) bool { } v.reset(OpAMD64TESTQ) x := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -486,7 +486,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v *Value) bool { } // match: (CMPQconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPQconst (MOVQloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) + // result: (CMPQconst (MOVQloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -497,9 +497,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx1(v *Value) bool { break } v.reset(OpAMD64CMPQconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -515,7 +515,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPQconstloadidx8 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTQ x:(MOVQloadidx8 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTQ x:(MOVQloadidx8 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -527,7 +527,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v *Value) bool { } v.reset(OpAMD64TESTQ) x := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, typ.UInt64) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -535,7 +535,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v *Value) bool { } // match: (CMPQconstloadidx8 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPQconst (MOVQloadidx8 {sym} [vo.Off32()] ptr idx mem) [vo.Val32()]) + // result: (CMPQconst (MOVQloadidx8 {sym} [vo.Off()] ptr idx mem) [vo.Val()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -546,9 +546,9 @@ func rewriteValueAMD64splitload_OpAMD64CMPQconstloadidx8(v *Value) bool { break } v.reset(OpAMD64CMPQconst) - v.AuxInt = int32ToAuxInt(vo.Val32()) + v.AuxInt = int32ToAuxInt(vo.Val()) v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, typ.UInt64) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -636,7 +636,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPWconstload {sym} [vo] ptr mem) // cond: vo.Val() == 0 - // result: (TESTW x:(MOVWload {sym} [vo.Off32()] ptr mem) x) + // result: (TESTW x:(MOVWload {sym} [vo.Off()] ptr mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -647,7 +647,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { } v.reset(OpAMD64TESTW) x := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg2(ptr, mem) v.AddArg2(x, x) @@ -655,7 +655,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { } // match: (CMPWconstload {sym} [vo] ptr mem) // cond: vo.Val() != 0 - // result: (CMPWconst (MOVWload {sym} [vo.Off32()] ptr mem) [vo.Val16()]) + // result: (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -667,7 +667,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstload(v *Value) bool { v.reset(OpAMD64CMPWconst) v.AuxInt = int16ToAuxInt(vo.Val16()) v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg2(ptr, mem) v.AddArg(v0) @@ -683,7 +683,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPWconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTW x:(MOVWloadidx1 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTW x:(MOVWloadidx1 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -695,7 +695,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v *Value) bool { } v.reset(OpAMD64TESTW) x := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -703,7 +703,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v *Value) bool { } // match: (CMPWconstloadidx1 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPWconst (MOVWloadidx1 {sym} [vo.Off32()] ptr idx mem) [vo.Val16()]) + // result: (CMPWconst (MOVWloadidx1 {sym} [vo.Off()] ptr idx mem) [vo.Val16()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -716,7 +716,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx1(v *Value) bool { v.reset(OpAMD64CMPWconst) v.AuxInt = int16ToAuxInt(vo.Val16()) v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) @@ -732,7 +732,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v *Value) bool { typ := &b.Func.Config.Types // match: (CMPWconstloadidx2 {sym} [vo] ptr idx mem) // cond: vo.Val() == 0 - // result: (TESTW x:(MOVWloadidx2 {sym} [vo.Off32()] ptr idx mem) x) + // result: (TESTW x:(MOVWloadidx2 {sym} [vo.Off()] ptr idx mem) x) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -744,7 +744,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v *Value) bool { } v.reset(OpAMD64TESTW) x := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, typ.UInt16) - x.AuxInt = int32ToAuxInt(vo.Off32()) + x.AuxInt = int32ToAuxInt(vo.Off()) x.Aux = symToAux(sym) x.AddArg3(ptr, idx, mem) v.AddArg2(x, x) @@ -752,7 +752,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v *Value) bool { } // match: (CMPWconstloadidx2 {sym} [vo] ptr idx mem) // cond: vo.Val() != 0 - // result: (CMPWconst (MOVWloadidx2 {sym} [vo.Off32()] ptr idx mem) [vo.Val16()]) + // result: (CMPWconst (MOVWloadidx2 {sym} [vo.Off()] ptr idx mem) [vo.Val16()]) for { vo := auxIntToValAndOff(v.AuxInt) sym := auxToSym(v.Aux) @@ -765,7 +765,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWconstloadidx2(v *Value) bool { v.reset(OpAMD64CMPWconst) v.AuxInt = int16ToAuxInt(vo.Val16()) v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, typ.UInt16) - v0.AuxInt = int32ToAuxInt(vo.Off32()) + v0.AuxInt = int32ToAuxInt(vo.Off()) v0.Aux = symToAux(sym) v0.AddArg3(ptr, idx, mem) v.AddArg(v0) diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index 85260dace8..f02362a0d4 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -3433,7 +3433,7 @@ func rewriteValueS390X_OpMove(v *Value) bool { } // match: (Move [s] dst src mem) // cond: s > 0 && s <= 256 && logLargeCopy(v, s) - // result: (MVC [makeValAndOff32(int32(s), 0)] dst src mem) + // result: (MVC [makeValAndOff(int32(s), 0)] dst src mem) for { s := auxIntToInt64(v.AuxInt) dst := v_0 @@ -3443,13 +3443,13 @@ func rewriteValueS390X_OpMove(v *Value) bool { break } v.reset(OpS390XMVC) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(s), 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(s), 0)) v.AddArg3(dst, src, mem) return true } // match: (Move [s] dst src mem) // cond: s > 256 && s <= 512 && logLargeCopy(v, s) - // result: (MVC [makeValAndOff32(int32(s)-256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem)) + // result: (MVC [makeValAndOff(int32(s)-256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)) for { s := auxIntToInt64(v.AuxInt) dst := v_0 @@ -3459,16 +3459,16 @@ func rewriteValueS390X_OpMove(v *Value) bool { break } v.reset(OpS390XMVC) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(s)-256, 256)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(s)-256, 256)) v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 0)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 0)) v0.AddArg3(dst, src, mem) v.AddArg3(dst, src, v0) return true } // match: (Move [s] dst src mem) // cond: s > 512 && s <= 768 && logLargeCopy(v, s) - // result: (MVC [makeValAndOff32(int32(s)-512, 512)] dst src (MVC [makeValAndOff32(256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem))) + // result: (MVC [makeValAndOff(int32(s)-512, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem))) for { s := auxIntToInt64(v.AuxInt) dst := v_0 @@ -3478,11 +3478,11 @@ func rewriteValueS390X_OpMove(v *Value) bool { break } v.reset(OpS390XMVC) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(s)-512, 512)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(s)-512, 512)) v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 256)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 256)) v1 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 0)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 0)) v1.AddArg3(dst, src, mem) v0.AddArg3(dst, src, v1) v.AddArg3(dst, src, v0) @@ -3490,7 +3490,7 @@ func rewriteValueS390X_OpMove(v *Value) bool { } // match: (Move [s] dst src mem) // cond: s > 768 && s <= 1024 && logLargeCopy(v, s) - // result: (MVC [makeValAndOff32(int32(s)-768, 768)] dst src (MVC [makeValAndOff32(256, 512)] dst src (MVC [makeValAndOff32(256, 256)] dst src (MVC [makeValAndOff32(256, 0)] dst src mem)))) + // result: (MVC [makeValAndOff(int32(s)-768, 768)] dst src (MVC [makeValAndOff(256, 512)] dst src (MVC [makeValAndOff(256, 256)] dst src (MVC [makeValAndOff(256, 0)] dst src mem)))) for { s := auxIntToInt64(v.AuxInt) dst := v_0 @@ -3500,13 +3500,13 @@ func rewriteValueS390X_OpMove(v *Value) bool { break } v.reset(OpS390XMVC) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(s)-768, 768)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(s)-768, 768)) v0 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v0.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 512)) + v0.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 512)) v1 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 256)) + v1.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 256)) v2 := b.NewValue0(v.Pos, OpS390XMVC, types.TypeMem) - v2.AuxInt = valAndOffToAuxInt(makeValAndOff32(256, 0)) + v2.AuxInt = valAndOffToAuxInt(makeValAndOff(256, 0)) v2.AddArg3(dst, src, mem) v1.AddArg3(dst, src, v2) v0.AddArg3(dst, src, v1) @@ -8617,7 +8617,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { } // match: (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) // cond: is20Bit(int64(off)) && ptr.Op != OpSB - // result: (MOVBstoreconst [makeValAndOff32(int32(int8(c)),off)] {sym} ptr mem) + // result: (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -8631,7 +8631,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } v.reset(OpS390XMOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int8(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int8(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -8939,7 +8939,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) - // cond: is20Bit(sc.Off()+int64(off)) + // cond: is20Bit(sc.Off64()+int64(off)) // result: (MOVBstoreconst [sc.addOffset32(off)] {s} ptr mem) for { sc := auxIntToValAndOff(v.AuxInt) @@ -8950,7 +8950,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value) bool { off := auxIntToInt32(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(is20Bit(sc.Off() + int64(off))) { + if !(is20Bit(sc.Off64() + int64(off))) { break } v.reset(OpS390XMOVBstoreconst) @@ -8983,7 +8983,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value) bool { } // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem)) // cond: p.Op != OpSB && x.Uses == 1 && a.Off() + 1 == c.Off() && clobber(x) - // result: (MOVHstoreconst [makeValAndOff32(c.Val32()&0xff | a.Val32()<<8, a.Off32())] {s} p mem) + // result: (MOVHstoreconst [makeValAndOff(c.Val()&0xff | a.Val()<<8, a.Off())] {s} p mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -9001,7 +9001,7 @@ func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value) bool { break } v.reset(OpS390XMOVHstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(c.Val32()&0xff|a.Val32()<<8, a.Off32())) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(c.Val()&0xff|a.Val()<<8, a.Off())) v.Aux = symToAux(s) v.AddArg2(p, mem) return true @@ -9213,7 +9213,7 @@ func rewriteValueS390X_OpS390XMOVDstore(v *Value) bool { } // match: (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) // cond: is16Bit(c) && isU12Bit(int64(off)) && ptr.Op != OpSB - // result: (MOVDstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + // result: (MOVDstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -9227,7 +9227,7 @@ func rewriteValueS390X_OpS390XMOVDstore(v *Value) bool { break } v.reset(OpS390XMOVDstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -9343,7 +9343,7 @@ func rewriteValueS390X_OpS390XMOVDstoreconst(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MOVDstoreconst [sc] {s} (ADDconst [off] ptr) mem) - // cond: isU12Bit(sc.Off()+int64(off)) + // cond: isU12Bit(sc.Off64()+int64(off)) // result: (MOVDstoreconst [sc.addOffset32(off)] {s} ptr mem) for { sc := auxIntToValAndOff(v.AuxInt) @@ -9354,7 +9354,7 @@ func rewriteValueS390X_OpS390XMOVDstoreconst(v *Value) bool { off := auxIntToInt32(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(isU12Bit(sc.Off() + int64(off))) { + if !(isU12Bit(sc.Off64() + int64(off))) { break } v.reset(OpS390XMOVDstoreconst) @@ -10079,7 +10079,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { } // match: (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) // cond: isU12Bit(int64(off)) && ptr.Op != OpSB - // result: (MOVHstoreconst [makeValAndOff32(int32(int16(c)),off)] {sym} ptr mem) + // result: (MOVHstoreconst [makeValAndOff(int32(int16(c)),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -10093,7 +10093,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { break } v.reset(OpS390XMOVHstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(int16(c)), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(int16(c)), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -10244,7 +10244,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) - // cond: isU12Bit(sc.Off()+int64(off)) + // cond: isU12Bit(sc.Off64()+int64(off)) // result: (MOVHstoreconst [sc.addOffset32(off)] {s} ptr mem) for { sc := auxIntToValAndOff(v.AuxInt) @@ -10255,7 +10255,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst(v *Value) bool { off := auxIntToInt32(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(isU12Bit(sc.Off() + int64(off))) { + if !(isU12Bit(sc.Off64() + int64(off))) { break } v.reset(OpS390XMOVHstoreconst) @@ -10288,7 +10288,7 @@ func rewriteValueS390X_OpS390XMOVHstoreconst(v *Value) bool { } // match: (MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem)) // cond: p.Op != OpSB && x.Uses == 1 && a.Off() + 2 == c.Off() && clobber(x) - // result: (MOVWstore [a.Off32()] {s} p (MOVDconst [int64(c.Val32()&0xffff | a.Val32()<<16)]) mem) + // result: (MOVWstore [a.Off()] {s} p (MOVDconst [int64(c.Val()&0xffff | a.Val()<<16)]) mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -10306,10 +10306,10 @@ func rewriteValueS390X_OpS390XMOVHstoreconst(v *Value) bool { break } v.reset(OpS390XMOVWstore) - v.AuxInt = int32ToAuxInt(a.Off32()) + v.AuxInt = int32ToAuxInt(a.Off()) v.Aux = symToAux(s) v0 := b.NewValue0(x.Pos, OpS390XMOVDconst, typ.UInt64) - v0.AuxInt = int64ToAuxInt(int64(c.Val32()&0xffff | a.Val32()<<16)) + v0.AuxInt = int64ToAuxInt(int64(c.Val()&0xffff | a.Val()<<16)) v.AddArg3(p, v0, mem) return true } @@ -10917,7 +10917,7 @@ func rewriteValueS390X_OpS390XMOVWstore(v *Value) bool { } // match: (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) // cond: is16Bit(c) && isU12Bit(int64(off)) && ptr.Op != OpSB - // result: (MOVWstoreconst [makeValAndOff32(int32(c),off)] {sym} ptr mem) + // result: (MOVWstoreconst [makeValAndOff(int32(c),off)] {sym} ptr mem) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -10931,7 +10931,7 @@ func rewriteValueS390X_OpS390XMOVWstore(v *Value) bool { break } v.reset(OpS390XMOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(c), off)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) v.Aux = symToAux(sym) v.AddArg2(ptr, mem) return true @@ -11105,7 +11105,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) - // cond: isU12Bit(sc.Off()+int64(off)) + // cond: isU12Bit(sc.Off64()+int64(off)) // result: (MOVWstoreconst [sc.addOffset32(off)] {s} ptr mem) for { sc := auxIntToValAndOff(v.AuxInt) @@ -11116,7 +11116,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst(v *Value) bool { off := auxIntToInt32(v_0.AuxInt) ptr := v_0.Args[0] mem := v_1 - if !(isU12Bit(sc.Off() + int64(off))) { + if !(isU12Bit(sc.Off64() + int64(off))) { break } v.reset(OpS390XMOVWstoreconst) @@ -11149,7 +11149,7 @@ func rewriteValueS390X_OpS390XMOVWstoreconst(v *Value) bool { } // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem)) // cond: p.Op != OpSB && x.Uses == 1 && a.Off() + 4 == c.Off() && clobber(x) - // result: (MOVDstore [a.Off32()] {s} p (MOVDconst [c.Val()&0xffffffff | a.Val()<<32]) mem) + // result: (MOVDstore [a.Off()] {s} p (MOVDconst [c.Val64()&0xffffffff | a.Val64()<<32]) mem) for { c := auxIntToValAndOff(v.AuxInt) s := auxToSym(v.Aux) @@ -11167,10 +11167,10 @@ func rewriteValueS390X_OpS390XMOVWstoreconst(v *Value) bool { break } v.reset(OpS390XMOVDstore) - v.AuxInt = int32ToAuxInt(a.Off32()) + v.AuxInt = int32ToAuxInt(a.Off()) v.Aux = symToAux(s) v0 := b.NewValue0(x.Pos, OpS390XMOVDconst, typ.UInt64) - v0.AuxInt = int64ToAuxInt(c.Val()&0xffffffff | a.Val()<<32) + v0.AuxInt = int64ToAuxInt(c.Val64()&0xffffffff | a.Val64()<<32) v.AddArg3(p, v0, mem) return true } @@ -15918,7 +15918,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { return true } // match: (Zero [3] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,2)] destptr (MOVHstoreconst [0] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,2)] destptr (MOVHstoreconst [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 3 { break @@ -15926,7 +15926,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpS390XMOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 2)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 2)) v0 := b.NewValue0(v.Pos, OpS390XMOVHstoreconst, types.TypeMem) v0.AuxInt = valAndOffToAuxInt(0) v0.AddArg2(destptr, mem) @@ -15934,7 +15934,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { return true } // match: (Zero [5] destptr mem) - // result: (MOVBstoreconst [makeValAndOff32(0,4)] destptr (MOVWstoreconst [0] destptr mem)) + // result: (MOVBstoreconst [makeValAndOff(0,4)] destptr (MOVWstoreconst [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 5 { break @@ -15942,7 +15942,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpS390XMOVBstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem) v0.AuxInt = valAndOffToAuxInt(0) v0.AddArg2(destptr, mem) @@ -15950,7 +15950,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { return true } // match: (Zero [6] destptr mem) - // result: (MOVHstoreconst [makeValAndOff32(0,4)] destptr (MOVWstoreconst [0] destptr mem)) + // result: (MOVHstoreconst [makeValAndOff(0,4)] destptr (MOVWstoreconst [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 6 { break @@ -15958,7 +15958,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpS390XMOVHstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 4)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 4)) v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem) v0.AuxInt = valAndOffToAuxInt(0) v0.AddArg2(destptr, mem) @@ -15966,7 +15966,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { return true } // match: (Zero [7] destptr mem) - // result: (MOVWstoreconst [makeValAndOff32(0,3)] destptr (MOVWstoreconst [0] destptr mem)) + // result: (MOVWstoreconst [makeValAndOff(0,3)] destptr (MOVWstoreconst [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 7 { break @@ -15974,7 +15974,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { destptr := v_0 mem := v_1 v.reset(OpS390XMOVWstoreconst) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(0, 3)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 3)) v0 := b.NewValue0(v.Pos, OpS390XMOVWstoreconst, types.TypeMem) v0.AuxInt = valAndOffToAuxInt(0) v0.AddArg2(destptr, mem) @@ -15983,7 +15983,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { } // match: (Zero [s] destptr mem) // cond: s > 0 && s <= 1024 - // result: (CLEAR [makeValAndOff32(int32(s), 0)] destptr mem) + // result: (CLEAR [makeValAndOff(int32(s), 0)] destptr mem) for { s := auxIntToInt64(v.AuxInt) destptr := v_0 @@ -15992,7 +15992,7 @@ func rewriteValueS390X_OpZero(v *Value) bool { break } v.reset(OpS390XCLEAR) - v.AuxInt = valAndOffToAuxInt(makeValAndOff32(int32(s), 0)) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(s), 0)) v.AddArg2(destptr, mem) return true } diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index 62982f4c6d..e8c92c0f00 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -427,9 +427,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.From, v, sc.Off()) + ssagen.AddAux2(&p.From, v, sc.Off64()) p.To.Type = obj.TYPE_CONST - p.To.Offset = sc.Val() + p.To.Offset = sc.Val64() case ssa.Op386MOVLconst: x := v.Reg() @@ -544,7 +544,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } else { p = s.Prog(x86.ADECL) } - off := sc.Off() + off := sc.Off64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() ssagen.AddAux2(&p.To, v, off) @@ -553,8 +553,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { fallthrough case ssa.Op386ANDLconstmodify, ssa.Op386ORLconstmodify, ssa.Op386XORLconstmodify: sc := v.AuxValAndOff() - off := sc.Off() - val := sc.Val() + off := sc.Off64() + val := sc.Val64() p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST p.From.Offset = val @@ -591,10 +591,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.Op386ADDLconstmodifyidx4: sc := v.AuxValAndOff() val := sc.Val() @@ -605,7 +605,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } else { p = s.Prog(x86.ADECL) } - off := sc.Off() + off := sc.Off64() p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() p.To.Scale = 4 @@ -619,7 +619,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() - p.From.Offset = sc.Val() + p.From.Offset = sc.Val64() r := v.Args[0].Reg() i := v.Args[1].Reg() switch v.Op { @@ -637,7 +637,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_MEM p.To.Reg = r p.To.Index = i - ssagen.AddAux2(&p.To, v, sc.Off()) + ssagen.AddAux2(&p.To, v, sc.Off64()) case ssa.Op386MOVWLSX, ssa.Op386MOVBLSX, ssa.Op386MOVWLZX, ssa.Op386MOVBLZX, ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD, ssa.Op386CVTTSS2SL, ssa.Op386CVTTSD2SL, -- GitLab From 762ef81a5670da99a4b060fd3afe4134c9e82017 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 8 Mar 2021 18:44:27 -0800 Subject: [PATCH 0245/1298] cmd/link/internal/ld: deflake TestWindowsIssue36495 Over a dozen of the ld tests were missing closes. That was less obvious before CL 299670 started using T.TempDir instead, which fails a test when the tempdir can't be cleaned up (as it can't on Windows when things are still open), insteading of leaving tempdirs around on disk after the test. Most of the missing closes were fixed in CL 299670, but the builders helpfully pointed out that I missed at least this one. Change-Id: I35f695bb7cbfba31e16311c5af965c148f9d7943 Reviewed-on: https://go-review.googlesource.com/c/go/+/299929 Run-TryBot: Brad Fitzpatrick TryBot-Result: Go Bot Reviewed-by: Dan Scales Reviewed-by: Alex Brainman Trust: Dan Scales Trust: Alex Brainman --- src/cmd/link/internal/ld/dwarf_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index d16cff911b..f5f2258451 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -1297,6 +1297,7 @@ func main() { fmt.Println("Hello World") }` f := gobuild(t, dir, prog, NoOpt) + defer f.Close() exe, err := pe.Open(f.path) if err != nil { t.Fatalf("error opening pe file: %v", err) -- GitLab From 034fffdb490ade3cbccd79eacdb9370850ef51d1 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 9 Mar 2021 10:38:30 +0100 Subject: [PATCH 0246/1298] net: use io.Discard in TestSendfileOnWriteTimeoutExceeded Replace ioutil.Discard which is deprecated as of Go 1.16. This was already done in CL 263142 but accidentially re-introduced in CL 285914. Change-Id: Ife0944d416294b1ba7c8f6b602aa68a3b9213c50 Reviewed-on: https://go-review.googlesource.com/c/go/+/299989 Trust: Tobias Klauser Run-TryBot: Tobias Klauser Reviewed-by: Emmanuel Odeke TryBot-Result: Go Bot --- src/net/sendfile_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index db72daa328..54e51fa0ab 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -14,7 +14,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "runtime" "sync" @@ -367,7 +366,7 @@ func TestSendfileOnWriteTimeoutExceeded(t *testing.T) { } defer conn.Close() - n, err := io.Copy(ioutil.Discard, conn) + n, err := io.Copy(io.Discard, conn) if err != nil { t.Fatalf("expected nil error, but got %v", err) } -- GitLab From a70eb2c9f2e3d52116b90a21ce10718356197ee5 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 3 Mar 2021 13:33:27 -0800 Subject: [PATCH 0247/1298] cmd/compile: get instantiated generic types working with interfaces Get instantiatiated generic types working with interfaces, including typechecking assignments to interfaces and instantiating all the methods properly. To get it all working, this change includes: - Add support for substituting in interfaces in subster.typ() - Fill in the info for the methods for all instantiated generic types, so those methods will be available for later typechecking (by the old typechecker) when assigning an instantiated generic type to an interface. We also want those methods available so we have the list when we want to instantiate all methods of an instantiated type. We have both for instantiated types encountered during the initial noder phase, and for instantiated types created during stenciling of a function/method. - When we first create a fully-instantiated generic type (whether during initial noder2 pass or while instantiating a method/function), add it to a list so that all of its methods will also be instantiated. This is needed so that an instantiated type can be assigned to an interface. - Properly substitute type names in the names of instantiated methods. - New accessor methods for types.Type.RParam. - To deal with generic types which are empty structs (or just don't use their type params anywhere), we want to set HasTParam if a named type has any type params that are not fully instantiated, even if the type param is not used in the type. - In subst.typ() and elsewhere, always set sym.Def for a new forwarding type we are creating, so we always create a single unique type for each generic type instantiation. This handles recursion within a type, and also recursive relationships across many types or methods. We remove the seen[] hashtable, which was serving the same purpose, but for subst.typ() only. We now handle all kinds of recursive types. - We don't seem to need to force types.CheckSize() on created/substituted generic types anymore, so commented out for now. - Add an RParams accessor to types2.Signature, and also a new exported types2.AsSignature() function. Change-Id: If6c5dd98427b20bfe9de3379cc16f83df9c9b632 Reviewed-on: https://go-review.googlesource.com/c/go/+/298449 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/decl.go | 10 +- src/cmd/compile/internal/noder/irgen.go | 3 + src/cmd/compile/internal/noder/stencil.go | 371 +++++++++++++++------ src/cmd/compile/internal/noder/types.go | 125 +++++-- src/cmd/compile/internal/noder/validate.go | 4 +- src/cmd/compile/internal/types/type.go | 38 ++- src/cmd/compile/internal/types2/type.go | 8 +- test/typeparam/cons.go | 101 ++++++ test/typeparam/ordered.go | 95 ++++++ test/typeparam/settable.go | 4 +- 10 files changed, 620 insertions(+), 139 deletions(-) create mode 100644 test/typeparam/cons.go create mode 100644 test/typeparam/ordered.go diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index a1596be4a4..f0cdcbfc2e 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -134,14 +134,14 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { } // We need to use g.typeExpr(decl.Type) here to ensure that for - // chained, defined-type declarations like + // chained, defined-type declarations like: // // type T U // // //go:notinheap // type U struct { … } // - // that we mark both T and U as NotInHeap. If we instead used just + // we mark both T and U as NotInHeap. If we instead used just // g.typ(otyp.Underlying()), then we'd instead set T's underlying // type directly to the struct type (which is not marked NotInHeap) // and fail to mark T as NotInHeap. @@ -154,6 +154,12 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { // [mdempsky: Subtleties like these are why I always vehemently // object to new type pragmas.] ntyp.SetUnderlying(g.typeExpr(decl.Type)) + if len(decl.TParamList) > 0 { + // Set HasTParam if there are any tparams, even if no tparams are + // used in the type itself (e.g., if it is an empty struct, or no + // fields in the struct use the tparam). + ntyp.SetHasTParam(true) + } types.ResumeCheckSize() if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 { diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index da5b024b1a..06b234c31d 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -100,6 +100,9 @@ type irgen struct { objs map[types2.Object]*ir.Name typs map[types2.Type]*types.Type marker dwarfgen.ScopeMarker + + // Fully-instantiated generic types whose methods should be instantiated + instTypeList []*types.Type } func (g *irgen) generate(noders []*noder) { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index fb1bbfedc8..8001d6d398 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -18,10 +18,25 @@ import ( "strings" ) -// stencil scans functions for instantiated generic function calls and -// creates the required stencils for simple generic functions. +// For catching problems as we add more features +// TODO(danscales): remove assertions or replace with base.FatalfAt() +func assert(p bool) { + if !p { + panic("assertion failed") + } +} + +// stencil scans functions for instantiated generic function calls and creates the +// required instantiations for simple generic functions. It also creates +// instantiated methods for all fully-instantiated generic types that have been +// encountered already or new ones that are encountered during the stenciling +// process. func (g *irgen) stencil() { g.target.Stencils = make(map[*types.Sym]*ir.Func) + + // Instantiate the methods of instantiated generic types that we have seen so far. + g.instantiateMethods() + // Don't use range(g.target.Decls) - we also want to process any new instantiated // functions that are created during this loop, in order to handle generic // functions calling other generic functions. @@ -65,7 +80,7 @@ func (g *irgen) stencil() { // instantiation. call := n.(*ir.CallExpr) inst := call.X.(*ir.InstExpr) - st := g.getInstantiation(inst) + st := g.getInstantiationForNode(inst) // Replace the OFUNCINST with a direct reference to the // new stenciled function call.X = st.Nname @@ -94,7 +109,7 @@ func (g *irgen) stencil() { var edit func(ir.Node) ir.Node edit = func(x ir.Node) ir.Node { if x.Op() == ir.OFUNCINST { - st := g.getInstantiation(x.(*ir.InstExpr)) + st := g.getInstantiationForNode(x.(*ir.InstExpr)) return st.Nname } ir.EditChildren(x, edit) @@ -105,27 +120,65 @@ func (g *irgen) stencil() { if base.Flag.W > 1 && modified { ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl) } + // We may have seen new fully-instantiated generic types while + // instantiating any needed functions/methods in the above + // function. If so, instantiate all the methods of those types + // (which will then lead to more function/methods to scan in the loop). + g.instantiateMethods() } } -// getInstantiation gets the instantiated function corresponding to inst. If the -// instantiated function is not already cached, then it calls genericStub to -// create the new instantiation. -func (g *irgen) getInstantiation(inst *ir.InstExpr) *ir.Func { - var sym *types.Sym +// instantiateMethods instantiates all the methods of all fully-instantiated +// generic types that have been added to g.instTypeList. +func (g *irgen) instantiateMethods() { + for i := 0; i < len(g.instTypeList); i++ { + typ := g.instTypeList[i] + // Get the base generic type by looking up the symbol of the + // generic (uninstantiated) name. + baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym())) + baseType := baseSym.Def.(*ir.Name).Type() + for j, m := range typ.Methods().Slice() { + name := m.Nname.(*ir.Name) + targs := make([]ir.Node, len(typ.RParams())) + for k, targ := range typ.RParams() { + targs[k] = ir.TypeNode(targ) + } + baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) + name.Func = g.getInstantiation(baseNname, targs, true) + } + } + g.instTypeList = nil + +} + +// genericSym returns the name of the base generic type for the type named by +// sym. It simply returns the name obtained by removing everything after the +// first bracket ("["). +func genericTypeName(sym *types.Sym) string { + return sym.Name[0:strings.Index(sym.Name, "[")] +} + +// getInstantiationForNode returns the function/method instantiation for a +// InstExpr node inst. +func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func { if meth, ok := inst.X.(*ir.SelectorExpr); ok { - // Write the name of the generic method, including receiver type - sym = makeInstName(meth.Selection.Nname.Sym(), inst.Targs) + return g.getInstantiation(meth.Selection.Nname.(*ir.Name), inst.Targs, true) } else { - sym = makeInstName(inst.X.(*ir.Name).Name().Sym(), inst.Targs) + return g.getInstantiation(inst.X.(*ir.Name), inst.Targs, false) } - //fmt.Printf("Found generic func call in %v to %v\n", f, s) +} + +// getInstantiation gets the instantiantion of the function or method nameNode +// with the type arguments targs. If the instantiated function is not already +// cached, then it calls genericSubst to create the new instantiation. +func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool) *ir.Func { + sym := makeInstName(nameNode.Sym(), targs, isMeth) st := g.target.Stencils[sym] if st == nil { // If instantiation doesn't exist yet, create it and add // to the list of decls. - st = g.genericSubst(sym, inst) + st = g.genericSubst(sym, nameNode, targs, isMeth) g.target.Stencils[sym] = st g.target.Decls = append(g.target.Decls, st) if base.Flag.W > 1 { @@ -135,11 +188,29 @@ func (g *irgen) getInstantiation(inst *ir.InstExpr) *ir.Func { return st } -// makeInstName makes the unique name for a stenciled generic function, based on -// the name of the function and the targs. -func makeInstName(fnsym *types.Sym, targs []ir.Node) *types.Sym { - b := bytes.NewBufferString("#") - b.WriteString(fnsym.Name) +// makeInstName makes the unique name for a stenciled generic function or method, +// based on the name of the function fy=nsym and the targs. It replaces any +// existing bracket type list in the name. makeInstName asserts that fnsym has +// brackets in its name if and only if hasBrackets is true. +// TODO(danscales): remove the assertions and the hasBrackets argument later. +// +// Names of declared generic functions have no brackets originally, so hasBrackets +// should be false. Names of generic methods already have brackets, since the new +// type parameter is specified in the generic type of the receiver (e.g. func +// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. +// +// The standard naming is something like: 'genFn[int,bool]' for functions and +// '(*genType[int,bool]).methodName' for methods +func makeInstName(fnsym *types.Sym, targs []ir.Node, hasBrackets bool) *types.Sym { + b := bytes.NewBufferString("") + name := fnsym.Name + i := strings.Index(name, "[") + assert(hasBrackets == (i >= 0)) + if i >= 0 { + b.WriteString(name[0:i]) + } else { + b.WriteString(name) + } b.WriteString("[") for i, targ := range targs { if i > 0 { @@ -148,60 +219,64 @@ func makeInstName(fnsym *types.Sym, targs []ir.Node) *types.Sym { b.WriteString(targ.Type().String()) } b.WriteString("]") + if i >= 0 { + i2 := strings.Index(name[i:], "]") + assert(i2 >= 0) + b.WriteString(name[i+i2+1:]) + } return typecheck.Lookup(b.String()) } // Struct containing info needed for doing the substitution as we create the // instantiation of a generic function with specified type arguments. type subster struct { - g *irgen - newf *ir.Func // Func node for the new stenciled function - tparams []*types.Field - targs []ir.Node + g *irgen + isMethod bool // If a method is being instantiated + newf *ir.Func // Func node for the new stenciled function + tparams []*types.Field + targs []ir.Node // The substitution map from name nodes in the generic function to the // name nodes in the new stenciled function. vars map[*ir.Name]*ir.Name - seen map[*types.Type]*types.Type } -// genericSubst returns a new function with the specified name. The function is an -// instantiation of a generic function or method with type params, as specified by -// inst. For a method with a generic receiver, it returns an instantiated function -// type where the receiver becomes the first parameter. Otherwise the instantiated -// method would still need to be transformed by later compiler phases. -func (g *irgen) genericSubst(name *types.Sym, inst *ir.InstExpr) *ir.Func { - var nameNode *ir.Name +// genericSubst returns a new function with name newsym. The function is an +// instantiation of a generic function or method specified by namedNode with type +// args targs. For a method with a generic receiver, it returns an instantiated +// function type where the receiver becomes the first parameter. Otherwise the +// instantiated method would still need to be transformed by later compiler +// phases. +func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.Node, isMethod bool) *ir.Func { var tparams []*types.Field - if selExpr, ok := inst.X.(*ir.SelectorExpr); ok { + if isMethod { // Get the type params from the method receiver (after skipping // over any pointer) - nameNode = ir.AsNode(selExpr.Selection.Nname).(*ir.Name) - recvType := selExpr.Type().Recv().Type - if recvType.IsPtr() { - recvType = recvType.Elem() - } - tparams = make([]*types.Field, len(recvType.RParams)) - for i, rparam := range recvType.RParams { + recvType := nameNode.Type().Recv().Type + recvType = deref(recvType) + tparams = make([]*types.Field, len(recvType.RParams())) + for i, rparam := range recvType.RParams() { tparams[i] = types.NewField(src.NoXPos, nil, rparam) } } else { - nameNode = inst.X.(*ir.Name) tparams = nameNode.Type().TParams().Fields().Slice() } gf := nameNode.Func - newf := ir.NewFunc(inst.Pos()) - newf.Nname = ir.NewNameAt(inst.Pos(), name) + // Pos of the instantiated function is same as the generic function + newf := ir.NewFunc(gf.Pos()) + newf.Nname = ir.NewNameAt(gf.Pos(), newsym) newf.Nname.Func = newf newf.Nname.Defn = newf - name.Def = newf.Nname + newsym.Def = newf.Nname + + assert(len(tparams) == len(targs)) subst := &subster{ - g: g, - newf: newf, - tparams: tparams, - targs: inst.Targs, - vars: make(map[*ir.Name]*ir.Name), - seen: make(map[*types.Type]*types.Type), + g: g, + isMethod: isMethod, + newf: newf, + tparams: tparams, + targs: targs, + vars: make(map[*ir.Name]*ir.Name), } newf.Dcl = make([]*ir.Name, len(gf.Dcl)) @@ -213,7 +288,7 @@ func (g *irgen) genericSubst(name *types.Sym, inst *ir.InstExpr) *ir.Func { // Ugly: we have to insert the Name nodes of the parameters/results into // the function type. The current function type has no Nname fields set, // because it came via conversion from the types2 type. - oldt := inst.X.Type() + oldt := nameNode.Type() // We also transform a generic method type to the corresponding // instantiated function type where the receiver is the first parameter. newt := types.NewSignature(oldt.Pkg(), nil, nil, @@ -326,7 +401,9 @@ func (subst *subster) node(n ir.Node) ir.Node { } newfn.SetIsHiddenClosure(true) m.(*ir.ClosureExpr).Func = newfn - newsym := makeInstName(oldfn.Nname.Sym(), subst.targs) + // Closure name can already have brackets, if it derives + // from a generic method + newsym := makeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod) newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym) newfn.Nname.Func = newfn newfn.Nname.Defn = newfn @@ -379,6 +456,12 @@ func (subst *subster) list(l []ir.Node) []ir.Node { // Nname is in subst.vars. func (subst *subster) tstruct(t *types.Type) *types.Type { if t.NumFields() == 0 { + if t.HasTParam() { + // For an empty struct, we need to return a new type, + // since it may now be fully instantiated (HasTParam + // becomes false). + return types.NewStruct(t.Pkg(), nil) + } return t } var newfields []*types.Field @@ -391,12 +474,21 @@ func (subst *subster) tstruct(t *types.Type) *types.Type { } } if newfields != nil { + // TODO(danscales): make sure this works for the field + // names of embedded types (which should keep the name of + // the type param, not the instantiated type). newfields[i] = types.NewField(f.Pos, f.Sym, t2) if f.Nname != nil { // f.Nname may not be in subst.vars[] if this is // a function name or a function instantiation type // that we are translating - newfields[i].Nname = subst.vars[f.Nname.(*ir.Name)] + v := subst.vars[f.Nname.(*ir.Name)] + // Be careful not to put a nil var into Nname, + // since Nname is an interface, so it would be a + // non-nil interface. + if v != nil { + newfields[i].Nname = v + } } } } @@ -407,7 +499,32 @@ func (subst *subster) tstruct(t *types.Type) *types.Type { } -// instTypeName creates a name for an instantiated type, based on the type args +// tinter substitutes type params in types of the methods of an interface type. +func (subst *subster) tinter(t *types.Type) *types.Type { + if t.Methods().Len() == 0 { + return t + } + var newfields []*types.Field + for i, f := range t.Methods().Slice() { + t2 := subst.typ(f.Type) + if (t2 != f.Type || f.Nname != nil) && newfields == nil { + newfields = make([]*types.Field, t.NumFields()) + for j := 0; j < i; j++ { + newfields[j] = t.Methods().Slice()[j] + } + } + if newfields != nil { + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + } + } + if newfields != nil { + return types.NewInterface(t.Pkg(), newfields) + } + return t +} + +// instTypeName creates a name for an instantiated type, based on the name of the +// generic type and the type args func instTypeName(name string, targs []*types.Type) string { b := bytes.NewBufferString(name) b.WriteByte('[') @@ -423,27 +540,57 @@ func instTypeName(name string, targs []*types.Type) string { // typ computes the type obtained by substituting any type parameter in t with the // corresponding type argument in subst. If t contains no type parameters, the -// result is t; otherwise the result is a new type. -// It deals with recursive types by using a map and TFORW types. -// TODO(danscales) deal with recursion besides ptr/struct cases. +// result is t; otherwise the result is a new type. It deals with recursive types +// by using TFORW types and finding partially or fully created types via sym.Def. func (subst *subster) typ(t *types.Type) *types.Type { if !t.HasTParam() { return t } - if subst.seen[t] != nil { - // We've hit a recursive type - return subst.seen[t] - } - var newt *types.Type - switch t.Kind() { - case types.TTYPEPARAM: + if t.Kind() == types.TTYPEPARAM { for i, tp := range subst.tparams { if tp.Type == t { return subst.targs[i].Type() } } return t + } + + var newsym *types.Sym + var neededTargs []*types.Type + var forw *types.Type + + if t.Sym() != nil { + // Translate the type params for this type according to + // the tparam/targs mapping from subst. + neededTargs = make([]*types.Type, len(t.RParams())) + for i, rparam := range t.RParams() { + neededTargs[i] = subst.typ(rparam) + } + // For a named (defined) type, we have to change the name of the + // type as well. We do this first, so we can look up if we've + // already seen this type during this substitution or other + // definitions/substitutions. + genName := genericTypeName(t.Sym()) + newsym = t.Sym().Pkg.Lookup(instTypeName(genName, neededTargs)) + if newsym.Def != nil { + // We've already created this instantiated defined type. + return newsym.Def.Type() + } + + // In order to deal with recursive generic types, create a TFORW type + // initially and set its Def field, so it can be found if this type + // appears recursively within the type. + forw = types.New(types.TFORW) + forw.SetSym(newsym) + newsym.Def = ir.TypeNode(forw) + //println("Creating new type by sub", newsym.Name, forw.HasTParam()) + forw.SetRParams(neededTargs) + } + + var newt *types.Type + + switch t.Kind() { case types.TARRAY: elem := t.Elem() @@ -454,17 +601,10 @@ func (subst *subster) typ(t *types.Type) *types.Type { case types.TPTR: elem := t.Elem() - // In order to deal with recursive generic types, create a TFORW - // type initially and store it in the seen map, so it can be - // accessed if this type appears recursively within the type. - forw := types.New(types.TFORW) - subst.seen[t] = forw newelem := subst.typ(elem) if newelem != elem { - forw.SetUnderlying(types.NewPtr(newelem)) - newt = forw + newt = types.NewPtr(newelem) } - delete(subst.seen, t) case types.TSLICE: elem := t.Elem() @@ -474,14 +614,10 @@ func (subst *subster) typ(t *types.Type) *types.Type { } case types.TSTRUCT: - forw := types.New(types.TFORW) - subst.seen[t] = forw newt = subst.tstruct(t) - if newt != t { - forw.SetUnderlying(newt) - newt = forw + if newt == t { + newt = nil } - delete(subst.seen, t) case types.TFUNC: newrecvs := subst.tstruct(t.Recvs()) @@ -492,40 +628,61 @@ func (subst *subster) typ(t *types.Type) *types.Type { if newrecvs.NumFields() > 0 { newrecv = newrecvs.Field(0) } - newt = types.NewSignature(t.Pkg(), newrecv, nil, newparams.FieldSlice(), newresults.FieldSlice()) + newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice()) + } + + case types.TINTER: + newt = subst.tinter(t) + if newt == t { + newt = nil } // TODO: case TCHAN // TODO: case TMAP - // TODO: case TINTER } - if newt != nil { - if t.Sym() != nil { - // Since we've substituted types, we also need to change - // the defined name of the type, by removing the old types - // (in brackets) from the name, and adding the new types. - - // Translate the type params for this type according to - // the tparam/targs mapping of the function. - neededTargs := make([]*types.Type, len(t.RParams)) - for i, rparam := range t.RParams { - neededTargs[i] = subst.typ(rparam) - } - oldname := t.Sym().Name - i := strings.Index(oldname, "[") - oldname = oldname[:i] - sym := t.Sym().Pkg.Lookup(instTypeName(oldname, neededTargs)) - if sym.Def != nil { - // We've already created this instantiated defined type. - return sym.Def.Type() - } - newt.SetSym(sym) - sym.Def = ir.TypeNode(newt) - } + if newt == nil { + // Even though there were typeparams in the type, there may be no + // change if this is a function type for a function call (which will + // have its own tparams/targs in the function instantiation). + return t + } + + if t.Sym() == nil { + // Not a named type, so there was no forwarding type and there are + // no methods to substitute. + assert(t.Methods().Len() == 0) return newt } - return t + forw.SetUnderlying(newt) + newt = forw + + if t.Kind() != types.TINTER && t.Methods().Len() > 0 { + // Fill in the method info for the new type. + var newfields []*types.Field + newfields = make([]*types.Field, t.Methods().Len()) + for i, f := range t.Methods().Slice() { + t2 := subst.typ(f.Type) + oldsym := f.Nname.Sym() + newsym := makeInstName(oldsym, subst.targs, true) + var nname *ir.Name + if newsym.Def != nil { + nname = newsym.Def.(*ir.Name) + } else { + nname = ir.NewNameAt(f.Pos, newsym) + nname.SetType(t2) + newsym.Def = nname + } + newfields[i] = types.NewField(f.Pos, f.Sym, t2) + newfields[i].Nname = nname + } + newt.Methods().Set(newfields) + if !newt.HasTParam() { + // Generate all the methods for a new fully-instantiated type. + subst.g.instTypeList = append(subst.g.instTypeList, newt) + } + } + return newt } // fields sets the Nname field for the Field nodes inside a type signature, based @@ -554,3 +711,11 @@ func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir } return newfields } + +// defer does a single defer of type t, if it is a pointer type. +func deref(t *types.Type) *types.Type { + if t.IsPtr() { + return t.Elem() + } + return t +} diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index c23295c3a1..dfcf55d9c8 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -12,6 +12,7 @@ import ( "cmd/compile/internal/types" "cmd/compile/internal/types2" "cmd/internal/src" + "strings" ) func (g *irgen) pkg(pkg *types2.Package) *types.Pkg { @@ -29,11 +30,10 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg { // typ converts a types2.Type to a types.Type, including caching of previously // translated types. func (g *irgen) typ(typ types2.Type) *types.Type { - // Caching type mappings isn't strictly needed, because typ0 preserves - // type identity; but caching minimizes memory blow-up from mapping the - // same composite type multiple times, and also plays better with the - // current state of cmd/compile (e.g., haphazard calculation of type - // sizes). + // Cache type2-to-type mappings. Important so that each defined generic + // type (instantiated or not) has a single types.Type representation. + // Also saves a lot of computation and memory by avoiding re-translating + // types2 types repeatedly. res, ok := g.typs[typ] if !ok { res = g.typ0(typ) @@ -42,9 +42,9 @@ func (g *irgen) typ(typ types2.Type) *types.Type { // Ensure we calculate the size for all concrete types seen by // the frontend. This is another heavy hammer for something that // should really be the backend's responsibility instead. - if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() { - types.CheckSize(res) - } + //if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() { + // types.CheckSize(res) + //} } return res } @@ -99,27 +99,35 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // Create a forwarding type first and put it in the g.typs // map, in order to deal with recursive generic types. + // Fully set up the extra ntyp information (Def, RParams, + // which may set HasTParam) before translating the + // underlying type itself, so we handle recursion + // correctly, including via method signatures. ntyp := types.New(types.TFORW) g.typs[typ] = ntyp - ntyp.SetUnderlying(g.typ(typ.Underlying())) ntyp.SetSym(s) + s.Def = ir.TypeNode(ntyp) - if ntyp.HasTParam() { - // If ntyp still has type params, then we must be - // referencing something like 'value[T2]', as when - // specifying the generic receiver of a method, - // where value was defined as "type value[T any] - // ...". Save the type args, which will now be the - // new type params of the current type. - ntyp.RParams = make([]*types.Type, len(typ.TArgs())) - for i, targ := range typ.TArgs() { - ntyp.RParams[i] = g.typ(targ) - } + // If ntyp still has type params, then we must be + // referencing something like 'value[T2]', as when + // specifying the generic receiver of a method, + // where value was defined as "type value[T any] + // ...". Save the type args, which will now be the + // new type of the current type. + // + // If ntyp does not have type params, we are saving the + // concrete types used to instantiate this type. We'll use + // these when instantiating the methods of the + // instantiated type. + rparams := make([]*types.Type, len(typ.TArgs())) + for i, targ := range typ.TArgs() { + rparams[i] = g.typ(targ) } + ntyp.SetRParams(rparams) + //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam()) - // Make sure instantiated type can be uniquely found from - // the sym - s.Def = ir.TypeNode(ntyp) + ntyp.SetUnderlying(g.typ(typ.Underlying())) + g.fillinMethods(typ, ntyp) return ntyp } obj := g.obj(typ.Obj()) @@ -174,7 +182,9 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { case *types2.TypeParam: tp := types.NewTypeParam(g.tpkg(typ), g.typ(typ.Bound())) // Save the name of the type parameter in the sym of the type. - tp.SetSym(g.sym(typ.Obj())) + // Include the types2 subscript in the sym name + sym := g.pkg(typ.Obj().Pkg()).Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" })) + tp.SetSym(sym) return tp case *types2.Tuple: @@ -188,7 +198,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { fields[i] = g.param(typ.At(i)) } t := types.NewStruct(types.LocalPkg, fields) - types.CheckSize(t) + //types.CheckSize(t) // Can only set after doing the types.CheckSize() t.StructType().Funarg = types.FunargResults return t @@ -199,6 +209,71 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { } } +// fillinMethods fills in the method name nodes and types for a defined type. This +// is needed for later typechecking when looking up methods of instantiated types, +// and for actually generating the methods for instantiated types. +func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { + if typ.NumMethods() != 0 { + targs := make([]ir.Node, len(typ.TArgs())) + for i, targ := range typ.TArgs() { + targs[i] = ir.TypeNode(g.typ(targ)) + } + + methods := make([]*types.Field, typ.NumMethods()) + for i := range methods { + m := typ.Method(i) + meth := g.obj(m) + recvType := types2.AsSignature(m.Type()).Recv().Type() + ptr := types2.AsPointer(recvType) + if ptr != nil { + recvType = ptr.Elem() + } + if recvType != types2.Type(typ) { + // Unfortunately, meth is the type of the method of the + // generic type, so we have to do a substitution to get + // the name/type of the method of the instantiated type, + // using m.Type().RParams() and typ.TArgs() + inst2 := instTypeName2("", typ.TArgs()) + name := meth.Sym().Name + i1 := strings.Index(name, "[") + i2 := strings.Index(name[i1:], "]") + assert(i1 >= 0 && i2 >= 0) + // Generate the name of the instantiated method. + name = name[0:i1] + inst2 + name[i1+i2+1:] + newsym := meth.Sym().Pkg.Lookup(name) + var meth2 *ir.Name + if newsym.Def != nil { + meth2 = newsym.Def.(*ir.Name) + } else { + meth2 = ir.NewNameAt(meth.Pos(), newsym) + rparams := types2.AsSignature(m.Type()).RParams() + tparams := make([]*types.Field, len(rparams)) + for i, rparam := range rparams { + tparams[i] = types.NewField(src.NoXPos, nil, g.typ(rparam.Type())) + } + assert(len(tparams) == len(targs)) + subst := &subster{ + g: g, + tparams: tparams, + targs: targs, + } + // Do the substitution of the type + meth2.SetType(subst.typ(meth.Type())) + newsym.Def = meth2 + } + meth = meth2 + } + methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type()) + methods[i].Nname = meth + } + ntyp.Methods().Set(methods) + if !ntyp.HasTParam() { + // Generate all the methods for a new fully-instantiated type. + g.instTypeList = append(g.instTypeList, ntyp) + } + } +} + func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type { tparams2 := sig.TParams() tparams := make([]*types.Field, len(tparams2)) diff --git a/src/cmd/compile/internal/noder/validate.go b/src/cmd/compile/internal/noder/validate.go index f97f81d5ad..3341de8e04 100644 --- a/src/cmd/compile/internal/noder/validate.go +++ b/src/cmd/compile/internal/noder/validate.go @@ -96,9 +96,7 @@ func (g *irgen) unsafeExpr(name string, arg syntax.Expr) int64 { selection := g.info.Selections[sel] typ := g.typ(g.info.Types[sel.X].Type) - if typ.IsPtr() { - typ = typ.Elem() - } + typ = deref(typ) var offset int64 for _, i := range selection.Index() { diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index b0516a8259..d76d9b409f 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -177,10 +177,16 @@ type Type struct { flags bitset8 - // Type params (in order) of this named type that need to be instantiated. + // For defined (named) generic types, the list of type params (in order) + // of this type that need to be instantiated. For fully-instantiated + // generic types, this is the targs used to instantiate them (which are + // used when generating the corresponding instantiated methods). rparams + // is only set for named types that are generic or are fully-instantiated + // from a generic type. + // TODO(danscales): for space reasons, should probably be a pointer to a // slice, possibly change the name of this field. - RParams []*Type + rparams []*Type } func (*Type) CanBeAnSSAAux() {} @@ -236,6 +242,26 @@ func (t *Type) Pos() src.XPos { return src.NoXPos } +func (t *Type) RParams() []*Type { + return t.rparams +} + +func (t *Type) SetRParams(rparams []*Type) { + t.rparams = rparams + if t.HasTParam() { + return + } + // HasTParam should be set if any rparam is or has a type param. This is + // to handle the case of a generic type which doesn't reference any of its + // type params (e.g. most commonly, an empty struct). + for _, rparam := range rparams { + if rparam.HasTParam() { + t.SetHasTParam(true) + break + } + } +} + // NoPkg is a nil *Pkg value for clarity. // It's intended for use when constructing types that aren't exported // and thus don't need to be associated with any package. @@ -1702,6 +1728,13 @@ func NewBasic(kind Kind, obj Object) *Type { func NewInterface(pkg *Pkg, methods []*Field) *Type { t := New(TINTER) t.SetInterface(methods) + for _, f := range methods { + // f.Type could be nil for a broken interface declaration + if f.Type != nil && f.Type.HasTParam() { + t.SetHasTParam(true) + break + } + } if anyBroke(methods) { t.SetBroke(true) } @@ -1754,6 +1787,7 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ unzeroFieldOffsets(params) unzeroFieldOffsets(results) ft.Receiver = funargs(recvs, FunargRcvr) + // TODO(danscales): just use nil here (save memory) if no tparams ft.TParams = funargs(tparams, FunargTparams) ft.Params = funargs(params, FunargParams) ft.Results = funargs(results, FunargResults) diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 52bd99deab..ae6642a059 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -243,6 +243,9 @@ func (s *Signature) Recv() *Var { return s.recv } // TParams returns the type parameters of signature s, or nil. func (s *Signature) TParams() []*TypeName { return s.tparams } +// RParams returns the receiver type params of signature s, or nil. +func (s *Signature) RParams() []*TypeName { return s.rparams } + // SetTParams sets the type parameters of signature s. func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams } @@ -965,5 +968,6 @@ func asTypeParam(t Type) *TypeParam { // Exported for the compiler. -func AsPointer(t Type) *Pointer { return asPointer(t) } -func AsNamed(t Type) *Named { return asNamed(t) } +func AsPointer(t Type) *Pointer { return asPointer(t) } +func AsNamed(t Type) *Named { return asNamed(t) } +func AsSignature(t Type) *Signature { return asSignature(t) } diff --git a/test/typeparam/cons.go b/test/typeparam/cons.go new file mode 100644 index 0000000000..08a825f59f --- /dev/null +++ b/test/typeparam/cons.go @@ -0,0 +1,101 @@ +// run -gcflags=-G=3 + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// lice + +package main + +import "fmt" + +// Overriding the predeclare "any", so it can be used as a type constraint or a type +// argument +type any interface{} + +type _Function[a, b any] interface { + Apply(x a) b +} + +type incr struct{ n int } + +func (this incr) Apply(x int) int { + return x + this.n +} + +type pos struct{} + +func (this pos) Apply(x int) bool { + return x > 0 +} + +type compose[a, b, c any] struct { + f _Function[a, b] + g _Function[b, c] +} + +func (this compose[a, b, c]) Apply(x a) c { + return this.g.Apply(this.f.Apply(x)) +} + +type _Eq[a any] interface { + Equal(a) bool +} + +type Int int + +func (this Int) Equal(that int) bool { + return int(this) == that +} + +type _List[a any] interface { + Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any +} + +type _Nil[a any] struct{ +} + +func (xs _Nil[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any { + return casenil.Apply(xs) +} + +type _Cons[a any] struct { + Head a + Tail _List[a] +} + +func (xs _Cons[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any { + return casecons.Apply(xs) +} + +type mapNil[a, b any] struct{ +} + +func (m mapNil[a, b]) Apply(_ _Nil[a]) any { + return _Nil[b]{} +} + +type mapCons[a, b any] struct { + f _Function[a, b] +} + +func (m mapCons[a, b]) Apply(xs _Cons[a]) any { + return _Cons[b]{m.f.Apply(xs.Head), _Map[a, b](m.f, xs.Tail)} +} + +func _Map[a, b any](f _Function[a, b], xs _List[a]) _List[b] { + return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(_List[b]) +} + +func main() { + var xs _List[int] = _Cons[int]{3, _Cons[int]{6, _Nil[int]{}}} + // TODO(danscales): Remove conversion calls in next two, needed for now. + var ys _List[int] = _Map[int, int](_Function[int, int](incr{-5}), xs) + var xz _List[bool] = _Map[int, bool](_Function[int, bool](pos{}), ys) + cs1 := xz.(_Cons[bool]) + cs2 := cs1.Tail.(_Cons[bool]) + _, ok := cs2.Tail.(_Nil[bool]) + if cs1.Head != false || cs2.Head != true || !ok { + panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true", + cs1.Head, cs2.Head, ok)) + } +} diff --git a/test/typeparam/ordered.go b/test/typeparam/ordered.go new file mode 100644 index 0000000000..448db68bb5 --- /dev/null +++ b/test/typeparam/ordered.go @@ -0,0 +1,95 @@ +// run -gcflags=-G=3 + +// Copyright 2021 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 ( + "fmt" + "math" + "sort" +) + +type Ordered interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64, + string +} + +type orderedSlice[Elem Ordered] []Elem + +func (s orderedSlice[Elem]) Len() int { return len(s) } +func (s orderedSlice[Elem]) Less(i, j int) bool { + if s[i] < s[j] { + return true + } + isNaN := func(f Elem) bool { return f != f } + if isNaN(s[i]) && !isNaN(s[j]) { + return true + } + return false +} +func (s orderedSlice[Elem]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func _OrderedSlice[Elem Ordered](s []Elem) { + sort.Sort(orderedSlice[Elem](s)) +} + +var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} +var float64s = []float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} +var strings = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} + +func TestSortOrderedInts() bool { + return testOrdered("ints", ints, sort.Ints) +} + +func TestSortOrderedFloat64s() bool { + return testOrdered("float64s", float64s, sort.Float64s) +} + +func TestSortOrderedStrings() bool { + return testOrdered("strings", strings, sort.Strings) +} + +func testOrdered[Elem Ordered](name string, s []Elem, sorter func([]Elem)) bool { + s1 := make([]Elem, len(s)) + copy(s1, s) + s2 := make([]Elem, len(s)) + copy(s2, s) + _OrderedSlice(s1) + sorter(s2) + ok := true + if !sliceEq(s1, s2) { + fmt.Printf("%s: got %v, want %v", name, s1, s2) + ok = false + } + for i := len(s1) - 1; i > 0; i-- { + if s1[i] < s1[i-1] { + fmt.Printf("%s: element %d (%v) < element %d (%v)", name, i, s1[i], i - 1, s1[i - 1]) + ok = false + } + } + return ok +} + +func sliceEq[Elem Ordered](s1, s2 []Elem) bool { + for i, v1 := range s1 { + v2 := s2[i] + if v1 != v2 { + isNaN := func(f Elem) bool { return f != f } + if !isNaN(v1) || !isNaN(v2) { + return false + } + } + } + return true +} + +func main() { + if !TestSortOrderedInts() || !TestSortOrderedFloat64s() || !TestSortOrderedStrings() { + panic("failure") + } +} diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go index 7532953a77..f42c6574fe 100644 --- a/test/typeparam/settable.go +++ b/test/typeparam/settable.go @@ -11,12 +11,12 @@ import ( "strconv" ) -type Setter[B any] interface { +type _Setter[B any] interface { Set(string) type *B } -func fromStrings1[T any, PT Setter[T]](s []string) []T { +func fromStrings1[T any, PT _Setter[T]](s []string) []T { result := make([]T, len(s)) for i, v := range s { // The type of &result[i] is *T which is in the type list -- GitLab From b60a3a8cfbc6096babe72ebcee0733bba496cf9a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 5 Mar 2021 09:49:28 -0800 Subject: [PATCH 0248/1298] cmd/compile: add debugging mode for import/export Just add a simple magic number with each op, to detect when the reader gets desynchronized from the writer. Change-Id: Iac7dab7f465b0021b1d7ae31c8f8a353ac3663a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/299769 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/typecheck/iexport.go | 8 ++++++++ src/cmd/compile/internal/typecheck/iimport.go | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 38ac753201..6f33ca1597 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -246,6 +246,11 @@ const ( interfaceType ) +const ( + debug = false + magic = 0x6742937dc293105 +) + func WriteExports(out *bufio.Writer) { p := iexporter{ allPkgs: map[*types.Pkg]bool{}, @@ -1584,6 +1589,9 @@ func (w *exportWriter) expr(n ir.Node) { } func (w *exportWriter) op(op ir.Op) { + if debug { + w.uint64(magic) + } w.uint64(uint64(op)) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 8df75b2285..d7c118b631 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1228,6 +1228,9 @@ func (r *importReader) node() ir.Node { } func (r *importReader) op() ir.Op { + if debug && r.uint64() != magic { + base.Fatalf("import stream has desynchronized") + } return ir.Op(r.uint64()) } -- GitLab From e8e425cb231863c1ed1bcf00dd5a517ceeaf6b9c Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 9 Mar 2021 10:41:16 -0500 Subject: [PATCH 0249/1298] runtime: add pollDesc partial edges gscan is taken during stack growth, which may occur while pollDesc is held. mallocgc may also be called while pollDesc is held. mallocgc may take mheap or mheapSpecial. The former exists, but is out of order; the latter is missing. Fixes #44881 Change-Id: Ie25935d9d433e813c11a528ee47255b317a09f41 Reviewed-on: https://go-review.googlesource.com/c/go/+/300009 Trust: Michael Pratt Trust: Dan Scales Reviewed-by: Dan Scales Reviewed-by: Michael Knyszek Run-TryBot: Michael Pratt --- src/runtime/lockrank.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go index 23b727f4d8..5a908b470f 100644 --- a/src/runtime/lockrank.go +++ b/src/runtime/lockrank.go @@ -224,14 +224,14 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankRwmutexR: {lockRankSysmon, lockRankRwmutexW}, lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankSpanSetSpine}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankSpanSetSpine}, lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankSpanSetSpine, lockRankGscan}, lockRankStackLarge: {lockRankSysmon, lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankSpanSetSpine, lockRankGscan}, lockRankDefer: {}, lockRankSudog: {lockRankNotifyList, lockRankHchan}, lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankFin, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankFin, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, lockRankGlobalAlloc: {lockRankProf, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial}, lockRankGFree: {lockRankSched}, -- GitLab From b6df58bd1f3b2a05787f62bbec4267f7867d4bbd Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 5 Mar 2021 09:50:28 -0800 Subject: [PATCH 0250/1298] cmd/compile: detect duplicate importing earlier Change-Id: I05ba944e189a884b727e40a9526d212612c3e923 Reviewed-on: https://go-review.googlesource.com/c/go/+/299770 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/typecheck/func.go | 11 +++-------- src/cmd/compile/internal/typecheck/iimport.go | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 6e2354c281..367df8e9f4 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -108,6 +108,9 @@ var inTypeCheckInl bool // Lazy typechecking of imported bodies. For local functions, CanInline will set ->typecheck // because they're a copy of an already checked body. func ImportedBody(fn *ir.Func) { + if fn.Inl.Body != nil { + return + } lno := ir.SetPos(fn.Nname) // When we load an inlined body, we need to allow OADDR @@ -151,14 +154,6 @@ func ImportedBody(fn *ir.Func) { inTypeCheckInl = false ir.CurFunc = savefn - // During ImportBody (which imports fn.Func.Inl.Body), - // declarations are added to fn.Func.Dcl by funcBody(). Move them - // to fn.Func.Inl.Dcl for consistency with how local functions - // behave. (Append because ImportedBody may be called multiple - // times on same fn.) - fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...) - fn.Dcl = nil - base.Pos = lno } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index d7c118b631..5c57373b66 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -63,7 +63,7 @@ func expandDecl(n ir.Node) ir.Node { func ImportBody(fn *ir.Func) { if fn.Inl.Body != nil { - return + base.Fatalf("%v already has inline body", fn) } r := importReaderFor(fn.Nname.Sym(), inlineImporter) -- GitLab From 48895d021bf631f15d68ecc10cab89ebd9cb28f6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 7 Mar 2021 23:48:02 -0800 Subject: [PATCH 0251/1298] cmd/compile: remove skipping of implicit operations during export We'll need to attach types to these operations, so we need to represent them in the import/export data. Some of the operations use a selector indicating a different package, so we need to provide an option to encode the package of a selector. The default selector() function can't encode that extra information, as selector's exact encoding is used by go/types. Change-Id: I4c110fe347b3d915f88a722834bc4058baea7854 Reviewed-on: https://go-review.googlesource.com/c/go/+/299771 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/typecheck/iexport.go | 42 ++++++++++++------- src/cmd/compile/internal/typecheck/iimport.go | 19 ++++++++- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 6f33ca1597..fa16357066 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -617,6 +617,11 @@ func (w *exportWriter) selector(s *types.Sym) { base.Fatalf("missing currPkg") } + // If the selector being written is unexported, it comes with a package qualifier. + // If the selector being written is exported, it is not package-qualified. + // See the spec: https://golang.org/ref/spec#Uniqueness_of_identifiers + // As an optimization, we don't actually write the package every time - instead we + // call setPkg before a group of selectors (all of which must have the same package qualifier). pkg := w.currPkg if types.IsExported(s.Name) { pkg = types.LocalPkg @@ -628,6 +633,26 @@ func (w *exportWriter) selector(s *types.Sym) { w.string(s.Name) } +// Export a selector, but one whose package may not match +// the package being compiled. This is a separate function +// because the standard selector() serialization format is fixed +// by the go/types reader. This one can only be used during +// inline/generic body exporting. +func (w *exportWriter) exoticSelector(s *types.Sym) { + pkg := w.currPkg + if types.IsExported(s.Name) { + pkg = types.LocalPkg + } + + w.string(s.Name) + if s.Pkg == pkg { + w.uint64(0) + } else { + w.uint64(1) + w.pkg(s.Pkg) + } +} + func (w *exportWriter) typ(t *types.Type) { w.data.uint64(w.p.typOff(t)) } @@ -1299,21 +1324,6 @@ func simplifyForExport(n ir.Node) ir.Node { case ir.OPAREN: n := n.(*ir.ParenExpr) return simplifyForExport(n.X) - case ir.ODEREF: - n := n.(*ir.StarExpr) - if n.Implicit() { - return simplifyForExport(n.X) - } - case ir.OADDR: - n := n.(*ir.AddrExpr) - if n.Implicit() { - return simplifyForExport(n.X) - } - case ir.ODOT, ir.ODOTPTR: - n := n.(*ir.SelectorExpr) - if n.Implicit() { - return simplifyForExport(n.X) - } } return n } @@ -1437,7 +1447,7 @@ func (w *exportWriter) expr(n ir.Node) { w.op(ir.OXDOT) w.pos(n.Pos()) w.expr(n.X) - w.selector(n.Sel) + w.exoticSelector(n.Sel) case ir.ODOTTYPE, ir.ODOTTYPE2: n := n.(*ir.TypeAssertExpr) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 5c57373b66..91bb215a29 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -466,6 +466,21 @@ func (r *importReader) ident(selector bool) *types.Sym { func (r *importReader) localIdent() *types.Sym { return r.ident(false) } func (r *importReader) selector() *types.Sym { return r.ident(true) } +func (r *importReader) exoticSelector() *types.Sym { + name := r.string() + if name == "" { + return nil + } + pkg := r.currPkg + if types.IsExported(name) { + pkg = types.LocalPkg + } + if r.uint64() != 0 { + pkg = r.pkg() + } + return pkg.Lookup(name) +} + func (r *importReader) qualifiedIdent() *ir.Ident { name := r.string() pkg := r.pkg() @@ -753,7 +768,7 @@ func (r *importReader) doInline(fn *ir.Func) { base.Fatalf("%v already has inline body", fn) } - //fmt.Printf("Importing %v\n", n) + //fmt.Printf("Importing %s\n", fn.Nname.Sym().Name) r.funcBody(fn) importlist = append(importlist, fn) @@ -1038,7 +1053,7 @@ func (r *importReader) node() ir.Node { case ir.OXDOT: // see parser.new_dotname - return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.selector()) + return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.exoticSelector()) // case ODOTTYPE, ODOTTYPE2: // unreachable - mapped to case ODOTTYPE below by exporter -- GitLab From 5eb99120844c0494d655678262e1fb41949a2b99 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 5 Mar 2021 19:56:13 -0500 Subject: [PATCH 0252/1298] cmd/compile: fix OpArg decomposer for registers in expandCalls Includes test taken from https://github.com/golang/go/issues/44816#issuecomment-791618179 and improved debugging output. Updates #44816 Change-Id: I94aeb9c5255f175fe80727be29d218bad54bf7ea Reviewed-on: https://go-review.googlesource.com/c/go/+/299389 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 162 +++++++++++++++---- test/abi/double_nested_struct.go | 9 +- test/abi/struct_lower_1.go | 30 ++++ test/abi/struct_lower_1.out | 1 + test/abi/too_big_to_ssa.go | 7 +- 5 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 test/abi/struct_lower_1.go create mode 100644 test/abi/struct_lower_1.out diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index df135853fe..516ea42db9 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -78,7 +78,8 @@ func (rc *registerCursor) String() string { regs = regs + x.LongString() } } - return fmt.Sprintf("RCSR{storeDest=%v, regsLen=%d, nextSlice=%d, regValues=[%s], config=%v", dest, rc.regsLen, rc.nextSlice, regs, rc.config) + // not printing the config because that has not been useful + return fmt.Sprintf("RCSR{storeDest=%v, regsLen=%d, nextSlice=%d, regValues=[%s]}", dest, rc.regsLen, rc.nextSlice, regs) } // next effectively post-increments the register cursor; the receiver is advanced, @@ -189,6 +190,7 @@ type expandState struct { commonSelectors map[selKey]*Value // used to de-dupe selectors commonArgs map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem. + indentLevel int // Indentation for debugging recursion } // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target @@ -267,6 +269,19 @@ func ParamAssignmentForArgName(f *Func, name *ir.Name) *abi.ABIParamAssignment { panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, abiInfo.InParams())) } +// indent increments (or decrements) the indentation. +func (x *expandState) indent(n int) { + x.indentLevel += n +} + +// Printf does an indented fmt.Printf on te format and args. +func (x *expandState) Printf(format string, a ...interface{}) (n int, err error) { + if x.indentLevel > 0 { + fmt.Printf("%[1]*s", x.indentLevel, "") + } + return fmt.Printf(format, a...) +} + // Calls that need lowering have some number of inputs, including a memory input, // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able. @@ -286,7 +301,9 @@ func ParamAssignmentForArgName(f *Func, name *ir.Name) *abi.ABIParamAssignment { // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory. func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []LocalSlot { if x.debug { - fmt.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset) + x.indent(3) + defer x.indent(-3) + x.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset) } var locs []LocalSlot leafType := leaf.Type @@ -308,7 +325,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString()) } if x.debug { - fmt.Printf("\tOpArg, break\n") + x.Printf("---OpArg, break\n") } break } @@ -427,7 +444,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call) leaf.copyOf(w) if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) + x.Printf("---new %s\n", w.LongString()) } } } @@ -539,9 +556,86 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, return mem } -// decomposeArgOrLoad is a helper for storeArgOrLoad. -// It decomposes a Load or an Arg into smaller parts, parameterized by the decomposeOne and decomposeTwo functions -// passed to it, and returns the new mem. +// decomposeArg is a helper for storeArgOrLoad. +// It decomposes a Load or an Arg into smaller parts and returns the new mem. +// If the type does not match one of the expected aggregate types, it returns nil instead. +// Parameters: +// pos -- the location of any generated code. +// b -- the block into which any generated code should normally be placed +// source -- the value, possibly an aggregate, to be stored. +// mem -- the mem flowing into this decomposition (loads depend on it, stores updated it) +// t -- the type of the value to be stored +// storeOffset -- if the value is stored in memory, it is stored at base (see storeRc) + storeOffset +// loadRegOffset -- regarding source as a value in registers, the register offset in ABI1. Meaningful only if source is OpArg. +// storeRc -- storeRC; if the value is stored in registers, this specifies the registers. +// StoreRc also identifies whether the target is registers or memory, and has the base for the store operation. +func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + + pa := x.prAssignForArg(source) + if len(pa.Registers) > 0 { + // Handle the in-registers case directly + rts, offs := pa.RegisterTypesAndOffsets() + last := loadRegOffset + x.regWidth(t) + if offs[loadRegOffset] != 0 { + panic(fmt.Errorf("offset %d of requested register %d should be zero", offs[loadRegOffset], loadRegOffset)) + } + for i := loadRegOffset; i < last; i++ { + rt := rts[i] + off := offs[i] + w := x.commonArgs[selKey{source, off, rt.Width, rt}] + if w == nil { + w = x.newArgToMemOrRegs(source, w, off, i, rt, pos) + } + mem = x.storeArgOrLoad(pos, b, w, mem, rt, storeOffset+off, i, storeRc.next(rt)) + } + return mem + } + + u := source.Type + switch u.Kind() { + case types.TARRAY: + elem := u.Elem() + elemRO := x.regWidth(elem) + for i := int64(0); i < u.NumElem(); i++ { + elemOff := i * elem.Size() + mem = storeOneArg(x, pos, b, source, mem, elem, elemOff, storeOffset+elemOff, loadRegOffset, storeRc.next(elem)) + loadRegOffset += elemRO + pos = pos.WithNotStmt() + } + return mem + case types.TSTRUCT: + for i := 0; i < u.NumFields(); i++ { + fld := u.Field(i) + mem = storeOneArg(x, pos, b, source, mem, fld.Type, fld.Offset, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + loadRegOffset += x.regWidth(fld.Type) + pos = pos.WithNotStmt() + } + return mem + case types.TINT64, types.TUINT64: + if t.Width == x.regSize { + break + } + tHi, tLo := x.intPairTypes(t.Kind()) + mem = storeOneArg(x, pos, b, source, mem, tHi, x.hiOffset, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + pos = pos.WithNotStmt() + return storeOneArg(x, pos, b, source, mem, tLo, x.lowOffset, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) + case types.TINTER: + return storeTwoArg(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc) + case types.TSTRING: + return storeTwoArg(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, storeOffset, loadRegOffset, storeRc) + case types.TCOMPLEX64: + return storeTwoArg(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, storeOffset, loadRegOffset, storeRc) + case types.TCOMPLEX128: + return storeTwoArg(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, storeOffset, loadRegOffset, storeRc) + case types.TSLICE: + mem = storeOneArg(x, pos, b, source, mem, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return storeTwoArg(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) + } + return nil +} + +// decomposeLoad is a helper for storeArgOrLoad. +// It decomposes a Load into smaller parts and returns the new mem. // If the type does not match one of the expected aggregate types, it returns nil instead. // Parameters: // pos -- the location of any generated code. @@ -555,11 +649,7 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, // StoreRc also identifies whether the target is registers or memory, and has the base for the store operation. // // TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates. -func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor, - // For decompose One and Two, the additional offArg provides the offset from the beginning of "source", if it is in memory. - // offStore is combined to base to obtain a store destionation, like "offset" of decomposeArgOrLoad - decomposeOne func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value, - decomposeTwo func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value { +func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { u := source.Type switch u.Kind() { case types.TARRAY: @@ -567,7 +657,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Va elemRO := x.regWidth(elem) for i := int64(0); i < u.NumElem(); i++ { elemOff := i * elem.Size() - mem = decomposeOne(x, pos, b, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) + mem = storeOneLoad(x, pos, b, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) loadRegOffset += elemRO pos = pos.WithNotStmt() } @@ -575,7 +665,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Va case types.TSTRUCT: for i := 0; i < u.NumFields(); i++ { fld := u.Field(i) - mem = decomposeOne(x, pos, b, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = storeOneLoad(x, pos, b, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -585,20 +675,20 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Va break } tHi, tLo := x.intPairTypes(t.Kind()) - mem = decomposeOne(x, pos, b, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = storeOneLoad(x, pos, b, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() - return decomposeOne(x, pos, b, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) + return storeOneLoad(x, pos, b, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) case types.TINTER: - return decomposeTwo(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) case types.TSTRING: - return decomposeTwo(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX64: - return decomposeTwo(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) case types.TCOMPLEX128: - return decomposeTwo(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) case types.TSLICE: - mem = decomposeOne(x, pos, b, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) - return decomposeTwo(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) + mem = storeOneLoad(x, pos, b, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) } return nil } @@ -642,7 +732,9 @@ func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1 // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering. func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { if x.debug { - fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String()) + x.indent(3) + defer x.indent(-3) + x.Printf("storeArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String()) } // Start with Opcodes that can be disassembled @@ -651,13 +743,13 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc) case OpLoad, OpDereference: - ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad) + ret := x.decomposeLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) if ret != nil { return ret } case OpArg: - ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg) + ret := x.decomposeArg(pos, b, source, mem, t, offset, loadRegOffset, storeRc) if ret != nil { return ret } @@ -823,7 +915,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) } if x.debug { - fmt.Printf("\t\tstoreArg returns %s, storeRc=%s\n", s.LongString(), storeRc.String()) + x.Printf("-->storeArg returns %s, storeRc=%s\n", s.LongString(), storeRc.String()) } return s } @@ -860,7 +952,7 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) { aOffset = aux.OffsetOfArg(auxI) } if x.debug { - fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) + x.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset) } rc.init(aRegs, aux.abiInfo, result, x.sp) mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc) @@ -910,7 +1002,7 @@ func expandCalls(f *Func) { } if x.debug { - fmt.Printf("\nexpandsCalls(%s)\n", f.Name) + x.Printf("\nexpandsCalls(%s)\n", f.Name) } // TODO if too slow, whole program iteration can be replaced w/ slices of appropriate values, accumulated in first loop here. @@ -1055,7 +1147,7 @@ func expandCalls(f *Func) { case OpStructSelect, OpArraySelect, OpSelectN, OpArg: val2Preds[w] += 1 if x.debug { - fmt.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w]) + x.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w]) } } fallthrough @@ -1064,7 +1156,7 @@ func expandCalls(f *Func) { if _, ok := val2Preds[v]; !ok { val2Preds[v] = 0 if x.debug { - fmt.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v]) + x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v]) } } @@ -1075,7 +1167,7 @@ func expandCalls(f *Func) { if _, ok := val2Preds[v]; !ok { val2Preds[v] = 0 if x.debug { - fmt.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v]) + x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v]) } } @@ -1203,7 +1295,7 @@ func expandCalls(f *Func) { for i, v := range allOrdered { if x.debug { b := v.Block - fmt.Printf("allOrdered[%d] = b%d, %s, uses=%d\n", i, b.ID, v.LongString(), v.Uses) + x.Printf("allOrdered[%d] = b%d, %s, uses=%d\n", i, b.ID, v.LongString(), v.Uses) } if v.Uses == 0 { v.reset(OpInvalid) @@ -1305,7 +1397,7 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value { // newArgToMemOrRegs either rewrites toReplace into an OpArg referencing memory or into an OpArgXXXReg to a register, // or rewrites it into a copy of the appropriate OpArgXXX. The actual OpArgXXX is determined by combining baseArg (an OpArg) -// with offset, regOffset, and t to determine which portion of it reference (either all or a part, in memory or in registers). +// with offset, regOffset, and t to determine which portion of it to reference (either all or a part, in memory or in registers). func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value { key := selKey{baseArg, offset, t.Width, t} w := x.commonArgs[key] @@ -1336,7 +1428,7 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, w := baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux) x.commonArgs[key] = w if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) + x.Printf("---new %s\n", w.LongString()) } if toReplace != nil { toReplace.copyOf(w) @@ -1364,7 +1456,7 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, } else { w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) if x.debug { - fmt.Printf("\tnew %s\n", w.LongString()) + x.Printf("---new %s\n", w.LongString()) } x.commonArgs[key] = w if toReplace != nil { diff --git a/test/abi/double_nested_struct.go b/test/abi/double_nested_struct.go index 70d8ea4bce..814341e701 100644 --- a/test/abi/double_nested_struct.go +++ b/test/abi/double_nested_struct.go @@ -8,7 +8,7 @@ // license that can be found in the LICENSE file. // wasm is excluded because the compiler chatter about register abi pragma ends up -// on stdout, and causes the expected output to not match. +// on stdout, and causes the expected output to not match. package main @@ -37,13 +37,12 @@ func H(spp stringPairPair) string { //go:registerparams //go:noinline -func G(a,b,c,d string) stringPairPair { - return stringPairPair{stringPair{a,b},stringPair{c,d}} +func G(a, b, c, d string) stringPairPair { + return stringPairPair{stringPair{a, b}, stringPair{c, d}} } - func main() { - spp := G("this","is","a","test") + spp := G("this", "is", "a", "test") s := H(spp) gotVsWant(s, "this is a test") } diff --git a/test/abi/struct_lower_1.go b/test/abi/struct_lower_1.go new file mode 100644 index 0000000000..b20de9be4b --- /dev/null +++ b/test/abi/struct_lower_1.go @@ -0,0 +1,30 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 "fmt" + +//go:registerparams +//go:noinline +func passStruct6(a Struct6) Struct6 { + return a +} + +type Struct6 struct { + Struct1 +} + +type Struct1 struct { + A, B, C uint +} + +func main() { + fmt.Println(passStruct6(Struct6{Struct1{1, 2, 3}})) +} diff --git a/test/abi/struct_lower_1.out b/test/abi/struct_lower_1.out new file mode 100644 index 0000000000..d326cb6119 --- /dev/null +++ b/test/abi/struct_lower_1.out @@ -0,0 +1 @@ +{{1 2 3}} diff --git a/test/abi/too_big_to_ssa.go b/test/abi/too_big_to_ssa.go index a5c6abb0e4..6c55d31419 100644 --- a/test/abi/too_big_to_ssa.go +++ b/test/abi/too_big_to_ssa.go @@ -1,5 +1,6 @@ // run +//go:build !wasm // +build !wasm // Copyright 2021 The Go Authors. All rights reserved. @@ -16,7 +17,7 @@ var sink *string type toobig struct { // 6 words will not SSA but will fit in registers - a,b,c string + a, b, c string } //go:registerparams @@ -27,8 +28,8 @@ func H(x toobig) string { //go:registerparams //go:noinline -func I(a,b,c string) toobig { - return toobig{a,b,c} +func I(a, b, c string) toobig { + return toobig{a, b, c} } func main() { -- GitLab From 98dfdc82c85c238a5ab6131d6f1e86e0da259851 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 5 Mar 2021 21:09:40 -0500 Subject: [PATCH 0253/1298] cmd/compile: fix broken type+offset calc for register args Includes more enhancements to debugging output. Updates #44816. Change-Id: I5b21815cf37ed21e7dec6c06f538090f32260203 Reviewed-on: https://go-review.googlesource.com/c/go/+/299409 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/abi/abiutils.go | 29 +++-- src/cmd/compile/internal/ssa/expand_calls.go | 110 ++++++++++--------- test/abi/bad_internal_offsets.go | 74 +++++++++++++ 3 files changed, 150 insertions(+), 63 deletions(-) create mode 100644 test/abi/bad_internal_offsets.go diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 3c07be62e0..7d5de1d528 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -130,10 +130,15 @@ func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) } typs := make([]*types.Type, 0, l) offs := make([]int64, 0, l) - return appendParamTypes(typs, pa.Type), appendParamOffsets(offs, 0, pa.Type) + offs, _ = appendParamOffsets(offs, 0, pa.Type) + return appendParamTypes(typs, pa.Type), offs } func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type { + w := t.Width + if w == 0 { + return rts + } if t.IsScalar() || t.IsPtrShaped() { if t.IsComplex() { c := types.FloatForComplex(t) @@ -176,28 +181,30 @@ func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type { } // appendParamOffsets appends the offset(s) of type t, starting from "at", -// to input offsets, and returns the longer slice. -func appendParamOffsets(offsets []int64, at int64, t *types.Type) []int64 { +// to input offsets, and returns the longer slice and the next unused offset. +func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int64) { at = align(at, t) + w := t.Width + if w == 0 { + return offsets, at + } if t.IsScalar() || t.IsPtrShaped() { if t.IsComplex() || int(t.Width) > types.RegSize { // complex and *int64 on 32-bit - s := t.Width / 2 - return append(offsets, at, at+s) + s := w / 2 + return append(offsets, at, at+s), at + w } else { - return append(offsets, at) + return append(offsets, at), at + w } } else { typ := t.Kind() switch typ { case types.TARRAY: for i := int64(0); i < t.NumElem(); i++ { - offsets = appendParamOffsets(offsets, at, t.Elem()) + offsets, at = appendParamOffsets(offsets, at, t.Elem()) } - return offsets case types.TSTRUCT: for _, f := range t.FieldSlice() { - offsets = appendParamOffsets(offsets, at, f.Type) - at += f.Type.Width + offsets, at = appendParamOffsets(offsets, at, f.Type) } case types.TSLICE: return appendParamOffsets(offsets, at, synthSlice) @@ -207,7 +214,7 @@ func appendParamOffsets(offsets []int64, at int64, t *types.Type) []int64 { return appendParamOffsets(offsets, at, synthIface) } } - return offsets + return offsets, at } // SpillOffset returns the offset *within the spill area* for the parameter that "a" describes. diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 516ea42db9..d4fa7f2b14 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -643,13 +643,13 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t // source -- the value, possibly an aggregate, to be stored. // mem -- the mem flowing into this decomposition (loads depend on it, stores updated it) // t -- the type of the value to be stored -// offset -- if the value is stored in memory, it is stored at base (see storeRc) + offset +// storeOffset -- if the value is stored in memory, it is stored at base (see storeRc) + offset // loadRegOffset -- regarding source as a value in registers, the register offset in ABI1. Meaningful only if source is OpArg. // storeRc -- storeRC; if the value is stored in registers, this specifies the registers. // StoreRc also identifies whether the target is registers or memory, and has the base for the store operation. // // TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates. -func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { u := source.Type switch u.Kind() { case types.TARRAY: @@ -657,7 +657,7 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, elemRO := x.regWidth(elem) for i := int64(0); i < u.NumElem(); i++ { elemOff := i * elem.Size() - mem = storeOneLoad(x, pos, b, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem)) + mem = storeOneLoad(x, pos, b, source, mem, elem, elemOff, storeOffset+elemOff, loadRegOffset, storeRc.next(elem)) loadRegOffset += elemRO pos = pos.WithNotStmt() } @@ -665,7 +665,7 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, case types.TSTRUCT: for i := 0; i < u.NumFields(); i++ { fld := u.Field(i) - mem = storeOneLoad(x, pos, b, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = storeOneLoad(x, pos, b, source, mem, fld.Type, fld.Offset, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -675,20 +675,20 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, break } tHi, tLo := x.intPairTypes(t.Kind()) - mem = storeOneLoad(x, pos, b, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = storeOneLoad(x, pos, b, source, mem, tHi, x.hiOffset, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() - return storeOneLoad(x, pos, b, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) + return storeOneLoad(x, pos, b, source, mem, tLo, x.lowOffset, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo)) case types.TINTER: - return storeTwoLoad(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc) case types.TSTRING: - return storeTwoLoad(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, storeOffset, loadRegOffset, storeRc) case types.TCOMPLEX64: - return storeTwoLoad(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, storeOffset, loadRegOffset, storeRc) case types.TCOMPLEX128: - return storeTwoLoad(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, storeOffset, loadRegOffset, storeRc) case types.TSLICE: - mem = storeOneLoad(x, pos, b, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) - return storeTwoLoad(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) + mem = storeOneLoad(x, pos, b, source, mem, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + return storeTwoLoad(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc) } return nil } @@ -696,12 +696,18 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, // storeOneArg creates a decomposed (one step) arg that is then stored. // pos and b locate the store instruction, source is the "base" of the value input, // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases. -func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { - w := x.commonArgs[selKey{source, offArg, t.Width, t}] +func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { + if x.debug { + x.indent(3) + defer x.indent(-3) + fmt.Printf("storeOneArg(%s; %s; %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String()) + } + + w := x.commonArgs[selKey{source, argOffset, t.Width, t}] if w == nil { - w = x.newArgToMemOrRegs(source, w, offArg, loadRegOffset, t, pos) + w = x.newArgToMemOrRegs(source, w, argOffset, loadRegOffset, t, pos) } - return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, w, mem, t, storeOffset, loadRegOffset, storeRc) } // storeOneLoad creates a decomposed (one step) load that is then stored. @@ -730,26 +736,26 @@ func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1 // storeArgOrLoad converts stores of SSA-able potentially aggregatable arguments (passed to a call) into a series of primitive-typed // stores of non-aggregate types. It recursively walks up a chain of selectors until it reaches a Load or an Arg. // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering. -func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { +func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { if x.debug { x.indent(3) defer x.indent(-3) - x.Printf("storeArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String()) + x.Printf("storeArgOrLoad(%s; %s; %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), storeOffset, storeRc.String()) } // Start with Opcodes that can be disassembled switch source.Op { case OpCopy: - return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, storeOffset, loadRegOffset, storeRc) case OpLoad, OpDereference: - ret := x.decomposeLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) + ret := x.decomposeLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc) if ret != nil { return ret } case OpArg: - ret := x.decomposeArg(pos, b, source, mem, t, offset, loadRegOffset, storeRc) + ret := x.decomposeArg(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc) if ret != nil { return ret } @@ -761,19 +767,19 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4: for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) - mem = x.storeArgOrLoad(pos, b, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type)) + mem = x.storeArgOrLoad(pos, b, source.Args[i], mem, fld.Type, storeOffset+fld.Offset, 0, storeRc.next(fld.Type)) pos = pos.WithNotStmt() } return mem case OpArrayMake1: - return x.storeArgOrLoad(pos, b, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0)) + return x.storeArgOrLoad(pos, b, source.Args[0], mem, t.Elem(), storeOffset, 0, storeRc.at(t, 0)) case OpInt64Make: tHi, tLo := x.intPairTypes(t.Kind()) - mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tHi, storeOffset+x.hiOffset, 0, storeRc.next(tHi)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, tLo, storeOffset+x.lowOffset, 0, storeRc) case OpComplexMake: tPart := x.typs.Float32 @@ -781,25 +787,25 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, if wPart == 8 { tPart = x.typs.Float64 } - mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tPart, storeOffset, 0, storeRc.next(tPart)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, source.Args[1], mem, tPart, offset+wPart, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, tPart, storeOffset+wPart, 0, storeRc) case OpIMake: - mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.Uintptr, storeOffset, 0, storeRc.next(x.typs.Uintptr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.BytePtr, storeOffset+x.ptrSize, 0, storeRc) case OpStringMake: - mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, storeOffset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc) + return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, storeOffset+x.ptrSize, 0, storeRc) case OpSliceMake: - mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, storeOffset, 0, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() - mem = x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int)) - return x.storeArgOrLoad(pos, b, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc) + mem = x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, storeOffset+x.ptrSize, 0, storeRc.next(x.typs.Int)) + return x.storeArgOrLoad(pos, b, source.Args[2], mem, x.typs.Int, storeOffset+2*x.ptrSize, 0, storeRc) } // For nodes that cannot be taken apart -- OpSelectN, other structure selectors. @@ -809,12 +815,12 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == x.regSize { t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc) } eltRO := x.regWidth(elt) for i := int64(0); i < t.NumElem(); i++ { sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0)) + mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Width, loadRegOffset, storeRc.at(t, 0)) loadRegOffset += eltRO pos = pos.WithNotStmt() } @@ -842,13 +848,13 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, // of a *uint8, which does not succeed. t = removeTrivialWrapperTypes(t) // it could be a leaf type, but the "leaf" could be complex64 (for example) - return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc) + return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc) } for i := 0; i < t.NumFields(); i++ { fld := t.Field(i) sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source) - mem = x.storeArgOrLoad(pos, b, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) + mem = x.storeArgOrLoad(pos, b, sel, mem, fld.Type, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type)) loadRegOffset += x.regWidth(fld.Type) pos = pos.WithNotStmt() } @@ -860,48 +866,48 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, } tHi, tLo := x.intPairTypes(t.Kind()) sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) + mem = x.storeArgOrLoad(pos, b, sel, mem, tHi, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source) - return x.storeArgOrLoad(pos, b, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo)) + return x.storeArgOrLoad(pos, b, sel, mem, tLo, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo)) case types.TINTER: sel := source.Block.NewValue1(pos, OpITab, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpIData, x.typs.BytePtr, source) - return x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc) case types.TSTRING: sel := source.Block.NewValue1(pos, OpStringPtr, x.typs.BytePtr, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpStringLen, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+x.ptrSize, loadRegOffset+RO_string_len, storeRc) case types.TSLICE: et := types.NewPtr(t.Elem()) sel := source.Block.NewValue1(pos, OpSlicePtr, et, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, et, offset, loadRegOffset, storeRc.next(et)) + mem = x.storeArgOrLoad(pos, b, sel, mem, et, storeOffset, loadRegOffset, storeRc.next(et)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpSliceLen, x.typs.Int, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int)) sel = source.Block.NewValue1(pos, OpSliceCap, x.typs.Int, source) - return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc) case types.TCOMPLEX64: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float32, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, storeOffset, loadRegOffset, storeRc.next(x.typs.Float32)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float32, source) - return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, storeOffset+4, loadRegOffset+RO_complex_imag, storeRc) case types.TCOMPLEX128: sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float64, source) - mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64)) + mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, storeOffset, loadRegOffset, storeRc.next(x.typs.Float64)) pos = pos.WithNotStmt() sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float64, source) - return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc) + return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, storeOffset+8, loadRegOffset+RO_complex_imag, storeRc) } s := mem @@ -911,7 +917,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, if storeRc.hasRegs() { storeRc.addArg(source) } else { - dst := x.offsetFrom(b, storeRc.storeDest, offset, types.NewPtr(t)) + dst := x.offsetFrom(b, storeRc.storeDest, storeOffset, types.NewPtr(t)) s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) } if x.debug { diff --git a/test/abi/bad_internal_offsets.go b/test/abi/bad_internal_offsets.go new file mode 100644 index 0000000000..d396c1a60f --- /dev/null +++ b/test/abi/bad_internal_offsets.go @@ -0,0 +1,74 @@ +// compile + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 genChecker0 + +var FailCount int + +//go:noinline +func NoteFailure(fidx int, pkg string, pref string, parmNo int, _ uint64) { + FailCount += 1 + if FailCount > 10 { + panic("bad") + } +} + +//go:noinline +func NoteFailureElem(fidx int, pkg string, pref string, parmNo int, elem int, _ uint64) { + FailCount += 1 + if FailCount > 10 { + panic("bad") + } +} + +type StructF0S0 struct { + F0 int16 + F1 string + F2 StructF0S1 +} + +type StructF0S1 struct { + _ uint16 +} + +// 0 returns 3 params +//go:registerparams +//go:noinline +func Test0(p0 uint32, p1 StructF0S0, p2 int32) { + // consume some stack space, so as to trigger morestack + var pad [256]uint64 + pad[FailCount]++ + if p0 == 0 { + return + } + p1f0c := int16(-3096) + if p1.F0 != p1f0c { + NoteFailureElem(0, "genChecker0", "parm", 1, 0, pad[0]) + return + } + p1f1c := "f6ꂅ8ˋ<" + if p1.F1 != p1f1c { + NoteFailureElem(0, "genChecker0", "parm", 1, 1, pad[0]) + return + } + p1f2c := StructF0S1{} + if p1.F2 != p1f2c { + NoteFailureElem(0, "genChecker0", "parm", 1, 2, pad[0]) + return + } + p2f0c := int32(496713155) + if p2 != p2f0c { + NoteFailureElem(0, "genChecker0", "parm", 2, 0, pad[0]) + return + } + // recursive call + Test0(p0-1, p1, p2) + return + // 0 addr-taken params, 0 addr-taken returns +} -- GitLab From 9f5298ca6e7fc9c46c0a82bd7be39450ec48dcb5 Mon Sep 17 00:00:00 2001 From: David Chase Date: Sat, 6 Mar 2021 20:59:40 -0500 Subject: [PATCH 0254/1298] cmd/compile: fix confusion in generating SelectN index Old: return the ABI register index of the result (wrong!) New: return the index w/in sequence of result registers (right!) Fixed bug: genCaller0/genCaller0.go:43:9: internal compiler error: 'Caller0': panic during schedule while compiling Caller0: runtime error: index out of range [10] with length 9 Updates #44816. Change-Id: I1111e283658a2d6422986ae3d61bd95d1b9bde5e Reviewed-on: https://go-review.googlesource.com/c/go/+/299549 Trust: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index d4fa7f2b14..d7d7d3bc45 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -424,7 +424,11 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, } outParam := aux.abiInfo.OutParam(int(which)) if len(outParam.Registers) > 0 { - reg := int64(outParam.Registers[regOffset]) + firstReg := uint32(0) + for i := 0; i < int(which); i++ { + firstReg += uint32(len(aux.abiInfo.OutParam(i).Registers)) + } + reg := int64(regOffset + Abi1RO(firstReg)) if leaf.Block == call.Block { leaf.reset(OpSelectN) leaf.SetArgs1(call0) -- GitLab From 382851c1fd135a99efbe128a3be0ce466d42506f Mon Sep 17 00:00:00 2001 From: David Chase Date: Sun, 7 Mar 2021 14:00:10 -0500 Subject: [PATCH 0255/1298] cmd/compile: fix failure to communicate between ABIinfo producer&consumer ABI info producer and consumer had different ideas for register order for parameters. Includes a test, includes improvements to debugging output. Updates #44816. Change-Id: I4812976f7a6c08d6fc02aac1ec0544b1f141cca6 Reviewed-on: https://go-review.googlesource.com/c/go/+/299570 Trust: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/abi/abiutils.go | 77 ++++++++++++----- src/cmd/compile/internal/ssa/expand_calls.go | 83 ++++++++++--------- src/cmd/compile/internal/ssa/value.go | 4 +- .../compile/internal/test/abiutils_test.go | 6 +- src/cmd/internal/obj/x86/asm6.go | 2 +- test/abi/s_sif_sif.go | 37 +++++++++ 6 files changed, 142 insertions(+), 67 deletions(-) create mode 100644 test/abi/s_sif_sif.go diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index 7d5de1d528..ecde34313a 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -477,9 +477,9 @@ func (c *RegAmounts) regString(r RegIndex) string { return fmt.Sprintf("%d", r) } -// toString method renders an ABIParamAssignment in human-readable +// ToString method renders an ABIParamAssignment in human-readable // form, suitable for debugging or unit testing. -func (ri *ABIParamAssignment) toString(config *ABIConfig) string { +func (ri *ABIParamAssignment) ToString(config *ABIConfig, extra bool) string { regs := "R{" offname := "spilloffset" // offset is for spill for register(s) if len(ri.Registers) == 0 { @@ -487,19 +487,25 @@ func (ri *ABIParamAssignment) toString(config *ABIConfig) string { } for _, r := range ri.Registers { regs += " " + config.regAmounts.regString(r) + if extra { + regs += fmt.Sprintf("(%d)", r) + } + } + if extra { + regs += fmt.Sprintf(" | #I=%d, #F=%d", config.regAmounts.intRegs, config.regAmounts.floatRegs) } return fmt.Sprintf("%s } %s: %d typ: %v", regs, offname, ri.offset, ri.Type) } -// toString method renders an ABIParamResultInfo in human-readable +// String method renders an ABIParamResultInfo in human-readable // form, suitable for debugging or unit testing. func (ri *ABIParamResultInfo) String() string { res := "" for k, p := range ri.inparams { - res += fmt.Sprintf("IN %d: %s\n", k, p.toString(ri.config)) + res += fmt.Sprintf("IN %d: %s\n", k, p.ToString(ri.config, false)) } for k, r := range ri.outparams { - res += fmt.Sprintf("OUT %d: %s\n", k, r.toString(ri.config)) + res += fmt.Sprintf("OUT %d: %s\n", k, r.ToString(ri.config, false)) } res += fmt.Sprintf("offsetToSpillArea: %d spillAreaSize: %d", ri.offsetToSpillArea, ri.spillAreaSize) @@ -537,25 +543,54 @@ func (state *assignState) stackSlot(t *types.Type) int64 { return rv } -// allocateRegs returns a set of register indices for a parameter or result +// allocateRegs returns an ordered list of register indices for a parameter or result // that we've just determined to be register-assignable. The number of registers // needed is assumed to be stored in state.pUsed. -func (state *assignState) allocateRegs() []RegIndex { - regs := []RegIndex{} - - // integer - for r := state.rUsed.intRegs; r < state.rUsed.intRegs+state.pUsed.intRegs; r++ { - regs = append(regs, RegIndex(r)) +func (state *assignState) allocateRegs(regs []RegIndex, t *types.Type) []RegIndex { + if t.Width == 0 { + return regs } - state.rUsed.intRegs += state.pUsed.intRegs - - // floating - for r := state.rUsed.floatRegs; r < state.rUsed.floatRegs+state.pUsed.floatRegs; r++ { - regs = append(regs, RegIndex(r+state.rTotal.intRegs)) + ri := state.rUsed.intRegs + rf := state.rUsed.floatRegs + if t.IsScalar() || t.IsPtrShaped() { + if t.IsComplex() { + regs = append(regs, RegIndex(rf+state.rTotal.intRegs), RegIndex(rf+1+state.rTotal.intRegs)) + rf += 2 + } else if t.IsFloat() { + regs = append(regs, RegIndex(rf+state.rTotal.intRegs)) + rf += 1 + } else { + n := (int(t.Size()) + types.RegSize - 1) / types.RegSize + for i := 0; i < n; i++ { // looking ahead to really big integers + regs = append(regs, RegIndex(ri)) + ri += 1 + } + } + state.rUsed.intRegs = ri + state.rUsed.floatRegs = rf + return regs + } else { + typ := t.Kind() + switch typ { + case types.TARRAY: + for i := int64(0); i < t.NumElem(); i++ { + regs = state.allocateRegs(regs, t.Elem()) + } + return regs + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + regs = state.allocateRegs(regs, f.Type) + } + return regs + case types.TSLICE: + return state.allocateRegs(regs, synthSlice) + case types.TSTRING: + return state.allocateRegs(regs, synthString) + case types.TINTER: + return state.allocateRegs(regs, synthIface) + } } - state.rUsed.floatRegs += state.pUsed.floatRegs - - return regs + panic(fmt.Errorf("Was not expecting type %s", t)) } // regAllocate creates a register ABIParamAssignment object for a param @@ -571,7 +606,7 @@ func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn return ABIParamAssignment{ Type: t, Name: name, - Registers: state.allocateRegs(), + Registers: state.allocateRegs([]RegIndex{}, t), offset: int32(spillLoc), } } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index d7d7d3bc45..6e2004224f 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -303,7 +303,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, if x.debug { x.indent(3) defer x.indent(-3) - x.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset) + x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset) } var locs []LocalSlot leafType := leaf.Type @@ -581,7 +581,13 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t rts, offs := pa.RegisterTypesAndOffsets() last := loadRegOffset + x.regWidth(t) if offs[loadRegOffset] != 0 { - panic(fmt.Errorf("offset %d of requested register %d should be zero", offs[loadRegOffset], loadRegOffset)) + // Document the problem before panicking. + for i := 0; i < len(rts); i++ { + rt := rts[i] + off := offs[i] + fmt.Printf("rt=%s, off=%d, rt.Width=%d, rt.Align=%d\n", rt.String(), off, rt.Width, rt.Align) + } + panic(fmt.Errorf("offset %d of requested register %d should be zero, source=%s", offs[loadRegOffset], loadRegOffset, source.LongString())) } for i := loadRegOffset; i < last; i++ { rt := rts[i] @@ -704,7 +710,7 @@ func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t * if x.debug { x.indent(3) defer x.indent(-3) - fmt.Printf("storeOneArg(%s; %s; %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String()) + x.Printf("storeOneArg(%s; %s; %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String()) } w := x.commonArgs[selKey{source, argOffset, t.Width, t}] @@ -1388,14 +1394,8 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value { } case 1: r := pa.Registers[0] - i := x.f.ABISelf.FloatIndexFor(r) - // TODO seems like this has implications for debugging. How does this affect the location? - if i >= 0 { // float PR - v.Op = OpArgFloatReg - } else { - v.Op = OpArgIntReg - i = int64(r) - } + var i int64 + v.Op, i = ArgOpAndRegisterFor(r, x.f.ABISelf) v.Aux = &AuxNameOffset{v.Aux.(*ir.Name), 0} v.AuxInt = i @@ -1409,6 +1409,11 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value { // or rewrites it into a copy of the appropriate OpArgXXX. The actual OpArgXXX is determined by combining baseArg (an OpArg) // with offset, regOffset, and t to determine which portion of it to reference (either all or a part, in memory or in registers). func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value { + if x.debug { + x.indent(3) + defer x.indent(-3) + x.Printf("newArgToMemOrRegs(base=%s; toReplace=%s; t=%s; memOff=%d; regOff=%d)\n", baseArg.String(), toReplace.LongString(), t, offset, regOffset) + } key := selKey{baseArg, offset, t.Width, t} w := x.commonArgs[key] if w != nil { @@ -1432,28 +1437,27 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, toReplace.Aux = aux toReplace.AuxInt = auxInt toReplace.Type = t - x.commonArgs[key] = toReplace - return toReplace + w = toReplace } else { - w := baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux) - x.commonArgs[key] = w - if x.debug { - x.Printf("---new %s\n", w.LongString()) - } - if toReplace != nil { - toReplace.copyOf(w) - } - return w + w = baseArg.Block.NewValue0IA(pos, OpArg, t, auxInt, aux) + } + x.commonArgs[key] = w + if toReplace != nil { + toReplace.copyOf(w) } + if x.debug { + x.Printf("-->%s\n", w.LongString()) + } + return w } // Arg is in registers r := pa.Registers[regOffset] - auxInt := x.f.ABISelf.FloatIndexFor(r) - op := OpArgFloatReg - // TODO seems like this has implications for debugging. How does this affect the location? - if auxInt < 0 { // int (not float) parameter register - op = OpArgIntReg - auxInt = int64(r) + op, auxInt := ArgOpAndRegisterFor(r, x.f.ABISelf) + if op == OpArgIntReg && t.IsFloat() || op == OpArgFloatReg && t.IsInteger() { + fmt.Printf("pa=%v\nx.f.OwnAux.abiInfo=%s\n", + pa.ToString(x.f.ABISelf, true), + x.f.OwnAux.abiInfo.String()) + panic(fmt.Errorf("Op/Type mismatch, op=%s, type=%s", op.String(), t.String())) } aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset} if toReplace != nil && toReplace.Block == baseArg.Block { @@ -1461,24 +1465,23 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, toReplace.Aux = aux toReplace.AuxInt = auxInt toReplace.Type = t - x.commonArgs[key] = toReplace - return toReplace + w = toReplace } else { - w := baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) - if x.debug { - x.Printf("---new %s\n", w.LongString()) - } - x.commonArgs[key] = w - if toReplace != nil { - toReplace.copyOf(w) - } - return w + w = baseArg.Block.NewValue0IA(pos, op, t, auxInt, aux) + } + x.commonArgs[key] = w + if toReplace != nil { + toReplace.copyOf(w) } + if x.debug { + x.Printf("-->%s\n", w.LongString()) + } + return w + } // argOpAndRegisterFor converts an abi register index into an ssa Op and corresponding // arg register index. -// TODO could call this in at least two places earlier in this file. func ArgOpAndRegisterFor(r abi.RegIndex, abiConfig *abi.ABIConfig) (Op, int64) { i := abiConfig.FloatIndexFor(r) if i >= 0 { // float PR diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 6cc2b2ab8b..5a9779dd1e 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -198,12 +198,12 @@ func (v *Value) auxString() string { if v.Aux != nil { return fmt.Sprintf(" {%v}", v.Aux) } - case auxSymOff, auxCallOff, auxTypSize: + case auxSymOff, auxCallOff, auxTypSize, auxNameOffsetInt8: s := "" if v.Aux != nil { s = fmt.Sprintf(" {%v}", v.Aux) } - if v.AuxInt != 0 { + if v.AuxInt != 0 || opcodeTable[v.Op].auxType == auxNameOffsetInt8 { s += fmt.Sprintf(" [%v]", v.AuxInt) } return s diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go index 9a7d6d138c..f8d0af8d7a 100644 --- a/src/cmd/compile/internal/test/abiutils_test.go +++ b/src/cmd/compile/internal/test/abiutils_test.go @@ -170,9 +170,9 @@ func TestABIUtilsStruct2(t *testing.T) { exp := makeExpectedDump(` IN 0: R{ I0 } spilloffset: 0 typ: struct { int64; struct {} } IN 1: R{ I1 } spilloffset: 16 typ: struct { int64; struct {} } - IN 2: R{ I2 F0 } spilloffset: 32 typ: struct { float64; struct { int64; struct {} }; struct {} } - OUT 0: R{ I0 F0 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} } - OUT 1: R{ I1 F1 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} } + IN 2: R{ F0 I2 } spilloffset: 32 typ: struct { float64; struct { int64; struct {} }; struct {} } + OUT 0: R{ F0 I0 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} } + OUT 1: R{ F1 I1 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} } offsetToSpillArea: 0 spillAreaSize: 64 `) diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index fa670d5c18..52ac567a36 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -5306,7 +5306,7 @@ bad: } } - ctxt.Diag("invalid instruction: %v", p) + ctxt.Diag("%s: invalid instruction: %v", cursym.Name, p) } // byteswapreg returns a byte-addressable register (AX, BX, CX, DX) diff --git a/test/abi/s_sif_sif.go b/test/abi/s_sif_sif.go new file mode 100644 index 0000000000..f05f26f29f --- /dev/null +++ b/test/abi/s_sif_sif.go @@ -0,0 +1,37 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 + +// Test ensures that abi information producer and consumer agree about the +// order of registers for inputs. T's registers should be I0, F0, I1, F1. + +import "fmt" + +type P struct { + a int8 + x float64 +} + +type T struct { + d, e P +} + +//go:registerparams +//go:noinline +func G(t T) float64 { + return float64(t.d.a+t.e.a) + t.d.x + t.e.x +} + +func main() { + x := G(T{P{10, 20}, P{30, 40}}) + if x != 100.0 { + fmt.Printf("FAIL, Expected 100, got %f\n", x) + } +} -- GitLab From e4f3cfadf618df5135bf0952507ab491975cceb5 Mon Sep 17 00:00:00 2001 From: Fazlul Shahriar Date: Thu, 25 Feb 2021 15:16:25 -0500 Subject: [PATCH 0256/1298] net: don't append a dot to TXT records on Plan 9 TXT records are not domain names, so no need to call absDomainName. The output now matches the pure Go resolver. Fixes #44619 Change-Id: I1ebf09152ff5c0446d2e2b4c26671358892d9dc9 Reviewed-on: https://go-review.googlesource.com/c/go/+/296589 Reviewed-by: David du Colombier <0intro@gmail.com> Run-TryBot: David du Colombier <0intro@gmail.com> TryBot-Result: Go Bot Trust: David du Colombier <0intro@gmail.com> Trust: Ian Lance Taylor --- src/net/lookup_plan9.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go index 6a2d48eeda..5fc23f098b 100644 --- a/src/net/lookup_plan9.go +++ b/src/net/lookup_plan9.go @@ -308,7 +308,7 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err } for _, line := range lines { if i := bytealg.IndexByteString(line, '\t'); i >= 0 { - txt = append(txt, absDomainName([]byte(line[i+1:]))) + txt = append(txt, line[i+1:]) } } return -- GitLab From 18510ae88ffcb9c4a914805fde3e613539f9b6dc Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 7 Mar 2021 20:52:48 -0800 Subject: [PATCH 0257/1298] runtime, cmd/link/internal/ld: disable memory profiling when data unreachable If runtime.MemProfile is unreachable, default to not collecting any memory profiling samples, to save memory on the hash table. Fixes #42347 Change-Id: I9a4894a5fc77035fe59b1842e1ec77a1182e70c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/299671 Reviewed-by: Cherry Zhang Trust: Keith Randall --- src/cmd/link/internal/ld/ld_test.go | 100 ++++++++++++++++++++++++++++ src/cmd/link/internal/ld/lib.go | 12 ++++ src/runtime/mprof.go | 17 ++++- 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go index 836d9bff3d..f3725cbc6a 100644 --- a/src/cmd/link/internal/ld/ld_test.go +++ b/src/cmd/link/internal/ld/ld_test.go @@ -224,3 +224,103 @@ func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) { t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set") } } + +// TestMemProfileCheck tests that cmd/link sets +// runtime.disableMemoryProfiling if the runtime.MemProfile +// symbol is unreachable after deadcode (and not dynlinking). +// The runtime then uses that to set the default value of +// runtime.MemProfileRate, which this test checks. +func TestMemProfileCheck(t *testing.T) { + testenv.MustHaveGoBuild(t) + t.Parallel() + + tests := []struct { + name string + prog string + wantOut string + }{ + { + "no_memprofile", + ` +package main +import "runtime" +func main() { + println(runtime.MemProfileRate) +} +`, + "0", + }, + { + "with_memprofile", + ` +package main +import "runtime" +func main() { + runtime.MemProfile(nil, false) + println(runtime.MemProfileRate) +} +`, + "524288", + }, + { + "with_memprofile_indirect", + ` +package main +import "runtime" +var f = runtime.MemProfile +func main() { + if f == nil { + panic("no f") + } + println(runtime.MemProfileRate) +} +`, + "524288", + }, + { + "with_memprofile_runtime_pprof", + ` +package main +import "runtime" +import "runtime/pprof" +func main() { + _ = pprof.Profiles() + println(runtime.MemProfileRate) +} +`, + "524288", + }, + { + "with_memprofile_http_pprof", + ` +package main +import "runtime" +import _ "net/http/pprof" +func main() { + println(runtime.MemProfileRate) +} +`, + "524288", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + tempDir := t.TempDir() + src := filepath.Join(tempDir, "x.go") + if err := ioutil.WriteFile(src, []byte(tt.prog), 0644); err != nil { + t.Fatal(err) + } + cmd := exec.Command(testenv.GoToolPath(t), "run", src) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(err) + } + got := strings.TrimSpace(string(out)) + if got != tt.wantOut { + t.Errorf("got %q; want %q", got, tt.wantOut) + } + }) + } +} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 517b0f6930..4c69d24354 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -790,6 +790,18 @@ func (ctxt *Link) linksetup() { sb.SetSize(0) sb.AddUint8(uint8(objabi.GOARM)) } + + // Set runtime.disableMemoryProfiling bool if + // runtime.MemProfile is not retained in the binary after + // deadcode (and we're not dynamically linking). + memProfile := ctxt.loader.Lookup("runtime.MemProfile", sym.SymVerABIInternal) + if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() { + memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0) + sb := ctxt.loader.MakeSymbolUpdater(memProfSym) + sb.SetType(sym.SDATA) + sb.SetSize(0) + sb.AddUint8(1) // true bool + } } else { // If OTOH the module does not contain the runtime package, // create a local symbol for the moduledata. diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index c94b8f7cae..1156329615 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -490,7 +490,22 @@ func (r *StackRecord) Stack() []uintptr { // memory profiling rate should do so just once, as early as // possible in the execution of the program (for example, // at the beginning of main). -var MemProfileRate int = 512 * 1024 +var MemProfileRate int = defaultMemProfileRate(512 * 1024) + +// defaultMemProfileRate returns 0 if disableMemoryProfiling is set. +// It exists primarily for the godoc rendering of MemProfileRate +// above. +func defaultMemProfileRate(v int) int { + if disableMemoryProfiling { + return 0 + } + return v +} + +// disableMemoryProfiling is set by the linker if runtime.MemProfile +// is not used and the link type guarantees nobody else could use it +// elsewhere. +var disableMemoryProfiling bool // A MemProfileRecord describes the live objects allocated // by a particular call sequence (stack trace). -- GitLab From 48ddf7012875014d3cab4a02002799a520b087a1 Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Tue, 5 Jan 2021 16:44:43 -0600 Subject: [PATCH 0258/1298] cmd/asm,cmd/compile: support 5 operand RLWNM/RLWMI on ppc64 These instructions are actually 5 argument opcodes as specified by the ISA. Prior to this patch, the MB and ME arguments were merged into a single bitmask operand to workaround the limitations of the ppc64 assembler backend. This limitation no longer exists. Thus, we can pass operands for these opcodes without having to merge the MB and ME arguments in the assembler frontend or compiler backend. Likewise, support for 4 operand variants is unchanged. Change-Id: Ib086774f3581edeaadfd2190d652aaaa8a90daeb Reviewed-on: https://go-review.googlesource.com/c/go/+/298750 Reviewed-by: Lynn Boger Reviewed-by: Carlos Eduardo Seo Trust: Carlos Eduardo Seo --- src/cmd/asm/internal/asm/asm.go | 14 +++------- src/cmd/asm/internal/asm/testdata/ppc64.s | 6 +++++ src/cmd/compile/internal/ppc64/ssa.go | 8 +++--- src/cmd/internal/obj/ppc64/asm9.go | 13 +++++++++ test/codegen/rotate.go | 32 +++++++++++------------ test/codegen/shift.go | 32 +++++++++++------------ 6 files changed, 58 insertions(+), 47 deletions(-) diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 06867cd507..340f188924 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -799,19 +799,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { p.errorf("can't handle %s instruction with 4 operands", op) return case 5: - if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) { - // Always reg, reg, con, con, reg. (con, con is a 'mask'). + if p.arch.Family == sys.PPC64 { prog.From = a[0] + // Second arg is always a register type on ppc64. prog.Reg = p.getRegister(prog, op, &a[1]) - mask1 := p.getConstant(prog, op, &a[2]) - mask2 := p.getConstant(prog, op, &a[3]) - var mask uint32 - if mask1 < mask2 { - mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2)) - } else { - mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1))) - } - prog.SetFrom3Const(int64(mask)) + prog.SetRestArgs([]obj.Addr{a[2], a[3]}) prog.To = a[4] break } diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s index 8f6eb14f73..a818c0e789 100644 --- a/src/cmd/asm/internal/asm/testdata/ppc64.s +++ b/src/cmd/asm/internal/asm/testdata/ppc64.s @@ -280,11 +280,17 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 ROTLW R3, R4, R5 // 5c85183e EXTSWSLI $3, R4, R5 // 7c851ef4 RLWMI $7, R3, $65535, R6 // 50663c3e + RLWMI $7, R3, $16, $31, R6 // 50663c3e RLWMICC $7, R3, $65535, R6 // 50663c3f + RLWMICC $7, R3, $16, $31, R6 // 50663c3f RLWNM $3, R4, $7, R6 // 54861f7e + RLWNM $3, R4, $29, $31, R6 // 54861f7e RLWNM R3, R4, $7, R6 // 5c861f7e + RLWNM R3, R4, $29, $31, R6 // 5c861f7e RLWNMCC $3, R4, $7, R6 // 54861f7f + RLWNMCC $3, R4, $29, $31, R6 // 54861f7f RLWNMCC R3, R4, $7, R6 // 5c861f7f + RLWNMCC R3, R4, $29, $31, R6 // 5c861f7f RLDMI $0, R4, $7, R6 // 7886076c RLDMICC $0, R4, $7, R6 // 7886076d RLDIMI $0, R4, $7, R6 // 788601cc diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index f984079c4b..2bae35bf44 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -653,21 +653,21 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // Auxint holds encoded rotate + mask case ssa.OpPPC64RLWINM, ssa.OpPPC64RLWMI: - rot, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt) + rot, mb, me, _ := ssa.DecodePPC64RotateMask(v.AuxInt) p := s.Prog(v.Op.Asm()) p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} p.Reg = v.Args[0].Reg() p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(rot)} - p.SetFrom3Const(int64(mask)) + p.SetRestArgs([]obj.Addr{{Type: obj.TYPE_CONST, Offset: mb}, {Type: obj.TYPE_CONST, Offset: me}}) // Auxint holds mask case ssa.OpPPC64RLWNM: - _, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt) + _, mb, me, _ := ssa.DecodePPC64RotateMask(v.AuxInt) p := s.Prog(v.Op.Asm()) p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} p.Reg = v.Args[0].Reg() p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()} - p.SetFrom3Const(int64(mask)) + p.SetRestArgs([]obj.Addr{{Type: obj.TYPE_CONST, Offset: mb}, {Type: obj.TYPE_CONST, Offset: me}}) case ssa.OpPPC64MADDLD: r := v.Reg() diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 7985f050de..648a41b5c7 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -181,7 +181,9 @@ var optab = []Optab{ {as: ASRAD, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 56, size: 4}, {as: ASRAD, a1: C_SCON, a6: C_REG, type_: 56, size: 4}, {as: ARLWMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 62, size: 4}, + {as: ARLWMI, a1: C_SCON, a2: C_REG, a3: C_SCON, a4: C_SCON, a6: C_REG, type_: 102, size: 4}, {as: ARLWMI, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 63, size: 4}, + {as: ARLWMI, a1: C_REG, a2: C_REG, a3: C_SCON, a4: C_SCON, a6: C_REG, type_: 103, size: 4}, {as: ACLRLSLWI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 62, size: 4}, {as: ARLDMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 30, size: 4}, {as: ARLDC, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 29, size: 4}, @@ -3861,6 +3863,17 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { } case 101: o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(0), uint32(p.From.Reg)) + + case 102: /* RLWMI $sh,rs,$mb,$me,rt (M-form opcode)*/ + mb := uint32(c.regoff(&p.RestArgs[0].Addr)) + me := uint32(c.regoff(&p.RestArgs[1].Addr)) + sh := uint32(c.regoff(&p.From)) + o1 = OP_RLW(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), sh, mb, me) + + case 103: /* RLWMI rb,rs,$mb,$me,rt (M-form opcode)*/ + mb := uint32(c.regoff(&p.RestArgs[0].Addr)) + me := uint32(c.regoff(&p.RestArgs[1].Addr)) + o1 = OP_RLW(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From.Reg), mb, me) } out[0] = o1 diff --git a/test/codegen/rotate.go b/test/codegen/rotate.go index e0bcd0abbc..bf4bcc4fc3 100644 --- a/test/codegen/rotate.go +++ b/test/codegen/rotate.go @@ -176,38 +176,38 @@ func f32(x uint32) uint32 { func checkMaskedRotate32(a []uint32, r int) { i := 0 - // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]16711680, R[0-9]+" - // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]16711680, R[0-9]+" + // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]8, [$]15, R[0-9]+" + // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]8, [$]15, R[0-9]+" a[i] = bits.RotateLeft32(a[i], 16) & 0xFF0000 i++ - // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]16711680, R[0-9]+" - // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]16711680, R[0-9]+" + // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]8, [$]15, R[0-9]+" + // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]8, [$]15, R[0-9]+" a[i] = bits.RotateLeft32(a[i]&0xFF, 16) i++ - // ppc64le: "RLWNM\t[$]4, R[0-9]+, [$]4080, R[0-9]+" - // ppc64: "RLWNM\t[$]4, R[0-9]+, [$]4080, R[0-9]+" + // ppc64le: "RLWNM\t[$]4, R[0-9]+, [$]20, [$]27, R[0-9]+" + // ppc64: "RLWNM\t[$]4, R[0-9]+, [$]20, [$]27, R[0-9]+" a[i] = bits.RotateLeft32(a[i], 4) & 0xFF0 i++ - // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]255, R[0-9]+" - // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]255, R[0-9]+" + // ppc64le: "RLWNM\t[$]16, R[0-9]+, [$]24, [$]31, R[0-9]+" + // ppc64: "RLWNM\t[$]16, R[0-9]+, [$]24, [$]31, R[0-9]+" a[i] = bits.RotateLeft32(a[i]&0xFF0000, 16) i++ - // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]16711680, R[0-9]+" - // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]16711680, R[0-9]+" + // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]8, [$]15, R[0-9]+" + // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]8, [$]15, R[0-9]+" a[i] = bits.RotateLeft32(a[i], r) & 0xFF0000 i++ - // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]65280, R[0-9]+" - // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]65280, R[0-9]+" + // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]16, [$]23, R[0-9]+" + // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]16, [$]23, R[0-9]+" a[i] = bits.RotateLeft32(a[3], r) & 0xFF00 i++ - // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]4293922815, R[0-9]+" - // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]4293922815, R[0-9]+" + // ppc64le: "RLWNM\tR[0-9]+, R[0-9]+, [$]20, [$]11, R[0-9]+" + // ppc64: "RLWNM\tR[0-9]+, R[0-9]+, [$]20, [$]11, R[0-9]+" a[i] = bits.RotateLeft32(a[3], r) & 0xFFF00FFF i++ - // ppc64le: "RLWNM\t[$]4, R[0-9]+, [$]4293922815, R[0-9]+" - // ppc64: "RLWNM\t[$]4, R[0-9]+, [$]4293922815, R[0-9]+" + // ppc64le: "RLWNM\t[$]4, R[0-9]+, [$]20, [$]11, R[0-9]+" + // ppc64: "RLWNM\t[$]4, R[0-9]+, [$]20, [$]11, R[0-9]+" a[i] = bits.RotateLeft32(a[3], 4) & 0xFFF00FFF i++ } diff --git a/test/codegen/shift.go b/test/codegen/shift.go index d19a1984c1..ab0ffc2e13 100644 --- a/test/codegen/shift.go +++ b/test/codegen/shift.go @@ -240,12 +240,12 @@ func checkWidenAfterShift(v int64, u uint64) (int64, uint64) { func checkShiftAndMask32(v []uint32) { i := 0 - // ppc64le: "RLWNM\t[$]24, R[0-9]+, [$]1044480, R[0-9]+" - // ppc64: "RLWNM\t[$]24, R[0-9]+, [$]1044480, R[0-9]+" + // ppc64le: "RLWNM\t[$]24, R[0-9]+, [$]12, [$]19, R[0-9]+" + // ppc64: "RLWNM\t[$]24, R[0-9]+, [$]12, [$]19, R[0-9]+" v[i] = (v[i] & 0xFF00000) >> 8 i++ - // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]1020, R[0-9]+" - // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]1020, R[0-9]+" + // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]22, [$]29, R[0-9]+" + // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]22, [$]29, R[0-9]+" v[i] = (v[i] & 0xFF00) >> 6 i++ // ppc64le: "MOVW\tR0" @@ -256,12 +256,12 @@ func checkShiftAndMask32(v []uint32) { // ppc64: "MOVW\tR0" v[i] = (v[i] & 0xF000000) >> 28 i++ - // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]255, R[0-9]+" - // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]255, R[0-9]+" + // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]24, [$]31, R[0-9]+" + // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]24, [$]31, R[0-9]+" v[i] = (v[i] >> 6) & 0xFF i++ - // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]1044480, R[0-9]+" - // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]1044480, R[0-9]+" + // ppc64le: "RLWNM\t[$]26, R[0-9]+, [$]12, [$]19, R[0-9]+" + // ppc64: "RLWNM\t[$]26, R[0-9]+, [$]12, [$]19, R[0-9]+" v[i] = (v[i] >> 6) & 0xFF000 i++ // ppc64le: "MOVW\tR0" @@ -275,16 +275,16 @@ func checkShiftAndMask32(v []uint32) { } func checkMergedShifts32(a [256]uint32, b [256]uint64, u uint32, v uint32) { - //ppc64le: -"CLRLSLDI", "RLWNM\t[$]10, R[0-9]+, [$]1020, R[0-9]+" - //ppc64: -"CLRLSLDI", "RLWNM\t[$]10, R[0-9]+, [$]1020, R[0-9]+" + //ppc64le: -"CLRLSLDI", "RLWNM\t[$]10, R[0-9]+, [$]22, [$]29, R[0-9]+" + //ppc64: -"CLRLSLDI", "RLWNM\t[$]10, R[0-9]+, [$]22, [$]29, R[0-9]+" a[0] = a[uint8(v>>24)] - //ppc64le: -"CLRLSLDI", "RLWNM\t[$]11, R[0-9]+, [$]2040, R[0-9]+" - //ppc64: -"CLRLSLDI", "RLWNM\t[$]11, R[0-9]+, [$]2040, R[0-9]+" + //ppc64le: -"CLRLSLDI", "RLWNM\t[$]11, R[0-9]+, [$]21, [$]28, R[0-9]+" + //ppc64: -"CLRLSLDI", "RLWNM\t[$]11, R[0-9]+, [$]21, [$]28, R[0-9]+" b[0] = b[uint8(v>>24)] - //ppc64le: -"CLRLSLDI", "RLWNM\t[$]15, R[0-9]+, [$]2040, R[0-9]+" - //ppc64: -"CLRLSLDI", "RLWNM\t[$]15, R[0-9]+, [$]2040, R[0-9]+" + //ppc64le: -"CLRLSLDI", "RLWNM\t[$]15, R[0-9]+, [$]21, [$]28, R[0-9]+" + //ppc64: -"CLRLSLDI", "RLWNM\t[$]15, R[0-9]+, [$]21, [$]28, R[0-9]+" b[1] = b[(v>>20)&0xFF] - //ppc64le: -"SLD", "RLWNM\t[$]10, R[0-9]+, [$]1016, R[0-9]+" - //ppc64: -"SLD", "RLWNM\t[$]10, R[0-9]+, [$]1016, R[0-9]+" + //ppc64le: -"SLD", "RLWNM\t[$]10, R[0-9]+, [$]22, [$]28, R[0-9]+" + //ppc64: -"SLD", "RLWNM\t[$]10, R[0-9]+, [$]22, [$]28, R[0-9]+" b[2] = b[v>>25] } -- GitLab From 142a76530cf610fe02d151727fa0d8038c552127 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 9 Mar 2021 14:22:38 -0500 Subject: [PATCH 0259/1298] go/types: improve the positioning of broken import errors The heuristic gopls uses to guess error spans can get tripped-up on certain valid characters in an import path (for example '-'). Update the error for broken imports to capture the full import path span, so that gopls doesn't need to rely on heuristics. Change-Id: Ieb8e0dce11933643f701b32271ff5f3477fecaaa Reviewed-on: https://go-review.googlesource.com/c/go/+/300169 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/resolver.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 763ea48d38..8e67237446 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -130,7 +130,7 @@ func (check *Checker) filename(fileNo int) string { return fmt.Sprintf("file[%d]", fileNo) } -func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package { +func (check *Checker) importPackage(at positioner, path, dir string) *Package { // If we already have a package for the given (path, dir) // pair, use it instead of doing a full import. // Checker.impMap only caches packages that are marked Complete @@ -170,7 +170,7 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package { imp = nil // create fake package below } if err != nil { - check.errorf(atPos(pos), _BrokenImport, "could not import %s (%s)", path, err) + check.errorf(at, _BrokenImport, "could not import %s (%s)", path, err) if imp == nil { // create a new fake package // come up with a sensible package name (heuristic) @@ -254,7 +254,7 @@ func (check *Checker) collectObjects() { return } - imp := check.importPackage(d.spec.Path.Pos(), path, fileDir) + imp := check.importPackage(d.spec.Path, path, fileDir) if imp == nil { return } -- GitLab From acd7cb5887f486558fbcd517ed636a96447d695d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 25 Feb 2021 14:54:04 -0800 Subject: [PATCH 0260/1298] cmd/compile/internal/types2: better error reporting framework (starting point) Until now, errors which came with additional details (e.g., a declaration cycle error followed by the list of objects involved in the cycle, one per line) were reported as an ordinary error followed by "secondary" errors, with the secondary errors marked as such by having a tab-indented error message. This approach often required clients to filter these secondary errors (as they are not new errors, they are just clarifying a previously reported error). This CL introduces a new internal error_ type which permits accumulating various error information that may then be reported as a single error. Change-Id: I25b2f094facd37e12737e517f7ef8853d465ff77 Reviewed-on: https://go-review.googlesource.com/c/go/+/296689 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/irgen.go | 8 -- src/cmd/compile/internal/types2/check_test.go | 6 +- src/cmd/compile/internal/types2/decl.go | 30 ++++--- src/cmd/compile/internal/types2/errors.go | 89 ++++++++++++++++--- .../compile/internal/types2/errors_test.go | 20 +++++ src/cmd/compile/internal/types2/initorder.go | 10 ++- src/cmd/compile/internal/types2/labels.go | 7 +- src/cmd/compile/internal/types2/resolver.go | 18 ++-- src/cmd/compile/internal/types2/stmt.go | 18 ++-- src/cmd/compile/internal/types2/typexpr.go | 24 +++-- 10 files changed, 166 insertions(+), 64 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 06b234c31d..2de8c3fa60 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -41,14 +41,6 @@ func check2(noders []*noder) { CompilerErrorMessages: true, // use error strings matching existing compiler errors Error: func(err error) { terr := err.(types2.Error) - if len(terr.Msg) > 0 && terr.Msg[0] == '\t' { - // types2 reports error clarifications via separate - // error messages which are indented with a tab. - // Ignore them to satisfy tools and tests that expect - // only one error in such cases. - // TODO(gri) Need to adjust error reporting in types2. - return - } base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg) }, Importer: &gcimports{ diff --git a/src/cmd/compile/internal/types2/check_test.go b/src/cmd/compile/internal/types2/check_test.go index 9c1d278520..fc6f46b4b8 100644 --- a/src/cmd/compile/internal/types2/check_test.go +++ b/src/cmd/compile/internal/types2/check_test.go @@ -146,11 +146,7 @@ func checkFiles(t *testing.T, sources []string, goVersion string, colDelta uint, t.Error(err) return } - // Ignore secondary error messages starting with "\t"; - // they are clarifying messages for a primary error. - if !strings.Contains(err.Error(), ": \t") { - errlist = append(errlist, err) - } + errlist = append(errlist, err) } conf.Check(pkgName, files, nil) diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index f0a037adb0..3528669bf9 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -11,12 +11,12 @@ import ( "go/constant" ) -func (check *Checker) reportAltDecl(obj Object) { +func (err *error_) recordAltDecl(obj Object) { if pos := obj.Pos(); pos.IsKnown() { // We use "other" rather than "previous" here because // the first declaration seen may not be textually // earlier in the source. - check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented + err.errorf(pos, "other declaration of %s", obj.Name()) } } @@ -27,8 +27,10 @@ func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syn // binding." if obj.Name() != "_" { if alt := scope.Insert(obj); alt != nil { - check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) + var err error_ + err.errorf(obj, "%s redeclared in this block", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) return } obj.setScopePos(pos) @@ -364,20 +366,22 @@ func (check *Checker) cycleError(cycle []Object) { // cycle? That would be more consistent with other error messages. i := firstInSrc(cycle) obj := cycle[i] + var err error_ if check.conf.CompilerErrorMessages { - check.errorf(obj.Pos(), "invalid recursive type %s", obj.Name()) + err.errorf(obj, "invalid recursive type %s", obj.Name()) } else { - check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name()) + err.errorf(obj, "illegal cycle in declaration of %s", obj.Name()) } for range cycle { - check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented + err.errorf(obj, "%s refers to", obj.Name()) i++ if i >= len(cycle) { i = 0 } obj = cycle[i] } - check.errorf(obj.Pos(), "\t%s", obj.Name()) + err.errorf(obj, "%s", obj.Name()) + check.report(&err) } // TODO(gri) This functionality should probably be with the Pos implementation. @@ -787,19 +791,21 @@ func (check *Checker) collectMethods(obj *TypeName) { // to it must be unique." assert(m.name != "_") if alt := mset.insert(m); alt != nil { + var err error_ switch alt.(type) { case *Var: - check.errorf(m.pos, "field and method with the same name %s", m.name) + err.errorf(m.pos, "field and method with the same name %s", m.name) case *Func: if check.conf.CompilerErrorMessages { - check.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name) + err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name) } else { - check.errorf(m.pos, "method %s already declared for %s", m.name, obj) + err.errorf(m.pos, "method %s already declared for %s", m.name, obj) } default: unreachable() } - check.reportAltDecl(alt) + err.recordAltDecl(alt) + check.report(&err) continue } diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go index 62b1d39d83..01df50c8e3 100644 --- a/src/cmd/compile/internal/types2/errors.go +++ b/src/cmd/compile/internal/types2/errors.go @@ -29,19 +29,61 @@ func unreachable() { panic("unreachable") } -func (check *Checker) qualifier(pkg *Package) string { - // Qualify the package unless it's the package being type-checked. - if pkg != check.pkg { - // If the same package name was used by multiple packages, display the full path. - if check.pkgCnt[pkg.name] > 1 { - return strconv.Quote(pkg.path) +// An error_ represents a type-checking error. +// To report an error_, call Checker.report. +type error_ struct { + desc []errorDesc + soft bool // TODO(gri) eventually determine this from an error code +} + +// An errorDesc describes part of a type-checking error. +type errorDesc struct { + pos syntax.Pos + format string + args []interface{} +} + +func (err *error_) empty() bool { + return err.desc == nil +} + +func (err *error_) pos() syntax.Pos { + if err.empty() { + return nopos + } + return err.desc[0].pos +} + +func (err *error_) msg(qf Qualifier) string { + if err.empty() { + return "no error" + } + var buf bytes.Buffer + for i := range err.desc { + p := &err.desc[i] + if i > 0 { + fmt.Fprintf(&buf, "\n\t%s: ", p.pos) } - return pkg.name + buf.WriteString(sprintf(qf, p.format, p.args...)) } - return "" + return buf.String() } -func (check *Checker) sprintf(format string, args ...interface{}) string { +// String is for testing. +func (err *error_) String() string { + if err.empty() { + return "no error" + } + return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil)) +} + +// errorf adds formatted error information to err. +// It may be called multiple times to provide additional information. +func (err *error_) errorf(at poser, format string, args ...interface{}) { + err.desc = append(err.desc, errorDesc{posFor(at), format, args}) +} + +func sprintf(qf Qualifier, format string, args ...interface{}) string { for i, arg := range args { switch a := arg.(type) { case nil: @@ -49,21 +91,44 @@ func (check *Checker) sprintf(format string, args ...interface{}) string { case operand: panic("internal error: should always pass *operand") case *operand: - arg = operandString(a, check.qualifier) + arg = operandString(a, qf) case syntax.Pos: arg = a.String() case syntax.Expr: arg = syntax.String(a) case Object: - arg = ObjectString(a, check.qualifier) + arg = ObjectString(a, qf) case Type: - arg = TypeString(a, check.qualifier) + arg = TypeString(a, qf) } args[i] = arg } return fmt.Sprintf(format, args...) } +func (check *Checker) qualifier(pkg *Package) string { + // Qualify the package unless it's the package being type-checked. + if pkg != check.pkg { + // If the same package name was used by multiple packages, display the full path. + if check.pkgCnt[pkg.name] > 1 { + return strconv.Quote(pkg.path) + } + return pkg.name + } + return "" +} + +func (check *Checker) sprintf(format string, args ...interface{}) string { + return sprintf(check.qualifier, format, args...) +} + +func (check *Checker) report(err *error_) { + if err.empty() { + panic("internal error: reporting no error") + } + check.err(err.pos(), err.msg(check.qualifier), err.soft) +} + func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) { fmt.Printf("%s:\t%s%s\n", pos, diff --git a/src/cmd/compile/internal/types2/errors_test.go b/src/cmd/compile/internal/types2/errors_test.go index cb21ff1ad3..e1f0e83fc9 100644 --- a/src/cmd/compile/internal/types2/errors_test.go +++ b/src/cmd/compile/internal/types2/errors_test.go @@ -6,6 +6,26 @@ package types2 import "testing" +func TestError(t *testing.T) { + var err error_ + want := "no error" + if got := err.String(); got != want { + t.Errorf("empty error: got %q, want %q", got, want) + } + + want = ": foo 42" + err.errorf(nopos, "foo %d", 42) + if got := err.String(); got != want { + t.Errorf("simple error: got %q, want %q", got, want) + } + + want = ": foo 42\n\t: bar 43" + err.errorf(nopos, "bar %d", 43) + if got := err.String(); got != want { + t.Errorf("simple error: got %q, want %q", got, want) + } +} + func TestStripAnnotations(t *testing.T) { for _, test := range []struct { in, want string diff --git a/src/cmd/compile/internal/types2/initorder.go b/src/cmd/compile/internal/types2/initorder.go index a9cabecdf2..4081627666 100644 --- a/src/cmd/compile/internal/types2/initorder.go +++ b/src/cmd/compile/internal/types2/initorder.go @@ -151,18 +151,20 @@ func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool // reportCycle reports an error for the given cycle. func (check *Checker) reportCycle(cycle []Object) { obj := cycle[0] + var err error_ if check.conf.CompilerErrorMessages { - check.errorf(obj, "initialization loop for %s", obj.Name()) + err.errorf(obj, "initialization loop for %s", obj.Name()) } else { - check.errorf(obj, "initialization cycle for %s", obj.Name()) + err.errorf(obj, "initialization cycle for %s", obj.Name()) } // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n for i := len(cycle) - 1; i >= 0; i-- { - check.errorf(obj, "\t%s refers to", obj.Name()) // secondary error, \t indented + err.errorf(obj, "%s refers to", obj.Name()) obj = cycle[i] } // print cycle[0] again to close the cycle - check.errorf(obj, "\t%s", obj.Name()) + err.errorf(obj, "%s", obj.Name()) + check.report(&err) } // ---------------------------------------------------------------------------- diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go index b20b454dea..cbbd65aa9a 100644 --- a/src/cmd/compile/internal/types2/labels.go +++ b/src/cmd/compile/internal/types2/labels.go @@ -128,8 +128,11 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab if name := s.Label.Value; name != "_" { lbl := NewLabel(s.Label.Pos(), check.pkg, name) if alt := all.Insert(lbl); alt != nil { - check.softErrorf(lbl.pos, "label %s already declared", name) - check.reportAltDecl(alt) + var err error_ + err.soft = true + err.errorf(lbl.pos, "label %s already declared", name) + err.recordAltDecl(alt) + check.report(&err) // ok to continue } else { b.insert(s) diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index 44fa51a8e5..fe551525c6 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -305,8 +305,10 @@ func (check *Checker) collectObjects() { // the object may be imported into more than one file scope // concurrently. See issue #32154.) if alt := fileScope.Insert(obj); alt != nil { - check.errorf(s.LocalPkgName, "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) + var err error_ + err.errorf(s.LocalPkgName, "%s redeclared in this block", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) } else { check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName } @@ -456,14 +458,16 @@ func (check *Checker) collectObjects() { for _, scope := range fileScopes { for _, obj := range scope.elems { if alt := pkg.scope.Lookup(obj.Name()); alt != nil { + var err error_ if pkg, ok := obj.(*PkgName); ok { - check.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported()) - check.reportAltDecl(pkg) + err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported()) + err.recordAltDecl(pkg) } else { - check.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) - // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything - check.reportAltDecl(obj) + err.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) + // TODO(gri) dot-imported objects don't have a position; recordAltDecl won't print anything + err.recordAltDecl(obj) } + check.report(&err) } } } diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 490cd0fc19..21244f6065 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -253,8 +253,10 @@ L: // (quadratic algorithm, but these lists tend to be very short) for _, vt := range seen[val] { if check.identical(v.typ, vt.typ) { - check.errorf(&v, "duplicate case %s in expression switch", &v) - check.error(vt.pos, "\tprevious case") // secondary error, \t indented + var err error_ + err.errorf(&v, "duplicate case %s in expression switch", &v) + err.errorf(vt.pos, "previous case") + check.report(&err) continue L } } @@ -282,8 +284,10 @@ L: if T != nil { Ts = T.String() } - check.errorf(e, "duplicate case %s in type switch", Ts) - check.error(pos, "\tprevious case") // secondary error, \t indented + var err error_ + err.errorf(e, "duplicate case %s in type switch", Ts) + err.errorf(pos, "previous case") + check.report(&err) continue L } } @@ -430,8 +434,10 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // with the same name as a result parameter is in scope at the place of the return." for _, obj := range res.vars { if alt := check.lookup(obj.name); alt != nil && alt != obj { - check.errorf(s, "result parameter %s not in scope at return", obj.name) - check.errorf(alt, "\tinner declaration of %s", obj) + var err error_ + err.errorf(s, "result parameter %s not in scope at return", obj.name) + err.errorf(alt, "inner declaration of %s", obj) + check.report(&err) // ok to continue } } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 02f9b2804d..177fcf4215 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -352,8 +352,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true) results, _ := check.collectParams(scope, ftyp.ResultList, nil, false) scope.Squash(func(obj, alt Object) { - check.errorf(obj, "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) + var err error_ + err.errorf(obj, "%s redeclared in this block", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) }) if recvPar != nil { @@ -796,8 +798,10 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool { if alt := oset.insert(obj); alt != nil { - check.errorf(pos, "%s redeclared", obj.Name()) - check.reportAltDecl(alt) + var err error_ + err.errorf(pos, "%s redeclared", obj.Name()) + err.recordAltDecl(alt) + check.report(&err) return false } return true @@ -940,8 +944,10 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { methods = append(methods, m) mpos[m] = pos case explicit: - check.errorf(pos, "duplicate method %s", m.name) - check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) default: // We have a duplicate method name in an embedded (not explicitly declared) method. // Check method signatures after all types are computed (issue #33656). @@ -950,8 +956,10 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // error message. check.atEnd(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { - check.errorf(pos, "duplicate method %s", m.name) - check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented + var err error_ + err.errorf(pos, "duplicate method %s", m.name) + err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) + check.report(&err) } }) } -- GitLab From 41245ab28390fed22ba03ee87c0e3db97b16c73b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 9 Mar 2021 17:14:15 -0800 Subject: [PATCH 0261/1298] cmd/compile/internal/types2: remove concept of finals This is a 1:1 port of the respective change in go/types in https://golang.org/cl/299590. Change-Id: I65ad723f2e21e3d95fc0b94665e0121e31871a48 Reviewed-on: https://go-review.googlesource.com/c/go/+/300250 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/check.go | 21 --------------------- src/cmd/compile/internal/types2/typexpr.go | 12 ++++++------ 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 95fb4e1076..c853925a2a 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -107,7 +107,6 @@ type Checker struct { methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods untyped map[syntax.Expr]exprInfo // map of expressions without final type delayed []func() // stack of delayed action segments; segments are processed in FIFO order - finals []func() // list of final actions; processed at the end of type-checking the current set of files objPath []Object // path of object dependencies during type inference (for cycle reporting) // context within which the current object is type-checked @@ -147,14 +146,6 @@ func (check *Checker) later(f func()) { check.delayed = append(check.delayed, f) } -// atEnd adds f to the list of actions processed at the end -// of type-checking, before initialization order computation. -// Actions added by atEnd are processed after any actions -// added by later. -func (check *Checker) atEnd(f func()) { - check.finals = append(check.finals, f) -} - // push pushes obj onto the object path and returns its index in the path. func (check *Checker) push(obj Object) int { check.objPath = append(check.objPath, obj) @@ -214,7 +205,6 @@ func (check *Checker) initFiles(files []*syntax.File) { check.methods = nil check.untyped = nil check.delayed = nil - check.finals = nil // determine package name and collect valid files pkg := check.pkg @@ -281,7 +271,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) { print("== processDelayed ==") check.processDelayed(0) // incl. all functions - check.processFinals() print("== initOrder ==") check.initOrder() @@ -324,16 +313,6 @@ func (check *Checker) processDelayed(top int) { check.delayed = check.delayed[:top] } -func (check *Checker) processFinals() { - n := len(check.finals) - for _, f := range check.finals { - f() // must not append to check.finals - } - if len(check.finals) != n { - panic("internal error: final action list grew") - } -} - func (check *Checker) recordUntyped() { if !debug && check.Types == nil { return // nothing to do diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 177fcf4215..14bc91785e 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -141,7 +141,7 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) { // We don't want to call under() (via Interface) or complete interfaces while we // are in the middle of type-checking parameter declarations that might belong to // interface methods. Delay this check to the end of type-checking. - check.atEnd(func() { + check.later(func() { if t := asInterface(typ); t != nil { check.completeInterface(pos, t) // TODO(gri) is this the correct position? if t.allTypes != nil { @@ -574,7 +574,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { // // Delay this check because it requires fully setup types; // it is safe to continue in any case (was issue 6667). - check.atEnd(func() { + check.later(func() { if !Comparable(typ.key) { var why string if asTypeParam(typ.key) != nil { @@ -676,7 +676,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def * // make sure we check instantiation works at least once // and that the resulting type is valid - check.atEnd(func() { + check.later(func() { t := typ.expand() check.validType(t, nil) }) @@ -954,7 +954,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // If we're pre-go1.14 (overlapping embeddings are not permitted), report that // error here as well (even though we could do it eagerly) because it's the same // error message. - check.atEnd(func() { + check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { var err error_ err.errorf(pos, "duplicate method %s", m.name) @@ -1170,7 +1170,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) { // (via under(t)) a possibly incomplete type. embeddedTyp := typ // for closure below embeddedPos := pos - check.atEnd(func() { + check.later(func() { t, isPtr := deref(embeddedTyp) switch t := optype(t).(type) { case *Basic: @@ -1230,7 +1230,7 @@ func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr // interfaces, which may not be complete yet. It's ok to do this check at the // end because it's not a requirement for correctness of the code. // Note: This is a quadratic algorithm, but type lists tend to be short. - check.atEnd(func() { + check.later(func() { for i, t := range list { if t := asInterface(t); t != nil { check.completeInterface(types[i].Pos(), t) -- GitLab From d33e2192a71c33a604af247161ba1d2c1969e4c7 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 9 Mar 2021 17:23:04 -0500 Subject: [PATCH 0262/1298] cmd/go: allow '+' in package import paths in module mode This change upgrades x/mod to pull in the fix from CL 300149. Fixes #44776. Change-Id: I273f41df2abfff76d91315b7f19fce851c8770d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/300176 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- .../testdata/script/mod_invalid_path_plus.txt | 32 ++++++++++++++++ .../vendor/golang.org/x/mod/module/module.go | 38 +++++++++++++++---- src/cmd/vendor/modules.txt | 2 +- 5 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_invalid_path_plus.txt diff --git a/src/cmd/go.mod b/src/cmd/go.mod index ef05ca1ad1..05076792c8 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa + golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 77063f76af..3827248879 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa h1:Ci2bbuyE4ah9djFByg+fdNQcqc8DVSdcXbrWy6MBoEs= -golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f h1:mQozKYYFIVK0MXcDB8Dvw0dR3rxKLnkSCJHWznfaodQ= +golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/src/cmd/go/testdata/script/mod_invalid_path_plus.txt b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt new file mode 100644 index 0000000000..636769eb4d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/44776 +# The '+' character should be disallowed in module paths, but allowed in package +# paths within valid modules. + +go get -d example.net/cmd +go list example.net/cmd/x++ + +! go list -versions -m 'example.net/bad++' +stderr '^go list -m: malformed module path "example.net/bad\+\+": invalid char ''\+''$' + +# TODO(bcmills): 'go get -d example.net/cmd/x++' should also work, but currently +# it does not. This might be fixed by https://golang.org/cl/297891. +! go get -d example.net/cmd/x++ +stderr '^go get: malformed module path "example.net/cmd/x\+\+": invalid char ''\+''$' + +-- go.mod -- +module example.com/m + +go 1.16 + +replace ( + example.net/cmd => ./cmd +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/x++/main.go -- +package main + +func main() {} diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go index 272baeef17..0e03014837 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/module.go +++ b/src/cmd/vendor/golang.org/x/mod/module/module.go @@ -224,12 +224,16 @@ func firstPathOK(r rune) bool { 'a' <= r && r <= 'z' } -// pathOK reports whether r can appear in an import path element. +// modPathOK reports whether r can appear in a module path element. // Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. -// This matches what "go get" has historically recognized in import paths. +// +// This matches what "go get" has historically recognized in import paths, +// and avoids confusing sequences like '%20' or '+' that would change meaning +// if used in a URL. +// // TODO(rsc): We would like to allow Unicode letters, but that requires additional // care in the safe encoding (see "escaped paths" above). -func pathOK(r rune) bool { +func modPathOK(r rune) bool { if r < utf8.RuneSelf { return r == '-' || r == '.' || r == '_' || r == '~' || '0' <= r && r <= '9' || @@ -239,6 +243,17 @@ func pathOK(r rune) bool { return false } +// modPathOK reports whether r can appear in a package import path element. +// +// Import paths are intermediate between module paths and file paths: we allow +// disallow characters that would be confusing or ambiguous as arguments to +// 'go get' (such as '@' and ' ' ), but allow certain characters that are +// otherwise-unambiguous on the command line and historically used for some +// binary names (such as '++' as a suffix for compiler binaries and wrappers). +func importPathOK(r rune) bool { + return modPathOK(r) || r == '+' +} + // fileNameOK reports whether r can appear in a file name. // For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. // If we expand the set of allowed characters here, we have to @@ -394,12 +409,19 @@ func checkElem(elem string, kind pathKind) error { if elem[len(elem)-1] == '.' { return fmt.Errorf("trailing dot in path element") } - charOK := pathOK - if kind == filePath { - charOK = fileNameOK - } for _, r := range elem { - if !charOK(r) { + ok := false + switch kind { + case modulePath: + ok = modPathOK(r) + case importPath: + ok = importPathOK(r) + case filePath: + ok = fileNameOK(r) + default: + panic(fmt.Sprintf("internal error: invalid kind %v", kind)) + } + if !ok { return fmt.Errorf("invalid char %q", r) } } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index b1a2c67581..b84ee5a7b1 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.2-0.20210301144719-c8bb1bd8a2aa +# golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile -- GitLab From 643d240a11b2d00e1718b02719707af0708e7519 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 19 Nov 2020 19:09:14 +0800 Subject: [PATCH 0263/1298] internal/poll: implement a pipe pool for splice() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In scenarios where splice() is called, splice() is usually called not just once, but many times, which means that a lot of pipes will be created and destroyed frequently, costing an amount of system resources and slowing down performance, thus I suggest that we add a pipe pool for reusing pipes. Benchmark tests: goos: linux goarch: amd64 pkg: internal/poll cpu: AMD EPYC 7K62 48-Core Processor name old time/op new time/op delta SplicePipe-8 1.36µs ± 1% 0.02µs ± 0% -98.57% (p=0.001 n=7+7) SplicePipeParallel-8 747ns ± 4% 4ns ± 0% -99.41% (p=0.001 n=7+7) name old alloc/op new alloc/op delta SplicePipe-8 24.0B ± 0% 0.0B -100.00% (p=0.001 n=7+7) SplicePipeParallel-8 24.0B ± 0% 0.0B -100.00% (p=0.001 n=7+7) name old allocs/op new allocs/op delta SplicePipe-8 1.00 ± 0% 0.00 -100.00% (p=0.001 n=7+7) SplicePipeParallel-8 1.00 ± 0% 0.00 -100.00% (p=0.001 n=7+7) Fixes #42740 Change-Id: Idff654b7264342084e089b5ba796c87c380c471b Reviewed-on: https://go-review.googlesource.com/c/go/+/271537 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Trust: Brad Fitzpatrick --- src/internal/poll/export_linux_test.go | 22 ++++++ src/internal/poll/splice_linux.go | 87 +++++++++++++++++------ src/internal/poll/splice_linux_test.go | 96 ++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 src/internal/poll/export_linux_test.go create mode 100644 src/internal/poll/splice_linux_test.go diff --git a/src/internal/poll/export_linux_test.go b/src/internal/poll/export_linux_test.go new file mode 100644 index 0000000000..7fba793697 --- /dev/null +++ b/src/internal/poll/export_linux_test.go @@ -0,0 +1,22 @@ +// Copyright 2021 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. + +// Export guts for testing on linux. +// Since testing imports os and os imports internal/poll, +// the internal/poll tests can not be in package poll. + +package poll + +var ( + GetPipe = getPipe + PutPipe = putPipe + NewPipe = newPipe + DestroyPipe = destroyPipe +) + +func GetPipeFds(p *SplicePipe) (int, int) { + return p.rfd, p.wfd +} + +type SplicePipe = splicePipe diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go index 968bc44a5f..971f754f43 100644 --- a/src/internal/poll/splice_linux.go +++ b/src/internal/poll/splice_linux.go @@ -6,6 +6,8 @@ package poll import ( "internal/syscall/unix" + "runtime" + "sync" "sync/atomic" "syscall" "unsafe" @@ -23,23 +25,23 @@ const ( // Splice transfers at most remain bytes of data from src to dst, using the // splice system call to minimize copies of data from and to userspace. // -// Splice creates a temporary pipe, to serve as a buffer for the data transfer. +// Splice gets a pipe buffer from the pool or creates a new one if needed, to serve as a buffer for the data transfer. // src and dst must both be stream-oriented sockets. // // If err != nil, sc is the system call which caused the error. func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, err error) { - prfd, pwfd, sc, err := newTempPipe() + p, sc, err := getPipe() if err != nil { return 0, false, sc, err } - defer destroyTempPipe(prfd, pwfd) + defer putPipe(p) var inPipe, n int for err == nil && remain > 0 { max := maxSpliceSize if int64(max) > remain { max = int(remain) } - inPipe, err = spliceDrain(pwfd, src, max) + inPipe, err = spliceDrain(p.wfd, src, max) // The operation is considered handled if splice returns no // error, or an error other than EINVAL. An EINVAL means the // kernel does not support splice for the socket type of src. @@ -55,10 +57,13 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, if err != nil || inPipe == 0 { break } - n, err = splicePump(dst, prfd, inPipe) + p.data += inPipe + + n, err = splicePump(dst, p.rfd, inPipe) if n > 0 { written += int64(n) remain -= int64(n) + p.data -= n } } if err != nil { @@ -149,13 +154,57 @@ func splice(out int, in int, max int, flags int) (int, error) { return int(n), err } +type splicePipe struct { + rfd int + wfd int + data int +} + +// splicePipePool caches pipes to avoid high frequency construction and destruction of pipe buffers. +// The garbage collector will free all pipes in the sync.Pool in periodically, thus we need to set up +// a finalizer for each pipe to close the its file descriptors before the actual GC. +var splicePipePool = sync.Pool{New: newPoolPipe} + +func newPoolPipe() interface{} { + // Discard the error which occurred during the creation of pipe buffer, + // redirecting the data transmission to the conventional way utilizing read() + write() as a fallback. + p := newPipe() + if p != nil { + runtime.SetFinalizer(p, destroyPipe) + } + return p +} + +// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from cache. +// +// Note that it may fail to create a new pipe buffer by newPipe(), in which case getPipe() will return a generic error +// and system call name splice in string as the indication. +func getPipe() (*splicePipe, string, error) { + v := splicePipePool.Get() + if v == nil { + return nil, "splice", syscall.EINVAL + } + return v.(*splicePipe), "", nil +} + +func putPipe(p *splicePipe) { + // If there is still data left in the pipe, + // then close and discard it instead of putting it back into the pool. + if p.data != 0 { + runtime.SetFinalizer(p, nil) + destroyPipe(p) + return + } + splicePipePool.Put(p) +} + var disableSplice unsafe.Pointer -// newTempPipe sets up a temporary pipe for a splice operation. -func newTempPipe() (prfd, pwfd int, sc string, err error) { +// newPipe sets up a pipe for a splice operation. +func newPipe() (sp *splicePipe) { p := (*bool)(atomic.LoadPointer(&disableSplice)) if p != nil && *p { - return -1, -1, "splice", syscall.EINVAL + return nil } var fds [2]int @@ -165,9 +214,11 @@ func newTempPipe() (prfd, pwfd int, sc string, err error) { // closed. const flags = syscall.O_CLOEXEC | syscall.O_NONBLOCK if err := syscall.Pipe2(fds[:], flags); err != nil { - return -1, -1, "pipe2", err + return nil } + sp = &splicePipe{rfd: fds[0], wfd: fds[1]} + if p == nil { p = new(bool) defer atomic.StorePointer(&disableSplice, unsafe.Pointer(p)) @@ -175,20 +226,16 @@ func newTempPipe() (prfd, pwfd int, sc string, err error) { // F_GETPIPE_SZ was added in 2.6.35, which does not have the -EAGAIN bug. if _, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fds[0]), syscall.F_GETPIPE_SZ, 0); errno != 0 { *p = true - destroyTempPipe(fds[0], fds[1]) - return -1, -1, "fcntl", errno + destroyPipe(sp) + return nil } } - return fds[0], fds[1], "", nil + return } -// destroyTempPipe destroys a temporary pipe. -func destroyTempPipe(prfd, pwfd int) error { - err := CloseFunc(prfd) - err1 := CloseFunc(pwfd) - if err == nil { - return err1 - } - return err +// destroyPipe destroys a pipe. +func destroyPipe(p *splicePipe) { + CloseFunc(p.rfd) + CloseFunc(p.wfd) } diff --git a/src/internal/poll/splice_linux_test.go b/src/internal/poll/splice_linux_test.go new file mode 100644 index 0000000000..9ea5197242 --- /dev/null +++ b/src/internal/poll/splice_linux_test.go @@ -0,0 +1,96 @@ +// Copyright 2021 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 poll_test + +import ( + "internal/poll" + "runtime" + "syscall" + "testing" + "time" +) + +// checkPipes returns true if all pipes are closed properly, false otherwise. +func checkPipes(fds []int) bool { + for _, fd := range fds { + // Check if each pipe fd has been closed. + err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETFD, nil) + if err == nil { + return false + } + } + return true +} + +func TestSplicePipePool(t *testing.T) { + const N = 64 + var ( + p *poll.SplicePipe + ps []*poll.SplicePipe + fds []int + err error + ) + for i := 0; i < N; i++ { + p, _, err = poll.GetPipe() + if err != nil { + t.Skip("failed to create pipe, skip this test") + } + prfd, pwfd := poll.GetPipeFds(p) + fds = append(fds, prfd, pwfd) + ps = append(ps, p) + } + for _, p = range ps { + poll.PutPipe(p) + } + ps = nil + + var ok bool + // Trigger garbage collection to free the pipes in sync.Pool and check whether or not + // those pipe buffers have been closed as we expected. + for i := 0; i < 5; i++ { + runtime.GC() + time.Sleep(time.Duration(i*100+10) * time.Millisecond) + if ok = checkPipes(fds); ok { + break + } + } + + if !ok { + t.Fatal("at least one pipe is still open") + } +} + +func BenchmarkSplicePipe(b *testing.B) { + b.Run("SplicePipeWithPool", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p, _, _ := poll.GetPipe() + poll.PutPipe(p) + } + }) + b.Run("SplicePipeWithoutPool", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p := poll.NewPipe() + poll.DestroyPipe(p) + } + }) +} + +func BenchmarkSplicePipePoolParallel(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p, _, _ := poll.GetPipe() + poll.PutPipe(p) + } + }) +} + +func BenchmarkSplicePipeNativeParallel(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p := poll.NewPipe() + poll.DestroyPipe(p) + } + }) +} -- GitLab From 4d608eb224fe1ba8e8532fcc44f91702a5b17f9f Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Wed, 10 Mar 2021 10:09:39 +0800 Subject: [PATCH 0264/1298] testing: fix typo in a comment Change-Id: I781808327be84113cd55c52bc214b821cd166114 Reviewed-on: https://go-review.googlesource.com/c/go/+/300269 Trust: fannie zhang Reviewed-by: Ian Lance Taylor --- src/testing/testing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index fc52f3c547..fafc67c5b7 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -388,7 +388,7 @@ type common struct { w io.Writer // For flushToParent. ran bool // Test or benchmark (or one of its subtests) was executed. failed bool // Test or benchmark has failed. - skipped bool // Test of benchmark has been skipped. + skipped bool // Test or benchmark has been skipped. done bool // Test is finished and all subtests have completed. helperPCs map[uintptr]struct{} // functions to be skipped when writing file/line info helperNames map[string]struct{} // helperPCs converted to function names -- GitLab From cf598504669524a9f7002f6b6c1cb4e567ea4e9e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 9 Mar 2021 19:13:37 +0000 Subject: [PATCH 0265/1298] crypto/rand: supports for getrandom syscall in DragonFlyBSD Since the 5.7 release, DragonFlyBSD supports as well the getrandom function, the actual stable is 5.8. Change-Id: I2b8fc468771b10ac12b38ea7e8e5314342de6375 GitHub-Last-Rev: c5c496f41898d58f2c6f3ccc81f754792f49edbe GitHub-Pull-Request: golang/go#42617 Reviewed-on: https://go-review.googlesource.com/c/go/+/269999 Run-TryBot: Ian Lance Taylor Trust: Ian Lance Taylor Trust: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Tobias Klauser --- src/crypto/rand/rand_batched.go | 4 +- src/crypto/rand/rand_batched_test.go | 4 +- src/crypto/rand/rand_dragonfly.go | 9 ++++ .../syscall/unix/getrandom_dragonfly.go | 51 +++++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/crypto/rand/rand_dragonfly.go create mode 100644 src/internal/syscall/unix/getrandom_dragonfly.go diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go index 45e9351a31..538769a868 100644 --- a/src/crypto/rand/rand_batched.go +++ b/src/crypto/rand/rand_batched.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux || freebsd -// +build linux freebsd +//go:build linux || freebsd || dragonfly +// +build linux freebsd dragonfly package rand diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go index fd50735c7d..814f15201a 100644 --- a/src/crypto/rand/rand_batched_test.go +++ b/src/crypto/rand/rand_batched_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux || freebsd -// +build linux freebsd +//go:build linux || freebsd || dragonfly +// +build linux freebsd dragonfly package rand diff --git a/src/crypto/rand/rand_dragonfly.go b/src/crypto/rand/rand_dragonfly.go new file mode 100644 index 0000000000..8a36fea6cd --- /dev/null +++ b/src/crypto/rand/rand_dragonfly.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 rand + +// maxGetRandomRead is the maximum number of bytes to ask for in one call to the +// getrandom() syscall. In DragonFlyBSD at most 256 bytes will be returned per call. +const maxGetRandomRead = 1 << 8 diff --git a/src/internal/syscall/unix/getrandom_dragonfly.go b/src/internal/syscall/unix/getrandom_dragonfly.go new file mode 100644 index 0000000000..b345b4c00c --- /dev/null +++ b/src/internal/syscall/unix/getrandom_dragonfly.go @@ -0,0 +1,51 @@ +// Copyright 2021 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 unix + +import ( + "sync/atomic" + "syscall" + "unsafe" +) + +var randomUnsupported int32 // atomic + +// DragonFlyBSD getrandom system call number. +const randomTrap uintptr = 550 + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +const ( + // GRND_RANDOM is only set for portability purpose, no-op on DragonFlyBSD. + GRND_RANDOM GetRandomFlag = 0x0001 + + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0002 + + // GRND_INSECURE is an GRND_NONBLOCK alias + GRND_INSECURE GetRandomFlag = 0x0004 +) + +// GetRandom calls the DragonFlyBSD getrandom system call. +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&randomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + r1, _, errno := syscall.Syscall(randomTrap, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags)) + if errno != 0 { + if errno == syscall.ENOSYS { + atomic.StoreInt32(&randomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} -- GitLab From 30c28bbf0507cba9219633192e02b68719ab8280 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 9 Mar 2021 23:31:41 -0500 Subject: [PATCH 0266/1298] cmd/go: avoid password prompts in TestScript/mod_get_private_vcs In some cases, this test would prompt for interactive SSH passwords in order to authenticate to github.com over SSH. Setting GIT_SSH_COMMAND to /bin/false prevents that, while still provoking the desired Git failure mode. Updates #44904. Change-Id: Idc9fe9f47d2ccb6c8a4ea988b73d9c8c774e4079 Reviewed-on: https://go-review.googlesource.com/c/go/+/300156 Trust: Bryan C. Mills Trust: Kevin Burke Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Kevin Burke --- src/cmd/go/testdata/script/mod_get_private_vcs.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/testdata/script/mod_get_private_vcs.txt b/src/cmd/go/testdata/script/mod_get_private_vcs.txt index 8b01eac62c..75c776a7fa 100644 --- a/src/cmd/go/testdata/script/mod_get_private_vcs.txt +++ b/src/cmd/go/testdata/script/mod_get_private_vcs.txt @@ -22,7 +22,8 @@ stderr '^If this is a private repository, see https://golang.org/doc/faq#git_htt ! stderr 'unknown revision' ! stdout . -[!linux] stop +[!linux] stop # Needs XDG_CONFIG_HOME. +[!exec:false] stop # Test that Git clone errors will be shown to the user instead of a generic # "unknown revision" error. To do this we want to force git ls-remote to return @@ -31,6 +32,7 @@ stderr '^If this is a private repository, see https://golang.org/doc/faq#git_htt # Set XDG_CONFIG_HOME to tell Git where to look for the git config file listed # below, which turns on ssh. env XDG_CONFIG_HOME=$TMPDIR +env GIT_SSH_COMMAND=false ! go install github.com/golang/nonexist@master stderr 'fatal: Could not read from remote repository.' ! stderr 'unknown revision' -- GitLab From bc489dd6d5e8fdb6089b41b21e2cca1151a8a691 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 9 Mar 2021 22:58:55 -0500 Subject: [PATCH 0267/1298] runtime: update signature of reflectcall functions reflectcall tail calls runtime.call{16,32,...} functions, so they have the same signature as reflectcall. It is important for them to have the correct arg map, because those functions, as well as the function being reflectcall'd, could move the stack. When that happens, its pointer arguments, in particular regArgs, need to be adjusted. Otherwise it will still point to the old stack, causing memory corruption. This only caused failures on the regabi builder because it is the only place where internal/abi.RegArgs is not a zero-sized type. May fix #44821. Change-Id: Iab400ea6b60c52360d0b43a793f6bfe50ca9989b Reviewed-on: https://go-review.googlesource.com/c/go/+/300154 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/stubs.go | 55 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index b9b313a711..5011d7199e 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -318,33 +318,34 @@ func return0() // in asm_*.s // not called directly; definitions here supply type information for traceback. -func call16(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call32(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call64(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call128(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call256(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call512(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call1024(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call2048(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call4096(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call8192(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call16384(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call32768(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call65536(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call131072(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call262144(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call524288(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call1048576(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call2097152(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call4194304(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call8388608(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call16777216(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call33554432(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call67108864(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call134217728(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call268435456(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call536870912(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -func call1073741824(typ, fn, arg unsafe.Pointer, n, retoffset uint32) +// These must have the same signature (arg pointer map) as reflectcall. +func call16(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call32(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call64(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call128(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call256(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call512(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call1024(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call2048(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call4096(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call8192(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call16384(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call32768(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call65536(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call131072(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call262144(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call524288(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call1048576(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call2097152(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call4194304(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call8388608(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call16777216(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call33554432(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call67108864(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call134217728(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call268435456(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call536870912(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +func call1073741824(typ, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) func systemstack_switch() -- GitLab From 818f6b14b496d718c0f8e49c9ef4c06cc45cc0d4 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 8 Mar 2021 15:19:47 -0500 Subject: [PATCH 0268/1298] cmd/compile: remove ".fp" fake arg No longer needed with previous CLs. Change-Id: I9a1c11092a2736c190fa8e8ddfbb913b708957eb Reviewed-on: https://go-review.googlesource.com/c/go/+/300155 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/ssagen/ssa.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index cc79c07af7..f1f244cce6 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -545,13 +545,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func { for _, n := range fn.Dcl { if n.Class == ir.PPARAM { if s.canSSA(n) { - var v *ssa.Value - if n.Sym().Name == ".fp" { - // Race-detector's get-caller-pc incantation is NOT a real Arg. - v = s.newValue0(ssa.OpGetCallerPC, n.Type()) - } else { - v = s.newValue0A(ssa.OpArg, n.Type(), n) - } + v := s.newValue0A(ssa.OpArg, n.Type(), n) s.vars[n] = v s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself. } else { // address was taken AND/OR too large for SSA -- GitLab From 74574623039f2369b3e4b3d717285a48c47b73c4 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 10 Mar 2021 11:41:04 -0500 Subject: [PATCH 0269/1298] runtime/race: update dead link LLVM changed their main branch name, so this link didn't work anymore. Change-Id: I4c3a67b26e2bda012071281e29ea3c932c185130 Reviewed-on: https://go-review.googlesource.com/c/go/+/300469 Trust: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Dmitry Vyukov TryBot-Result: Go Bot --- src/runtime/race/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/race/README b/src/runtime/race/README index dbff42dc8a..3b188a0361 100644 --- a/src/runtime/race/README +++ b/src/runtime/race/README @@ -1,6 +1,6 @@ runtime/race package contains the data race detector runtime library. It is based on ThreadSanitizer race detector, that is currently a part of -the LLVM project (https://github.com/llvm/llvm-project/tree/master/compiler-rt). +the LLVM project (https://github.com/llvm/llvm-project/tree/main/compiler-rt). To update the .syso files use golang.org/x/build/cmd/racebuild. -- GitLab From 489231111f2ef097e99b150232cc0c5323c9729e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 10 Mar 2021 11:30:24 -0500 Subject: [PATCH 0270/1298] go/types: add missing build tag to api_go1.18_test.go This file has a go:build comment without a corresponding +build comment. Change-Id: Id01604242a14d8ead16ffb9aa1b45eef7706956a Reviewed-on: https://go-review.googlesource.com/c/go/+/300450 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_go1.18_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/go/types/api_go1.18_test.go b/src/go/types/api_go1.18_test.go index bbbf70581d..e60fe23201 100644 --- a/src/go/types/api_go1.18_test.go +++ b/src/go/types/api_go1.18_test.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. //go:build go1.18 +// +build go1.18 package types_test -- GitLab From 5edab39f490dd3cff7bf02101b2d37a90827fa6d Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 10 Mar 2021 11:33:23 -0500 Subject: [PATCH 0271/1298] cmd/gofmt: fix const association to avoid inaccurate comment The const parseTypeParams was grouped with printer-related consts in gofmt.go, implicitly suggesting that it must be kept in sync with go/format/format.go. Change-Id: Ia65dc15c27fef2c389f963071252adee32ec6bd6 Reviewed-on: https://go-review.googlesource.com/c/go/+/300451 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/gofmt/gofmt.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 95f537d91e..cd867bba15 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -51,12 +51,12 @@ const ( // // This value is defined in go/printer specifically for go/format and cmd/gofmt. printerNormalizeNumbers = 1 << 30 - - // parseTypeParams tells go/parser to parse type parameters. Must be kept in - // sync with go/parser/interface.go. - parseTypeParams parser.Mode = 1 << 30 ) +// parseTypeParams tells go/parser to parse type parameters. Must be kept in +// sync with go/parser/interface.go. +const parseTypeParams parser.Mode = 1 << 30 + var ( fileSet = token.NewFileSet() // per process FileSet exitCode = 0 -- GitLab From 1811aeae66bee899317403c92c83b56673919775 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 5 Mar 2021 22:07:56 -0800 Subject: [PATCH 0272/1298] cmd/compile: deal with helper generic types that add methods to T Deal with cases like: 'type P[T any] T' (used to add methods to an arbitrary type T), In this case, P[T] has kind types.TTYPEPARAM (as does T itself), but requires more code to substitute than a simple TTYPEPARAM T. See the comment near the beginning of subster.typ() in stencil.go. Add new test absdiff.go. This test has a case for complex types (which I've commented out) that will only work when we deal better with Go builtins in generic functions (like real and imag). Remove change in fmt.go for TTYPEPARAMS that is no longer needed (since all TTYPEPARAMS have a sym) and was sometimes causing an extra prefix when formatting method names. Separate out the setting of a TTYPEPARAM bound, since it can reference the TTYPEPARAM being defined, so must be done separately. Also, we don't currently (and may not ever) need bounds after types2 typechecking. Change-Id: Id173057e0c4563b309b95e665e9c1151ead4ba77 Reviewed-on: https://go-review.googlesource.com/c/go/+/300049 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/stencil.go | 29 ++++++- src/cmd/compile/internal/noder/types.go | 9 ++- src/cmd/compile/internal/types/fmt.go | 2 +- src/cmd/compile/internal/types/type.go | 7 +- test/typeparam/absdiff.go | 99 +++++++++++++++++++++++ 5 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 test/typeparam/absdiff.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 8001d6d398..071a2f44c2 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -553,7 +553,25 @@ func (subst *subster) typ(t *types.Type) *types.Type { return subst.targs[i].Type() } } - return t + // If t is a simple typeparam T, then t has the name/symbol 'T' + // and t.Underlying() == t. + // + // However, consider the type definition: 'type P[T any] T'. We + // might use this definition so we can have a variant of type T + // that we can add new methods to. Suppose t is a reference to + // P[T]. t has the name 'P[T]', but its kind is TTYPEPARAM, + // because P[T] is defined as T. If we look at t.Underlying(), it + // is different, because the name of t.Underlying() is 'T' rather + // than 'P[T]'. But the kind of t.Underlying() is also TTYPEPARAM. + // In this case, we do the needed recursive substitution in the + // case statement below. + if t.Underlying() == t { + // t is a simple typeparam that didn't match anything in tparam + return t + } + // t is a more complex typeparam (e.g. P[T], as above, whose + // definition is just T). + assert(t.Sym() != nil) } var newsym *types.Sym @@ -591,6 +609,15 @@ func (subst *subster) typ(t *types.Type) *types.Type { var newt *types.Type switch t.Kind() { + case types.TTYPEPARAM: + if t.Sym() == newsym { + // The substitution did not change the type. + return t + } + // Substitute the underlying typeparam (e.g. T in P[T], see + // the example describing type P[T] above). + newt = subst.typ(t.Underlying()) + assert(newt != t) case types.TARRAY: elem := t.Elem() diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index dfcf55d9c8..96bf75d594 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -180,11 +180,18 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...)) case *types2.TypeParam: - tp := types.NewTypeParam(g.tpkg(typ), g.typ(typ.Bound())) + tp := types.NewTypeParam(g.tpkg(typ)) // Save the name of the type parameter in the sym of the type. // Include the types2 subscript in the sym name sym := g.pkg(typ.Obj().Pkg()).Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" })) tp.SetSym(sym) + // Set g.typs[typ] in case the bound methods reference typ. + g.typs[typ] = tp + + // TODO(danscales): we don't currently need to use the bounds + // anywhere, so eventually we can probably remove. + bound := g.typ(typ.Bound()) + *tp.Methods() = *bound.Methods() return tp case *types2.Tuple: diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index c59f62e302..e29c826bb7 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -318,7 +318,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type } // Unless the 'L' flag was specified, if the type has a name, just print that name. - if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] && t.Kind() != TTYPEPARAM { + if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] { switch mode { case fmtTypeID, fmtTypeIDName: if verb == 'S' { diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index d76d9b409f..ffaf755345 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1742,12 +1742,9 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type { return t } -// NewTypeParam returns a new type param with the given constraint (which may -// not really be needed except for the type checker). -func NewTypeParam(pkg *Pkg, constraint *Type) *Type { +// NewTypeParam returns a new type param. +func NewTypeParam(pkg *Pkg) *Type { t := New(TTYPEPARAM) - constraint.wantEtype(TINTER) - t.methods = constraint.methods t.Extra.(*Interface).pkg = pkg t.SetHasTParam(true) return t diff --git a/test/typeparam/absdiff.go b/test/typeparam/absdiff.go new file mode 100644 index 0000000000..5dd58f14f7 --- /dev/null +++ b/test/typeparam/absdiff.go @@ -0,0 +1,99 @@ +// run -gcflags=-G=3 + +// Copyright 2020 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 ( + "fmt" + //"math" +) + +type Numeric interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64, + complex64, complex128 +} + +// numericAbs matches numeric types with an Abs method. +type numericAbs[T any] interface { + Numeric + Abs() T +} + +// AbsDifference computes the absolute value of the difference of +// a and b, where the absolute value is determined by the Abs method. +func absDifference[T numericAbs[T]](a, b T) T { + d := a - b + return d.Abs() +} + +// orderedNumeric matches numeric types that support the < operator. +type orderedNumeric interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64 +} + +// Complex matches the two complex types, which do not have a < operator. +type Complex interface { + type complex64, complex128 +} + +// orderedAbs is a helper type that defines an Abs method for +// ordered numeric types. +type orderedAbs[T orderedNumeric] T + +func (a orderedAbs[T]) Abs() orderedAbs[T] { + // TODO(danscales): orderedAbs[T] conversion shouldn't be needed + if a < orderedAbs[T](0) { + return -a + } + return a +} + +// complexAbs is a helper type that defines an Abs method for +// complex types. +// type complexAbs[T Complex] T + +// func (a complexAbs[T]) Abs() complexAbs[T] { +// r := float64(real(a)) +// i := float64(imag(a)) +// d := math.Sqrt(r * r + i * i) +// return complexAbs[T](complex(d, 0)) +// } + +// OrderedAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of an ordered type. +func orderedAbsDifference[T orderedNumeric](a, b T) T { + return T(absDifference(orderedAbs[T](a), orderedAbs[T](b))) +} + +// ComplexAbsDifference returns the absolute value of the difference +// between a and b, where a and b are of a complex type. +// func complexAbsDifference[T Complex](a, b T) T { +// return T(absDifference(complexAbs[T](a), complexAbs[T](b))) +// } + +func main() { + if got, want := orderedAbsDifference(1.0, -2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := orderedAbsDifference(-1.0, 2.0), 3.0; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + if got, want := orderedAbsDifference(-20, 15), 35; got != want { + panic(fmt.Sprintf("got = %v, want = %v", got, want)) + } + + // Still have to handle built-ins real/abs to make this work + // if got, want := complexAbsDifference(5.0 + 2.0i, 2.0 - 2.0i), 5; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want) + // } + // if got, want := complexAbsDifference(2.0 - 2.0i, 5.0 + 2.0i), 5; got != want { + // panic(fmt.Sprintf("got = %v, want = %v", got, want) + // } +} -- GitLab From cd3b4ca9f20fd14187ed4cdfdee1a02ea87e5cd8 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 2 Mar 2021 10:00:53 -0800 Subject: [PATCH 0273/1298] archive/zip: fix panic in Reader.Open When operating on a Zip file that contains a file prefixed with "../", Open(...) would cause a panic in toValidName when attempting to strip the prefixed path components. Fixes CVE-2021-27919 Fixes #44916 Change-Id: Ic755d8126cb0897e2cbbdacf572439c38dde7b35 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1004761 Reviewed-by: Filippo Valsorda Reviewed-by: Russ Cox Reviewed-by: Katie Hockman Reviewed-on: https://go-review.googlesource.com/c/go/+/300489 Trust: Katie Hockman Run-TryBot: Katie Hockman TryBot-Result: Go Bot Reviewed-by: Alexander Rakoczy Reviewed-by: Filippo Valsorda --- src/archive/zip/reader.go | 2 +- src/archive/zip/reader_test.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go index 8b4e77875f..c288ad965b 100644 --- a/src/archive/zip/reader.go +++ b/src/archive/zip/reader.go @@ -664,7 +664,7 @@ func toValidName(name string) string { if strings.HasPrefix(p, "/") { p = p[len("/"):] } - for strings.HasPrefix(name, "../") { + for strings.HasPrefix(p, "../") { p = p[len("../"):] } return p diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index 34e96f7da4..5faf1f49b5 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -1081,3 +1081,38 @@ func TestFS(t *testing.T) { t.Fatal(err) } } + +func TestCVE202127919(t *testing.T) { + // Archive containing only the file "../test.txt" + data := []byte{ + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e, + 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, + 0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c, + 0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51, + 0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc, + 0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed, + 0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, + 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, + 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, + 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00, + 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, + } + r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data))) + if err != nil { + t.Fatalf("Error reading the archive: %v", err) + } + _, err = r.Open("test.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } +} -- GitLab From d0b79e3513a29628f3599dc8860666b6eed75372 Mon Sep 17 00:00:00 2001 From: Katie Hockman Date: Mon, 1 Mar 2021 09:54:00 -0500 Subject: [PATCH 0274/1298] encoding/xml: prevent infinite loop while decoding This change properly handles a TokenReader which returns an EOF in the middle of an open XML element. Thanks to Sam Whited for reporting this. Fixes CVE-2021-27918 Fixes #44913 Change-Id: Id02a3f3def4a1b415fa2d9a8e3b373eb6cb0f433 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1004594 Reviewed-by: Russ Cox Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda Reviewed-on: https://go-review.googlesource.com/c/go/+/300391 Trust: Katie Hockman Run-TryBot: Katie Hockman TryBot-Result: Go Bot Reviewed-by: Alexander Rakoczy Reviewed-by: Filippo Valsorda --- src/encoding/xml/xml.go | 19 ++++--- src/encoding/xml/xml_test.go | 104 +++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index adaf4daf19..6f9594d7ba 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { // it will return an error. // // Token implements XML name spaces as described by -// https://www.w3.org/TR/REC-xml-names/. Each of the +// https://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, @@ -285,16 +285,17 @@ func (d *Decoder) Token() (Token, error) { if d.nextToken != nil { t = d.nextToken d.nextToken = nil - } else if t, err = d.rawToken(); err != nil { - switch { - case err == io.EOF && d.t != nil: - err = nil - case err == io.EOF && d.stk != nil && d.stk.kind != stkEOF: - err = d.syntaxError("unexpected EOF") + } else { + if t, err = d.rawToken(); t == nil && err != nil { + if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF { + err = d.syntaxError("unexpected EOF") + } + return nil, err } - return t, err + // We still have a token to process, so clear any + // errors (e.g. EOF) and proceed. + err = nil } - if !d.Strict { if t1, ok := d.autoClose(t); ok { d.nextToken = t diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go index efddca43e9..5672ebb375 100644 --- a/src/encoding/xml/xml_test.go +++ b/src/encoding/xml/xml_test.go @@ -33,30 +33,90 @@ func (t *toks) Token() (Token, error) { func TestDecodeEOF(t *testing.T) { start := StartElement{Name: Name{Local: "test"}} - t.Run("EarlyEOF", func(t *testing.T) { - d := NewTokenDecoder(&toks{earlyEOF: true, t: []Token{ - start, - start.End(), - }}) - err := d.Decode(&struct { - XMLName Name `xml:"test"` - }{}) - if err != nil { - t.Error(err) + tests := []struct { + name string + tokens []Token + ok bool + }{ + { + name: "OK", + tokens: []Token{ + start, + start.End(), + }, + ok: true, + }, + { + name: "Malformed", + tokens: []Token{ + start, + StartElement{Name: Name{Local: "bad"}}, + start.End(), + }, + ok: false, + }, + } + for _, tc := range tests { + for _, eof := range []bool{true, false} { + name := fmt.Sprintf("%s/earlyEOF=%v", tc.name, eof) + t.Run(name, func(t *testing.T) { + d := NewTokenDecoder(&toks{ + earlyEOF: eof, + t: tc.tokens, + }) + err := d.Decode(&struct { + XMLName Name `xml:"test"` + }{}) + if tc.ok && err != nil { + t.Fatalf("d.Decode: expected nil error, got %v", err) + } + if _, ok := err.(*SyntaxError); !tc.ok && !ok { + t.Errorf("d.Decode: expected syntax error, got %v", err) + } + }) } - }) - t.Run("LateEOF", func(t *testing.T) { - d := NewTokenDecoder(&toks{t: []Token{ - start, - start.End(), - }}) - err := d.Decode(&struct { - XMLName Name `xml:"test"` - }{}) - if err != nil { - t.Error(err) + } +} + +type toksNil struct { + returnEOF bool + t []Token +} + +func (t *toksNil) Token() (Token, error) { + if len(t.t) == 0 { + if !t.returnEOF { + // Return nil, nil before returning an EOF. It's legal, but + // discouraged. + t.returnEOF = true + return nil, nil } - }) + return nil, io.EOF + } + var tok Token + tok, t.t = t.t[0], t.t[1:] + return tok, nil +} + +func TestDecodeNilToken(t *testing.T) { + for _, strict := range []bool{true, false} { + name := fmt.Sprintf("Strict=%v", strict) + t.Run(name, func(t *testing.T) { + start := StartElement{Name: Name{Local: "test"}} + bad := StartElement{Name: Name{Local: "bad"}} + d := NewTokenDecoder(&toksNil{ + // Malformed + t: []Token{start, bad, start.End()}, + }) + d.Strict = strict + err := d.Decode(&struct { + XMLName Name `xml:"test"` + }{}) + if _, ok := err.(*SyntaxError); !ok { + t.Errorf("d.Decode: expected syntax error, got %v", err) + } + }) + } } const testInput = ` -- GitLab From 5ce51ea74177513b473e2da05d0e4e9b7affb3c4 Mon Sep 17 00:00:00 2001 From: KimMachineGun Date: Wed, 10 Mar 2021 12:55:56 +0000 Subject: [PATCH 0275/1298] flag: panic if flag name begins with - or contains = Fixes #41792 Change-Id: I9b4aae8a899e3c3ac9532d27932d275cfb1fab48 GitHub-Last-Rev: f06b1e17674bf77bdc2d3e798df4c4379748c8d2 GitHub-Pull-Request: golang/go#42737 Reviewed-on: https://go-review.googlesource.com/c/go/+/271788 Reviewed-by: Emmanuel Odeke Reviewed-by: Rob Pike Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Trust: Rob Pike --- src/flag/flag.go | 24 +++++++++---- src/flag/flag_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/flag/flag.go b/src/flag/flag.go index a8485f034f..f7598a6758 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -857,17 +857,23 @@ func Func(name, usage string, fn func(string) error) { // of strings by giving the slice the methods of Value; in particular, Set would // decompose the comma-separated string into the slice. func (f *FlagSet) Var(value Value, name string, usage string) { + // Flag must not begin "-" or contain "=". + if strings.HasPrefix(name, "-") { + panic(f.sprintf("flag %q begins with -", name)) + } else if strings.Contains(name, "=") { + panic(f.sprintf("flag %q contains =", name)) + } + // Remember the default value as a string; it won't change. flag := &Flag{name, usage, value, value.String()} _, alreadythere := f.formal[name] if alreadythere { var msg string if f.name == "" { - msg = fmt.Sprintf("flag redefined: %s", name) + msg = f.sprintf("flag redefined: %s", name) } else { - msg = fmt.Sprintf("%s flag redefined: %s", f.name, name) + msg = f.sprintf("%s flag redefined: %s", f.name, name) } - fmt.Fprintln(f.Output(), msg) panic(msg) // Happens only if flags are declared with identical names } if f.formal == nil { @@ -886,13 +892,19 @@ func Var(value Value, name string, usage string) { CommandLine.Var(value, name, usage) } +// sprintf formats the message, prints it to output, and returns it. +func (f *FlagSet) sprintf(format string, a ...interface{}) string { + msg := fmt.Sprintf(format, a...) + fmt.Fprintln(f.Output(), msg) + return msg +} + // failf prints to standard error a formatted error and usage message and // returns the error. func (f *FlagSet) failf(format string, a ...interface{}) error { - err := fmt.Errorf(format, a...) - fmt.Fprintln(f.Output(), err) + msg := f.sprintf(format, a...) f.usage() - return err + return errors.New(msg) } // usage calls the Usage method for the flag set if one is specified, diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 06cab79405..5835fcf22c 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -655,3 +655,86 @@ func TestExitCode(t *testing.T) { } } } + +func mustPanic(t *testing.T, testName string, expected string, f func()) { + t.Helper() + defer func() { + switch msg := recover().(type) { + case nil: + t.Errorf("%s\n: expected panic(%q), but did not panic", testName, expected) + case string: + if msg != expected { + t.Errorf("%s\n: expected panic(%q), but got panic(%q)", testName, expected, msg) + } + default: + t.Errorf("%s\n: expected panic(%q), but got panic(%T%v)", testName, expected, msg, msg) + } + }() + f() +} + +func TestInvalidFlags(t *testing.T) { + tests := []struct { + flag string + errorMsg string + }{ + { + flag: "-foo", + errorMsg: "flag \"-foo\" begins with -", + }, + { + flag: "foo=bar", + errorMsg: "flag \"foo=bar\" contains =", + }, + } + + for _, test := range tests { + testName := fmt.Sprintf("FlagSet.Var(&v, %q, \"\")", test.flag) + + fs := NewFlagSet("", ContinueOnError) + buf := bytes.NewBuffer(nil) + fs.SetOutput(buf) + + mustPanic(t, testName, test.errorMsg, func() { + var v flagVar + fs.Var(&v, test.flag, "") + }) + if msg := test.errorMsg + "\n"; msg != buf.String() { + t.Errorf("%s\n: unexpected output: expected %q, bug got %q", testName, msg, buf) + } + } +} + +func TestRedefinedFlags(t *testing.T) { + tests := []struct { + flagSetName string + errorMsg string + }{ + { + flagSetName: "", + errorMsg: "flag redefined: foo", + }, + { + flagSetName: "fs", + errorMsg: "fs flag redefined: foo", + }, + } + + for _, test := range tests { + testName := fmt.Sprintf("flag redefined in FlagSet(%q)", test.flagSetName) + + fs := NewFlagSet(test.flagSetName, ContinueOnError) + buf := bytes.NewBuffer(nil) + fs.SetOutput(buf) + + var v flagVar + fs.Var(&v, "foo", "") + + mustPanic(t, testName, test.errorMsg, func() { + fs.Var(&v, "foo", "") + }) + if msg := test.errorMsg + "\n"; msg != buf.String() { + t.Errorf("%s\n: unexpected output: expected %q, bug got %q", testName, msg, buf) + } + } +} -- GitLab From c41bf9ee81e26d0fc0aca858a3d96d96be29ccba Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 9 Mar 2021 16:13:23 -0500 Subject: [PATCH 0276/1298] runtime: check partial lock ranking order To ease readability we typically keep the partial order lists sorted by rank. This isn't required for correctness, it just makes it (slightly) easier to read the lists. Currently we must notice out-of-order entries during code review, which is an error-prone process. Add a test to enforce ordering, and fix the errors that have crept in. Most of the existing errors were misordered lockRankHchan or lockRankPollDesc. While we're here, I've moved the correctness check that the partial ordering satisfies the total ordering from init to a test case. This will allow us to catch these errors without even running staticlockranking. Change-Id: I9c11abe49ea26c556439822bb6a3183129600c3b Reviewed-on: https://go-review.googlesource.com/c/go/+/300171 Trust: Michael Pratt Trust: Dan Scales Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/runtime/export_test.go | 8 +++++++ src/runtime/lockrank.go | 22 +++++++++---------- src/runtime/lockrank_on.go | 13 ------------ src/runtime/lockrank_test.go | 41 ++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 src/runtime/lockrank_test.go diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index a48bb2636f..5a87024b8a 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -46,6 +46,14 @@ var NetpollGenericInit = netpollGenericInit var Memmove = memmove var MemclrNoHeapPointers = memclrNoHeapPointers +var LockPartialOrder = lockPartialOrder + +type LockRank lockRank + +func (l LockRank) String() string { + return lockRank(l).String() +} + const PreemptMSupported = preemptMSupported type LFNode struct { diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go index 5a908b470f..b600c2132b 100644 --- a/src/runtime/lockrank.go +++ b/src/runtime/lockrank.go @@ -204,7 +204,7 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankDeadlock: {lockRankDeadlock}, lockRankAllg: {lockRankSysmon, lockRankSched}, lockRankAllp: {lockRankSysmon, lockRankSched}, - lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers}, + lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankPollDesc, lockRankSched, lockRankAllp, lockRankTimers}, lockRankItab: {}, lockRankReflectOffs: {lockRankItab}, lockRankHchan: {lockRankScavenge, lockRankSweep, lockRankHchan}, @@ -213,25 +213,25 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, lockRankTraceStrings: {lockRankTraceBuf}, lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProf: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, - lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, + lockRankProf: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings}, lockRankRoot: {}, - lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankSweep}, + lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot}, lockRankTraceStackTab: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankTrace}, lockRankNetpollInit: {lockRankTimers}, lockRankRwmutexW: {}, lockRankRwmutexR: {lockRankSysmon, lockRankRwmutexW}, - lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankSpanSetSpine}, - lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankSpanSetSpine, lockRankGscan}, + lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankSpanSetSpine}, + lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankSpanSetSpine, lockRankGscan}, lockRankStackLarge: {lockRankSysmon, lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankSpanSetSpine, lockRankGscan}, lockRankDefer: {}, - lockRankSudog: {lockRankNotifyList, lockRankHchan}, - lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankFin, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan}, + lockRankSudog: {lockRankHchan, lockRankNotifyList}, + lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankSpanSetSpine, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankPollDesc, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings}, lockRankGlobalAlloc: {lockRankProf, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial}, lockRankGFree: {lockRankSched}, diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go index 3958d9eeaa..fc8d2dc8d1 100644 --- a/src/runtime/lockrank_on.go +++ b/src/runtime/lockrank_on.go @@ -25,19 +25,6 @@ type lockRankStruct struct { pad int } -// init checks that the partial order in lockPartialOrder fits within the total -// order determined by the order of the lockRank constants. -func init() { - for rank, list := range lockPartialOrder { - for _, entry := range list { - if entry > lockRank(rank) { - println("lockPartial order row", lockRank(rank).String(), "entry", entry.String()) - throw("lockPartialOrder table is inconsistent with total lock ranking order") - } - } - } -} - func lockInit(l *mutex, rank lockRank) { l.rank = rank } diff --git a/src/runtime/lockrank_test.go b/src/runtime/lockrank_test.go new file mode 100644 index 0000000000..4b2fc0eaee --- /dev/null +++ b/src/runtime/lockrank_test.go @@ -0,0 +1,41 @@ +// Copyright 2021 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_test + +import ( + . "runtime" + "testing" +) + +// Check that the partial order in lockPartialOrder fits within the total order +// determined by the order of the lockRank constants. +func TestLockRankPartialOrder(t *testing.T) { + for r, list := range LockPartialOrder { + rank := LockRank(r) + for _, e := range list { + entry := LockRank(e) + if entry > rank { + t.Errorf("lockPartialOrder row %v entry %v is inconsistent with total lock ranking order", rank, entry) + } + } + } +} + +// Verify that partial order lists are kept sorted. This is a purely cosemetic +// check to make manual reviews simpler. It does not affect correctness, unlike +// the above test. +func TestLockRankPartialOrderSortedEntries(t *testing.T) { + for r, list := range LockPartialOrder { + rank := LockRank(r) + var prev LockRank + for _, e := range list { + entry := LockRank(e) + if entry <= prev { + t.Errorf("Partial order for rank %v out of order: %v <= %v in %v", rank, entry, prev, list) + } + prev = entry + } + } +} -- GitLab From ccf9acefa8b61fb58daad233a6e0478d092d55ef Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Mon, 8 Mar 2021 10:07:17 -0600 Subject: [PATCH 0277/1298] cmd/compile/internal: improve handling of DS form offsets on ppc64x In the ppc64 ISA DS form loads and stores are restricted to offset fields that are a multiple of 4. This is currently handled with checks in the rules that generate MOVDload, MOVWload, MOVDstore and MOVDstorezero to prevent invalid instructions from getting to the assembler. An unhandled case was discovered which led to the search for a better solution to this problem. Now, instead of checking the offset in the rules, this will be detected when processing these Ops in ssaGenValues in ppc64/ssa.go. If the offset is not valid, the address of the symbol to be loaded or stored will be computed using the base register + offset, and that value used in the new base register. With the full address in the base register, the offset field can be zero in the instruction. Updates #44739 Change-Id: I4f3c0c469ae70a63e3add295c9b55ea0e30ef9b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/299789 Trust: Lynn Boger Run-TryBot: Lynn Boger TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ppc64/ssa.go | 124 ++++++++++++++----- src/cmd/compile/internal/ssa/gen/PPC64.rules | 48 +++---- src/cmd/compile/internal/ssa/rewritePPC64.go | 107 +++------------- test/fixedbugs/issue44739.go | 61 +++++++++ 4 files changed, 192 insertions(+), 148 deletions(-) create mode 100644 test/fixedbugs/issue44739.go diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index 2bae35bf44..899f5ee6af 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -798,42 +798,63 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = v.Reg() p.To.Type = obj.TYPE_REG - case ssa.OpPPC64MOVDload: - - // MOVDload uses a DS instruction which requires the offset value of the data to be a multiple of 4. - // For offsets known at compile time, a MOVDload won't be selected, but in the case of a go.string, - // the offset is not known until link time. If the load of a go.string uses relocation for the - // offset field of the instruction, and if the offset is not aligned to 4, then a link error will occur. - // To avoid this problem, the full address of the go.string is computed and loaded into the base register, - // and that base register is used for the MOVDload using a 0 offset. This problem can only occur with - // go.string types because other types will have proper alignment. - - gostring := false - switch n := v.Aux.(type) { - case *obj.LSym: - gostring = strings.HasPrefix(n.Name, "go.string.") + case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload: + + // MOVDload and MOVWload are DS form instructions that are restricted to + // offsets that are a multiple of 4. If the offset is not a multple of 4, + // then the address of the symbol to be loaded is computed (base + offset) + // and used as the new base register and the offset field in the instruction + // can be set to zero. + + // This same problem can happen with gostrings since the final offset is not + // known yet, but could be unaligned after the relocation is resolved. + // So gostrings are handled the same way. + + // This allows the MOVDload and MOVWload to be generated in more cases and + // eliminates some offset and alignment checking in the rules file. + + fromAddr := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()} + ssagen.AddAux(&fromAddr, v) + + genAddr := false + + switch fromAddr.Name { + case obj.NAME_EXTERN, obj.NAME_STATIC: + // Special case for a rule combines the bytes of gostring. + // The v alignment might seem OK, but we don't want to load it + // using an offset because relocation comes later. + genAddr = strings.HasPrefix(fromAddr.Sym.Name, "go.string") || v.Type.Alignment()%4 != 0 || fromAddr.Offset%4 != 0 + default: + genAddr = fromAddr.Offset%4 != 0 } - if gostring { - // Generate full addr of the go.string const - // including AuxInt + if genAddr { + // Load full address into the temp register. p := s.Prog(ppc64.AMOVD) p.From.Type = obj.TYPE_ADDR p.From.Reg = v.Args[0].Reg() ssagen.AddAux(&p.From, v) + // Load target using temp as base register + // and offset zero. Setting NAME_NONE + // prevents any extra offsets from being + // added. p.To.Type = obj.TYPE_REG - p.To.Reg = v.Reg() - // Load go.string using 0 offset - p = s.Prog(v.Op.Asm()) - p.From.Type = obj.TYPE_MEM - p.From.Reg = v.Reg() - p.To.Type = obj.TYPE_REG - p.To.Reg = v.Reg() - break + p.To.Reg = ppc64.REGTMP + fromAddr.Reg = ppc64.REGTMP + // Clear the offset field and other + // information that might be used + // by the assembler to add to the + // final offset value. + fromAddr.Offset = 0 + fromAddr.Name = obj.NAME_NONE + fromAddr.Sym = nil } - // Not a go.string, generate a normal load - fallthrough + p := s.Prog(v.Op.Asm()) + p.From = fromAddr + p.To.Type = obj.TYPE_REG + p.To.Reg = v.Reg() + break - case ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload, ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload: + case ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload, ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[0].Reg() @@ -865,7 +886,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero: + case ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = ppc64.REGZERO @@ -873,7 +894,46 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To.Reg = v.Args[0].Reg() ssagen.AddAux(&p.To, v) - case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore, ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore: + case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVDstorezero: + + // MOVDstore and MOVDstorezero become DS form instructions that are restricted + // to offset values that are a multple of 4. If the offset field is not a + // multiple of 4, then the full address of the store target is computed (base + + // offset) and used as the new base register and the offset in the instruction + // is set to 0. + + // This allows the MOVDstore and MOVDstorezero to be generated in more cases, + // and prevents checking of the offset value and alignment in the rules. + + toAddr := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()} + ssagen.AddAux(&toAddr, v) + + if toAddr.Offset%4 != 0 { + p := s.Prog(ppc64.AMOVD) + p.From.Type = obj.TYPE_ADDR + p.From.Reg = v.Args[0].Reg() + ssagen.AddAux(&p.From, v) + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REGTMP + toAddr.Reg = ppc64.REGTMP + // Clear the offset field and other + // information that might be used + // by the assembler to add to the + // final offset value. + toAddr.Offset = 0 + toAddr.Name = obj.NAME_NONE + toAddr.Sym = nil + } + p := s.Prog(v.Op.Asm()) + p.To = toAddr + p.From.Type = obj.TYPE_REG + if v.Op == ssa.OpPPC64MOVDstorezero { + p.From.Reg = ppc64.REGZERO + } else { + p.From.Reg = v.Args[1].Reg() + } + + case ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore, ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[1].Reg() @@ -1476,7 +1536,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case rem >= 8: op, size = ppc64.AMOVD, 8 case rem >= 4: - op, size = ppc64.AMOVW, 4 + op, size = ppc64.AMOVWZ, 4 case rem >= 2: op, size = ppc64.AMOVH, 2 } @@ -1743,7 +1803,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case rem >= 8: op, size = ppc64.AMOVD, 8 case rem >= 4: - op, size = ppc64.AMOVW, 4 + op, size = ppc64.AMOVWZ, 4 case rem >= 2: op, size = ppc64.AMOVH, 2 } diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index 85ce9a5b54..b618cde529 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -607,24 +607,18 @@ (MOVHstorezero [4] destptr (MOVWstorezero destptr mem))) -// MOVD for store with DS must have offsets that are multiple of 4 -(Zero [8] {t} destptr mem) && t.Alignment()%4 == 0 => - (MOVDstorezero destptr mem) -(Zero [8] destptr mem) => - (MOVWstorezero [4] destptr - (MOVWstorezero [0] destptr mem)) -// Handle these cases only if aligned properly, otherwise use general case below -(Zero [12] {t} destptr mem) && t.Alignment()%4 == 0 => +(Zero [8] {t} destptr mem) => (MOVDstorezero destptr mem) +(Zero [12] {t} destptr mem) => (MOVWstorezero [8] destptr (MOVDstorezero [0] destptr mem)) -(Zero [16] {t} destptr mem) && t.Alignment()%4 == 0 => +(Zero [16] {t} destptr mem) => (MOVDstorezero [8] destptr (MOVDstorezero [0] destptr mem)) -(Zero [24] {t} destptr mem) && t.Alignment()%4 == 0 => +(Zero [24] {t} destptr mem) => (MOVDstorezero [16] destptr (MOVDstorezero [8] destptr (MOVDstorezero [0] destptr mem))) -(Zero [32] {t} destptr mem) && t.Alignment()%4 == 0 => +(Zero [32] {t} destptr mem) => (MOVDstorezero [24] destptr (MOVDstorezero [16] destptr (MOVDstorezero [8] destptr @@ -639,9 +633,6 @@ (Zero [s] ptr mem) && objabi.GOPPC64 >= 9 => (LoweredQuadZero [s] ptr mem) // moves -// Only the MOVD and MOVW instructions require 4 byte -// alignment in the offset field. The other MOVx instructions -// allow any alignment. (Move [0] _ _ mem) => mem (Move [1] dst src mem) => (MOVBstore dst (MOVBZload src mem) mem) (Move [2] dst src mem) => @@ -649,11 +640,8 @@ (Move [4] dst src mem) => (MOVWstore dst (MOVWZload src mem) mem) // MOVD for load and store must have offsets that are multiple of 4 -(Move [8] {t} dst src mem) && t.Alignment()%4 == 0 => +(Move [8] {t} dst src mem) => (MOVDstore dst (MOVDload src mem) mem) -(Move [8] dst src mem) => - (MOVWstore [4] dst (MOVWZload [4] src mem) - (MOVWstore dst (MOVWZload src mem) mem)) (Move [3] dst src mem) => (MOVBstore [2] dst (MOVBZload [2] src mem) (MOVHstore dst (MOVHload src mem) mem)) @@ -875,7 +863,7 @@ (MFVSRD x:(FMOVDload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVDload [off] {sym} ptr mem) // Fold offsets for stores. -(MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 => (MOVDstore [off1+int32(off2)] {sym} x val mem) +(MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(int64(off1)+off2) => (MOVDstore [off1+int32(off2)] {sym} x val mem) (MOVWstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(int64(off1)+off2) => (MOVWstore [off1+int32(off2)] {sym} x val mem) (MOVHstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(int64(off1)+off2) => (MOVHstore [off1+int32(off2)] {sym} x val mem) (MOVBstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(int64(off1)+off2) => (MOVBstore [off1+int32(off2)] {sym} x val mem) @@ -898,7 +886,7 @@ && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVDstore [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) - && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 => + && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (FMOVSstore [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) @@ -918,13 +906,13 @@ && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVWload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) - && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 => + && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVWZload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVDload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) - && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 => + && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (FMOVSload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) => @@ -937,8 +925,8 @@ (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is16Bit(int64(off1)+off2) => (FMOVSload [off1+int32(off2)] {sym} ptr mem) (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is16Bit(int64(off1)+off2) => (FMOVDload [off1+int32(off2)] {sym} ptr mem) -(MOVDload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 => (MOVDload [off1+int32(off2)] {sym} x mem) -(MOVWload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 => (MOVWload [off1+int32(off2)] {sym} x mem) +(MOVDload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVDload [off1+int32(off2)] {sym} x mem) +(MOVWload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVWload [off1+int32(off2)] {sym} x mem) (MOVWZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVWZload [off1+int32(off2)] {sym} x mem) (MOVHload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVHload [off1+int32(off2)] {sym} x mem) (MOVHZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVHZload [off1+int32(off2)] {sym} x mem) @@ -947,7 +935,10 @@ // Determine load + addressing that can be done as a register indexed load (MOV(D|W|WZ|H|HZ|BZ)load [0] {sym} p:(ADD ptr idx) mem) && sym == nil && p.Uses == 1 => (MOV(D|W|WZ|H|HZ|BZ)loadidx ptr idx mem) -// Determine indexed loads with constant values that can be done without index +// Determine if there is benefit to using a non-indexed load, since that saves the load +// of the index register. With MOVDload and MOVWload, there is no benefit if the offset +// value is not a multiple of 4, since that results in an extra instruction in the base +// register address computation. (MOV(D|W)loadidx ptr (MOVDconst [c]) mem) && is16Bit(c) && c%4 == 0 => (MOV(D|W)load [int32(c)] ptr mem) (MOV(WZ|H|HZ|BZ)loadidx ptr (MOVDconst [c]) mem) && is16Bit(c) => (MOV(WZ|H|HZ|BZ)load [int32(c)] ptr mem) (MOV(D|W)loadidx (MOVDconst [c]) ptr mem) && is16Bit(c) && c%4 == 0 => (MOV(D|W)load [int32(c)] ptr mem) @@ -960,7 +951,7 @@ (MOVBstore [off] {sym} ptr (MOVDconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem) // Fold offsets for storezero -(MOVDstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 => +(MOVDstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVDstorezero [off1+int32(off2)] {sym} x mem) (MOVWstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(int64(off1)+off2) => (MOVWstorezero [off1+int32(off2)] {sym} x mem) @@ -973,6 +964,7 @@ (MOV(D|W|H|B)store [0] {sym} p:(ADD ptr idx) val mem) && sym == nil && p.Uses == 1 => (MOV(D|W|H|B)storeidx ptr idx val mem) // Stores with constant index values can be done without indexed instructions +// No need to lower the idx cases if c%4 is not 0 (MOVDstoreidx ptr (MOVDconst [c]) val mem) && is16Bit(c) && c%4 == 0 => (MOVDstore [int32(c)] ptr val mem) (MOV(W|H|B)storeidx ptr (MOVDconst [c]) val mem) && is16Bit(c) => (MOV(W|H|B)store [int32(c)] ptr val mem) (MOVDstoreidx (MOVDconst [c]) ptr val mem) && is16Bit(c) && c%4 == 0 => (MOVDstore [int32(c)] ptr val mem) @@ -980,7 +972,7 @@ // Fold symbols into storezero (MOVDstorezero [off1] {sym1} p:(MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) - && (x.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 => + && (x.Op != OpSB || p.Uses == 1) => (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem) (MOVWstorezero [off1] {sym1} p:(MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) && (x.Op != OpSB || p.Uses == 1) => @@ -1294,7 +1286,6 @@ o3:(OR s3:(SLDconst x4:(MOVBZload [i4] {s} p mem) [32]) x0:(MOVWZload {s} [i0] p mem))))) && !config.BigEndian - && i0%4 == 0 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 @@ -1431,7 +1422,6 @@ x2:(MOVBstore [i4] {s} p (SRDconst w [32]) x3:(MOVWstore [i0] {s} p w mem))))) && !config.BigEndian - && i0%4 == 0 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && clobber(x0, x1, x2, x3) diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 3357864291..a5bbc836cc 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -3528,46 +3528,20 @@ func rewriteValuePPC64_OpMove(v *Value) bool { return true } // match: (Move [8] {t} dst src mem) - // cond: t.Alignment()%4 == 0 // result: (MOVDstore dst (MOVDload src mem) mem) for { if auxIntToInt64(v.AuxInt) != 8 { break } - t := auxToType(v.Aux) dst := v_0 src := v_1 mem := v_2 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVDstore) v0 := b.NewValue0(v.Pos, OpPPC64MOVDload, typ.Int64) v0.AddArg2(src, mem) v.AddArg3(dst, v0, mem) return true } - // match: (Move [8] dst src mem) - // result: (MOVWstore [4] dst (MOVWZload [4] src mem) (MOVWstore dst (MOVWZload src mem) mem)) - for { - if auxIntToInt64(v.AuxInt) != 8 { - break - } - dst := v_0 - src := v_1 - mem := v_2 - v.reset(OpPPC64MOVWstore) - v.AuxInt = int32ToAuxInt(4) - v0 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32) - v0.AuxInt = int32ToAuxInt(4) - v0.AddArg2(src, mem) - v1 := b.NewValue0(v.Pos, OpPPC64MOVWstore, types.TypeMem) - v2 := b.NewValue0(v.Pos, OpPPC64MOVWZload, typ.UInt32) - v2.AddArg2(src, mem) - v1.AddArg3(dst, v2, mem) - v.AddArg3(dst, v0, v1) - return true - } // match: (Move [3] dst src mem) // result: (MOVBstore [2] dst (MOVBZload [2] src mem) (MOVHstore dst (MOVHload src mem) mem)) for { @@ -7881,7 +7855,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value) bool { return true } // match: (MOVBstore [i7] {s} p (SRDconst w [56]) x0:(MOVBstore [i6] {s} p (SRDconst w [48]) x1:(MOVBstore [i5] {s} p (SRDconst w [40]) x2:(MOVBstore [i4] {s} p (SRDconst w [32]) x3:(MOVWstore [i0] {s} p w mem))))) - // cond: !config.BigEndian && i0%4 == 0 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && clobber(x0, x1, x2, x3) + // cond: !config.BigEndian && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && clobber(x0, x1, x2, x3) // result: (MOVDstore [i0] {s} p w mem) for { i7 := auxIntToInt32(v.AuxInt) @@ -7948,7 +7922,7 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value) bool { break } mem := x3.Args[2] - if p != x3.Args[0] || w != x3.Args[1] || !(!config.BigEndian && i0%4 == 0 && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && clobber(x0, x1, x2, x3)) { + if p != x3.Args[0] || w != x3.Args[1] || !(!config.BigEndian && x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && clobber(x0, x1, x2, x3)) { break } v.reset(OpPPC64MOVDstore) @@ -8392,7 +8366,7 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value) bool { return true } // match: (MOVDload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 + // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) // result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8405,7 +8379,7 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value) bool { sym2 := auxToSym(p.Aux) ptr := p.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0) { + if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1)) { break } v.reset(OpPPC64MOVDload) @@ -8415,7 +8389,7 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value) bool { return true } // match: (MOVDload [off1] {sym} (ADDconst [off2] x) mem) - // cond: is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 + // cond: is16Bit(int64(off1)+off2) // result: (MOVDload [off1+int32(off2)] {sym} x mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8426,7 +8400,7 @@ func rewriteValuePPC64_OpPPC64MOVDload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) x := v_0.Args[0] mem := v_1 - if !(is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0) { + if !(is16Bit(int64(off1) + off2)) { break } v.reset(OpPPC64MOVDload) @@ -8523,7 +8497,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value) bool { return true } // match: (MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) - // cond: is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 + // cond: is16Bit(int64(off1)+off2) // result: (MOVDstore [off1+int32(off2)] {sym} x val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8535,7 +8509,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value) bool { x := v_0.Args[0] val := v_1 mem := v_2 - if !(is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0) { + if !(is16Bit(int64(off1) + off2)) { break } v.reset(OpPPC64MOVDstore) @@ -8545,7 +8519,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value) bool { return true } // match: (MOVDstore [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) val mem) - // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 + // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) // result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8559,7 +8533,7 @@ func rewriteValuePPC64_OpPPC64MOVDstore(v *Value) bool { ptr := p.Args[0] val := v_1 mem := v_2 - if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0) { + if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1)) { break } v.reset(OpPPC64MOVDstore) @@ -8658,7 +8632,7 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MOVDstorezero [off1] {sym} (ADDconst [off2] x) mem) - // cond: is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 + // cond: is16Bit(int64(off1)+off2) // result: (MOVDstorezero [off1+int32(off2)] {sym} x mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8669,7 +8643,7 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) x := v_0.Args[0] mem := v_1 - if !(is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0) { + if !(is16Bit(int64(off1) + off2)) { break } v.reset(OpPPC64MOVDstorezero) @@ -8679,7 +8653,7 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value) bool { return true } // match: (MOVDstorezero [off1] {sym1} p:(MOVDaddr [off2] {sym2} x) mem) - // cond: canMergeSym(sym1,sym2) && (x.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 + // cond: canMergeSym(sym1,sym2) && (x.Op != OpSB || p.Uses == 1) // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -8692,7 +8666,7 @@ func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value) bool { sym2 := auxToSym(p.Aux) x := p.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && (x.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0) { + if !(canMergeSym(sym1, sym2) && (x.Op != OpSB || p.Uses == 1)) { break } v.reset(OpPPC64MOVDstorezero) @@ -10598,7 +10572,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MOVWload [off1] {sym1} p:(MOVDaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0 + // cond: canMergeSym(sym1,sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10611,7 +10585,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value) bool { sym2 := auxToSym(p.Aux) ptr := p.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1) && (off1+off2)%4 == 0) { + if !(canMergeSym(sym1, sym2) && is16Bit(int64(off1+off2)) && (ptr.Op != OpSB || p.Uses == 1)) { break } v.reset(OpPPC64MOVWload) @@ -10621,7 +10595,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value) bool { return true } // match: (MOVWload [off1] {sym} (ADDconst [off2] x) mem) - // cond: is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0 + // cond: is16Bit(int64(off1)+off2) // result: (MOVWload [off1+int32(off2)] {sym} x mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -10632,7 +10606,7 @@ func rewriteValuePPC64_OpPPC64MOVWload(v *Value) bool { off2 := auxIntToInt64(v_0.AuxInt) x := v_0.Args[0] mem := v_1 - if !(is16Bit(int64(off1)+off2) && (int64(off1)+off2)%4 == 0) { + if !(is16Bit(int64(off1) + off2)) { break } v.reset(OpPPC64MOVWload) @@ -12504,7 +12478,7 @@ func rewriteValuePPC64_OpPPC64OR(v *Value) bool { break } // match: (OR s6:(SLDconst x7:(MOVBZload [i7] {s} p mem) [56]) o5:(OR s5:(SLDconst x6:(MOVBZload [i6] {s} p mem) [48]) o4:(OR s4:(SLDconst x5:(MOVBZload [i5] {s} p mem) [40]) o3:(OR s3:(SLDconst x4:(MOVBZload [i4] {s} p mem) [32]) x0:(MOVWZload {s} [i0] p mem))))) - // cond: !config.BigEndian && i0%4 == 0 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses ==1 && x7.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && mergePoint(b, x0, x4, x5, x6, x7) != nil && clobber(x0, x4, x5, x6, x7, s3, s4, s5, s6, o3, o4, o5) + // cond: !config.BigEndian && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses ==1 && x7.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && mergePoint(b, x0, x4, x5, x6, x7) != nil && clobber(x0, x4, x5, x6, x7, s3, s4, s5, s6, o3, o4, o5) // result: @mergePoint(b,x0,x4,x5,x6,x7) (MOVDload {s} [i0] p mem) for { t := v.Type @@ -12602,7 +12576,7 @@ func rewriteValuePPC64_OpPPC64OR(v *Value) bool { continue } _ = x0.Args[1] - if p != x0.Args[0] || mem != x0.Args[1] || !(!config.BigEndian && i0%4 == 0 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && mergePoint(b, x0, x4, x5, x6, x7) != nil && clobber(x0, x4, x5, x6, x7, s3, s4, s5, s6, o3, o4, o5)) { + if p != x0.Args[0] || mem != x0.Args[1] || !(!config.BigEndian && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7 && x0.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && mergePoint(b, x0, x4, x5, x6, x7) != nil && clobber(x0, x4, x5, x6, x7, s3, s4, s5, s6, o3, o4, o5)) { continue } b = mergePoint(b, x0, x4, x5, x6, x7) @@ -16847,51 +16821,25 @@ func rewriteValuePPC64_OpZero(v *Value) bool { return true } // match: (Zero [8] {t} destptr mem) - // cond: t.Alignment()%4 == 0 // result: (MOVDstorezero destptr mem) for { if auxIntToInt64(v.AuxInt) != 8 { break } - t := auxToType(v.Aux) destptr := v_0 mem := v_1 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVDstorezero) v.AddArg2(destptr, mem) return true } - // match: (Zero [8] destptr mem) - // result: (MOVWstorezero [4] destptr (MOVWstorezero [0] destptr mem)) - for { - if auxIntToInt64(v.AuxInt) != 8 { - break - } - destptr := v_0 - mem := v_1 - v.reset(OpPPC64MOVWstorezero) - v.AuxInt = int32ToAuxInt(4) - v0 := b.NewValue0(v.Pos, OpPPC64MOVWstorezero, types.TypeMem) - v0.AuxInt = int32ToAuxInt(0) - v0.AddArg2(destptr, mem) - v.AddArg2(destptr, v0) - return true - } // match: (Zero [12] {t} destptr mem) - // cond: t.Alignment()%4 == 0 // result: (MOVWstorezero [8] destptr (MOVDstorezero [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 12 { break } - t := auxToType(v.Aux) destptr := v_0 mem := v_1 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVWstorezero) v.AuxInt = int32ToAuxInt(8) v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem) @@ -16901,18 +16849,13 @@ func rewriteValuePPC64_OpZero(v *Value) bool { return true } // match: (Zero [16] {t} destptr mem) - // cond: t.Alignment()%4 == 0 // result: (MOVDstorezero [8] destptr (MOVDstorezero [0] destptr mem)) for { if auxIntToInt64(v.AuxInt) != 16 { break } - t := auxToType(v.Aux) destptr := v_0 mem := v_1 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVDstorezero) v.AuxInt = int32ToAuxInt(8) v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem) @@ -16922,18 +16865,13 @@ func rewriteValuePPC64_OpZero(v *Value) bool { return true } // match: (Zero [24] {t} destptr mem) - // cond: t.Alignment()%4 == 0 // result: (MOVDstorezero [16] destptr (MOVDstorezero [8] destptr (MOVDstorezero [0] destptr mem))) for { if auxIntToInt64(v.AuxInt) != 24 { break } - t := auxToType(v.Aux) destptr := v_0 mem := v_1 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVDstorezero) v.AuxInt = int32ToAuxInt(16) v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem) @@ -16946,18 +16884,13 @@ func rewriteValuePPC64_OpZero(v *Value) bool { return true } // match: (Zero [32] {t} destptr mem) - // cond: t.Alignment()%4 == 0 // result: (MOVDstorezero [24] destptr (MOVDstorezero [16] destptr (MOVDstorezero [8] destptr (MOVDstorezero [0] destptr mem)))) for { if auxIntToInt64(v.AuxInt) != 32 { break } - t := auxToType(v.Aux) destptr := v_0 mem := v_1 - if !(t.Alignment()%4 == 0) { - break - } v.reset(OpPPC64MOVDstorezero) v.AuxInt = int32ToAuxInt(24) v0 := b.NewValue0(v.Pos, OpPPC64MOVDstorezero, types.TypeMem) diff --git a/test/fixedbugs/issue44739.go b/test/fixedbugs/issue44739.go new file mode 100644 index 0000000000..3441a90343 --- /dev/null +++ b/test/fixedbugs/issue44739.go @@ -0,0 +1,61 @@ +// compile + +// Copyright 2021 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 44739: cmd/compile: incorrect offset in MOVD +// load/store on ppc64/ppc64le causes assembler error. + +// Test other 8 byte loads and stores where the +// compile time offset is not aligned to 8, as +// well as cases where the offset is not known +// until link time (e.g. gostrings). + +package main + +import ( + "fmt" +) + +type T struct { + x [4]byte + y [8]byte +} + +var st T + +const ( + gostring1 = "abc" + gostring2 = "defghijk" + gostring3 = "lmnopqrs" +) + +func f(a T, _ byte, b T) bool { + // initialization of a,b + // tests unaligned store + return a.y == b.y +} + +func g(a T) { + // test load of unaligned + // 8 byte gostring, store + // to unaligned static + copy(a.y[:], gostring2) +} + +func main() { + var t1, t2 T + + // test copy to automatic storage, + // load of unaligned gostring. + copy(st.y[:], gostring2) + copy(t1.y[:], st.y[:]) + copy(t2.y[:], gostring3) + // test initialization of params + if !f(t1, 'a', t2) { + // gostring1 added so it has a use + fmt.Printf("FAIL: %s\n", gostring1) + } +} + -- GitLab From a1a3d33b0dbd42ab91b04ba19bbee48b55427d58 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Mon, 1 Mar 2021 15:18:12 -0500 Subject: [PATCH 0278/1298] cmd/go: test remote lookup of packages with leading dots in path elements Follow-up to CL 297530. For #43985 For #34992 Change-Id: I2cfa6c41c013e627c3464c383ca42f5c9ebe521a Reviewed-on: https://go-review.googlesource.com/c/go/+/297634 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- src/cmd/go/internal/modload/query.go | 18 ++++++- src/cmd/go/proxy_test.go | 2 +- .../mod/example.com_dotname_v1.0.0.txt | 12 +++++ .../script/mod_invalid_path_dotname.txt | 46 ++++++++++++++++ .../testdata/script/mod_invalid_path_plus.txt | 14 +++-- .../vendor/golang.org/x/mod/module/module.go | 52 +++++++++++++------ src/cmd/vendor/modules.txt | 2 +- 9 files changed, 126 insertions(+), 26 deletions(-) create mode 100644 src/cmd/go/testdata/mod/example.com_dotname_v1.0.0.txt create mode 100644 src/cmd/go/testdata/script/mod_invalid_path_dotname.txt diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 05076792c8..306143f088 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f + golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 3827248879..97fbd5c0a9 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f h1:mQozKYYFIVK0MXcDB8Dvw0dR3rxKLnkSCJHWznfaodQ= -golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa h1:++oSKjoJSsXNHyhUdK1BtBKMAaMHER+GWyKN3319OZA= +golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index a8012c792a..1707bd88ed 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -695,7 +695,9 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin // modulePrefixesExcludingTarget returns all prefixes of path that may plausibly // exist as a module, excluding targetPrefix but otherwise including path -// itself, sorted by descending length. +// itself, sorted by descending length. Prefixes that are not valid module paths +// but are valid package paths (like "m" or "example.com/.gen") are included, +// since they might be replaced. func modulePrefixesExcludingTarget(path string) []string { prefixes := make([]string, 0, strings.Count(path, "/")+1) @@ -747,6 +749,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod noPackage *PackageNotInModuleError noVersion *NoMatchingVersionError noPatchBase *NoPatchBaseError + invalidPath *module.InvalidPathError // see comment in case below notExistErr error ) for _, r := range results { @@ -767,6 +770,17 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod if noPatchBase == nil { noPatchBase = rErr } + case *module.InvalidPathError: + // The prefix was not a valid module path, and there was no replacement. + // Prefixes like this may appear in candidateModules, since we handle + // replaced modules that weren't required in the repo lookup process + // (see lookupRepo). + // + // A shorter prefix may be a valid module path and may contain a valid + // import path, so this is a low-priority error. + if invalidPath == nil { + invalidPath = rErr + } default: if errors.Is(rErr, fs.ErrNotExist) { if notExistErr == nil { @@ -800,6 +814,8 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod err = noVersion case noPatchBase != nil: err = noPatchBase + case invalidPath != nil: + err = invalidPath case notExistErr != nil: err = notExistErr default: diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index e390c73a9c..7d8a97dd99 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -362,7 +362,7 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { var buf bytes.Buffer z := zip.NewWriter(&buf) for _, f := range a.Files { - if strings.HasPrefix(f.Name, ".") { + if f.Name == ".info" || f.Name == ".mod" || f.Name == ".zip" { continue } var zipName string diff --git a/src/cmd/go/testdata/mod/example.com_dotname_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_dotname_v1.0.0.txt new file mode 100644 index 0000000000..2ada3a3f81 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_dotname_v1.0.0.txt @@ -0,0 +1,12 @@ +-- .info -- +{"Version":"v1.0.0"} +-- .mod -- +module example.com/dotname + +go 1.16 +-- go.mod -- +module example.com/dotname + +go 1.16 +-- .dot/dot.go -- +package dot diff --git a/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt b/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt new file mode 100644 index 0000000000..85934332d1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path_dotname.txt @@ -0,0 +1,46 @@ +# Test that an import path containing an element with a leading dot +# in another module is valid. + +# 'go get' works with no version query. +cp go.mod.empty go.mod +go get -d example.com/dotname/.dot +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go get' works with a version query. +cp go.mod.empty go.mod +go get -d example.com/dotname/.dot@latest +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go get' works on an importing package. +cp go.mod.empty go.mod +go get -d . +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +# 'go list' works on the dotted package. +go list example.com/dotname/.dot +stdout '^example.com/dotname/.dot$' + +# 'go list' works on an importing package. +go list . +stdout '^m$' + +# 'go mod tidy' works. +cp go.mod.empty go.mod +go mod tidy +go list -m example.com/dotname +stdout '^example.com/dotname v1.0.0$' + +-- go.mod.empty -- +module m + +go 1.16 +-- go.sum -- +example.com/dotname v1.0.0 h1:Q0JMAn464CnwFVCshs1n4+f5EFiW/eRhnx/fTWjw2Ag= +example.com/dotname v1.0.0/go.mod h1:7K4VLT7QylRI8H7yZwUkeDH2s19wQnyfp/3oBlItWJ0= +-- use.go -- +package use + +import _ "example.com/dotname/.dot" diff --git a/src/cmd/go/testdata/script/mod_invalid_path_plus.txt b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt index 636769eb4d..51dbf93688 100644 --- a/src/cmd/go/testdata/script/mod_invalid_path_plus.txt +++ b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt @@ -2,18 +2,22 @@ # The '+' character should be disallowed in module paths, but allowed in package # paths within valid modules. +# 'go list' accepts package paths with pluses. +cp go.mod.orig go.mod go get -d example.net/cmd go list example.net/cmd/x++ +# 'go list -m' rejects module paths with pluses. ! go list -versions -m 'example.net/bad++' stderr '^go list -m: malformed module path "example.net/bad\+\+": invalid char ''\+''$' -# TODO(bcmills): 'go get -d example.net/cmd/x++' should also work, but currently -# it does not. This might be fixed by https://golang.org/cl/297891. -! go get -d example.net/cmd/x++ -stderr '^go get: malformed module path "example.net/cmd/x\+\+": invalid char ''\+''$' +# 'go get' accepts package paths with pluses. +cp go.mod.orig go.mod +go get -d example.net/cmd/x++ +go list -m example.net/cmd +stdout '^example.net/cmd v0.0.0-00010101000000-000000000000 => ./cmd$' --- go.mod -- +-- go.mod.orig -- module example.com/m go 1.16 diff --git a/src/cmd/vendor/golang.org/x/mod/module/module.go b/src/cmd/vendor/golang.org/x/mod/module/module.go index 0e03014837..cf69ff657a 100644 --- a/src/cmd/vendor/golang.org/x/mod/module/module.go +++ b/src/cmd/vendor/golang.org/x/mod/module/module.go @@ -192,6 +192,21 @@ func (e *InvalidVersionError) Error() string { func (e *InvalidVersionError) Unwrap() error { return e.Err } +// An InvalidPathError indicates a module, import, or file path doesn't +// satisfy all naming constraints. See CheckPath, CheckImportPath, +// and CheckFilePath for specific restrictions. +type InvalidPathError struct { + Kind string // "module", "import", or "file" + Path string + Err error +} + +func (e *InvalidPathError) Error() string { + return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err) +} + +func (e *InvalidPathError) Unwrap() error { return e.Err } + // Check checks that a given module path, version pair is valid. // In addition to the path being a valid module path // and the version being a valid semantic version, @@ -296,30 +311,36 @@ func fileNameOK(r rune) bool { // this second requirement is replaced by a requirement that the path // follow the gopkg.in server's conventions. // Third, no path element may begin with a dot. -func CheckPath(path string) error { +func CheckPath(path string) (err error) { + defer func() { + if err != nil { + err = &InvalidPathError{Kind: "module", Path: path, Err: err} + } + }() + if err := checkPath(path, modulePath); err != nil { - return fmt.Errorf("malformed module path %q: %v", path, err) + return err } i := strings.Index(path, "/") if i < 0 { i = len(path) } if i == 0 { - return fmt.Errorf("malformed module path %q: leading slash", path) + return fmt.Errorf("leading slash") } if !strings.Contains(path[:i], ".") { - return fmt.Errorf("malformed module path %q: missing dot in first path element", path) + return fmt.Errorf("missing dot in first path element") } if path[0] == '-' { - return fmt.Errorf("malformed module path %q: leading dash in first path element", path) + return fmt.Errorf("leading dash in first path element") } for _, r := range path[:i] { if !firstPathOK(r) { - return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r) + return fmt.Errorf("invalid char %q in first path element", r) } } if _, _, ok := SplitPathVersion(path); !ok { - return fmt.Errorf("malformed module path %q: invalid version", path) + return fmt.Errorf("invalid version") } return nil } @@ -343,7 +364,7 @@ func CheckPath(path string) error { // subtleties of Unicode. func CheckImportPath(path string) error { if err := checkPath(path, importPath); err != nil { - return fmt.Errorf("malformed import path %q: %v", path, err) + return &InvalidPathError{Kind: "import", Path: path, Err: err} } return nil } @@ -358,12 +379,13 @@ const ( filePath ) -// checkPath checks that a general path is valid. -// It returns an error describing why but not mentioning path. -// Because these checks apply to both module paths and import paths, -// the caller is expected to add the "malformed ___ path %q: " prefix. -// fileName indicates whether the final element of the path is a file name -// (as opposed to a directory name). +// checkPath checks that a general path is valid. kind indicates what +// specific constraints should be applied. +// +// checkPath returns an error describing why the path is not valid. +// Because these checks apply to module, import, and file paths, +// and because other checks may be applied, the caller is expected to wrap +// this error with InvalidPathError. func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") @@ -477,7 +499,7 @@ func checkElem(elem string, kind pathKind) error { // subtleties of Unicode. func CheckFilePath(path string) error { if err := checkPath(path, filePath); err != nil { - return fmt.Errorf("malformed file path %q: %v", path, err) + return &InvalidPathError{Kind: "file", Path: path, Err: err} } return nil } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index b84ee5a7b1..af92df8721 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.2-0.20210309222212-d6ab96f2441f +# golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile -- GitLab From b7f0fb6d9eb9a2c1b2beb9ecd58bdbf3571dd5cd Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Sat, 6 Feb 2021 00:50:55 -0500 Subject: [PATCH 0279/1298] cmd/go/internal/modload: fuse upgrading with downgrading in EditBuildList Previosly, EditBuildList performed an mvs.Upgrade followed by an mvs.Downgrade, with the Downgrade building on the result of the Upgrade. Unfortunately, that approach potentially folds in irrelevant dependencies from the first Upgrade, which are then preserved unnecessarily by the Downgrade (see mod_get_downup_artifact.txt). Now, we use the initial Upgrade only to compute the maximum allowed versions of transitive dependencies, and apply the module upgrades and downgrades together in a single operation. For #36460 Change-Id: I7590c137111fed4a3b06531c88d90efd49e6943a Reviewed-on: https://go-review.googlesource.com/c/go/+/290770 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/modload/buildlist.go | 29 +- src/cmd/go/internal/modload/edit.go | 281 ++++++++++++++++++ src/cmd/go/internal/modload/mvs.go | 29 +- .../script/mod_get_downup_artifact.txt | 10 +- 4 files changed, 314 insertions(+), 35 deletions(-) create mode 100644 src/cmd/go/internal/modload/edit.go diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 45f220a6ee..5de26357e1 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -82,25 +82,9 @@ func Selected(path string) (version string) { // the listed modules requiring a higher version of another), EditBuildList // returns a *ConstraintError and leaves the build list in its previous state. func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error { - var upgraded = capVersionSlice(buildList) - if len(add) > 0 { - // First, upgrade the build list with any additions. - // In theory we could just append the additions to the build list and let - // mvs.Downgrade take care of resolving the upgrades too, but the - // diagnostics from Upgrade are currently much better in case of errors. - var err error - upgraded, err = mvs.Upgrade(Target, &mvsReqs{buildList: upgraded}, add...) - if err != nil { - return err - } - } - - downgraded, err := mvs.Downgrade(Target, &mvsReqs{buildList: append(upgraded, mustSelect...)}, mustSelect...) - if err != nil { - return err - } + LoadModFile(ctx) - final, err := mvs.Upgrade(Target, &mvsReqs{buildList: downgraded}, mustSelect...) + final, err := editBuildList(ctx, buildList, add, mustSelect) if err != nil { return err } @@ -112,10 +96,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error inconsistent := false for _, m := range mustSelect { s, ok := selected[m.Path] - if !ok { - if m.Version != "none" { - panic(fmt.Sprintf("internal error: mvs.BuildList lost %v", m)) - } + if !ok && m.Version == "none" { continue } if s.Version != m.Version { @@ -135,7 +116,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error return nil } - // We overshot one or more of the modules in mustSelected, which means that + // We overshot one or more of the modules in mustSelect, which means that // Downgrade removed something in mustSelect because it conflicted with // something else in mustSelect. // @@ -170,7 +151,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error s, ok := selected[m.Path] if !ok { if m.Version != "none" { - panic(fmt.Sprintf("internal error: mvs.BuildList lost %v", m)) + panic(fmt.Sprintf("internal error: editBuildList lost %v", m)) } continue } diff --git a/src/cmd/go/internal/modload/edit.go b/src/cmd/go/internal/modload/edit.go new file mode 100644 index 0000000000..4d1f3c7826 --- /dev/null +++ b/src/cmd/go/internal/modload/edit.go @@ -0,0 +1,281 @@ +// Copyright 2021 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 modload + +import ( + "context" + "sort" + + "cmd/go/internal/mvs" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +// editBuildList returns an edited version of initial such that: +// +// 1. Each module version in mustSelect is selected, unless it is upgraded +// by the transitive requirements of another version in mustSelect. +// +// 2. Each module version in tryUpgrade is upgraded toward the indicated +// version as far as can be done without violating (1). +// +// 3. Each module version in initial is downgraded from its original version +// only to the extent needed to satisfy (1), or upgraded only to the extent +// needed to satisfy (1) and (2). +// +// 4. No module is upgraded above the maximum version of its path found in the +// combined dependency graph of list, tryUpgrade, and mustSelect. +func editBuildList(ctx context.Context, initial, tryUpgrade, mustSelect []module.Version) ([]module.Version, error) { + // Per https://research.swtch.com/vgo-mvs#algorithm_4: + // “To avoid an unnecessary downgrade to E 1.1, we must also add a new + // requirement on E 1.2. We can apply Algorithm R to find the minimal set of + // new requirements to write to go.mod.” + // + // In order to generate those new requirements, we need consider versions for + // every module in the existing build list, plus every module being directly + // added by the edit. However, modules added only as dependencies of tentative + // versions should not be retained if they end up being upgraded or downgraded + // away due to versions in mustSelect. + + // When we downgrade modules in order to reach mustSelect, we don't want to + // upgrade any existing module above the version that would be selected if we + // just added all of the new requirements and *didn't* downgrade. + // + // So we'll do exactly that: just add all of the new requirements and not + // downgrade, and return the resulting versions as an upper bound. This + // intentionally limits our solution space so that edits that the user + // percieves as “downgrades” will not also result in upgrades. + max := make(map[string]string) + maxes, err := mvs.Upgrade(Target, &mvsReqs{ + buildList: append(capVersionSlice(initial), mustSelect...), + }, tryUpgrade...) + if err != nil { + return nil, err + } + for _, m := range maxes { + max[m.Path] = m.Version + } + // The versions in mustSelect override whatever we would naively select — + // we will downgrade other modules as needed in order to meet them. + for _, m := range mustSelect { + max[m.Path] = m.Version + } + + limiter := newVersionLimiter(max) + + // Force the selected versions in mustSelect, even if they conflict. + // + // TODO(bcmills): Instead of forcing these versions, record conflicts + // so that the caller doesn't have to recompute them. + for _, m := range mustSelect { + limiter.selected[m.Path] = m.Version + } + + // For each module, we want to get as close as we can to either the upgrade + // version or the previously-selected version in the build list, whichever is + // higher. We can compute those in either order, but the upgrades will tend to + // be higher than the build list, so we arbitrarily start with those. + for _, m := range tryUpgrade { + if err := limiter.upgradeToward(ctx, m); err != nil { + return nil, err + } + } + for _, m := range initial { + if err := limiter.upgradeToward(ctx, m); err != nil { + return nil, err + } + } + + // We've identified acceptable versions for each of the modules, but those + // versions are not necessarily consistent with each other: one upgraded or + // downgraded module may require a higher (but still allowed) version of + // another. The lower version may require extraneous dependencies that aren't + // actually relevant, so we need to compute the actual selected versions. + adjusted := make([]module.Version, 0, len(maxes)) + for _, m := range maxes { + if v, ok := limiter.selected[m.Path]; ok { + adjusted = append(adjusted, module.Version{Path: m.Path, Version: v}) + } + } + consistent, err := mvs.BuildList(Target, &mvsReqs{buildList: adjusted}) + if err != nil { + return nil, err + } + + // We have the correct selected versions. Now we need to re-run MVS with only + // the actually-selected versions in order to eliminate extraneous + // dependencies from lower-than-selected ones. + compacted := consistent[:0] + for _, m := range consistent { + if _, ok := limiter.selected[m.Path]; ok { + // The fact that the limiter has a version for m.Path indicates that we + // care about retaining that path, even if the version was upgraded for + // consistency. + compacted = append(compacted, m) + } + } + + return mvs.BuildList(Target, &mvsReqs{buildList: compacted}) +} + +// A versionLimiter tracks the versions that may be selected for each module +// subject to constraints on the maximum versions of transitive dependencies. +type versionLimiter struct { + // max maps each module path to the maximum version that may be selected for + // that path. Paths with no entry are unrestricted. + max map[string]string + + // selected maps each module path to a version of that path (if known) whose + // transitive dependencies do not violate any max version. The version kept + // is the highest one found during any call to upgradeToward for the given + // module path. + // + // If a higher acceptable version is found during a call to upgradeToward for + // some *other* module path, that does not update the selected version. + // Ignoring those versions keeps the downgrades computed for two modules + // together close to the individual downgrades that would be computed for each + // module in isolation. (The only way one module can affect another is if the + // final downgraded version of the one module explicitly requires a higher + // version of the other.) + // + // Version "none" of every module is always known not to violate any max + // version, so paths at version "none" are omitted. + selected map[string]string + + // disqualified maps each encountered version to either true (if that version + // is known to be disqualified due to a conflict with a max version) or false + // (if that version is not known to be disqualified, either because it is ok + // or because we are currently traversing a cycle that includes it). + disqualified map[module.Version]bool + + // requiredBy maps each not-yet-disqualified module version to the versions + // that directly require it. If that version becomes disqualified, the + // disqualification will be propagated to all of the versions in the list. + requiredBy map[module.Version][]module.Version +} + +func newVersionLimiter(max map[string]string) *versionLimiter { + return &versionLimiter{ + selected: map[string]string{Target.Path: Target.Version}, + max: max, + disqualified: map[module.Version]bool{Target: false}, + requiredBy: map[module.Version][]module.Version{}, + } +} + +// upgradeToward attempts to upgrade the selected version of m.Path as close as +// possible to m.Version without violating l's maximum version limits. +func (l *versionLimiter) upgradeToward(ctx context.Context, m module.Version) error { + selected, ok := l.selected[m.Path] + if ok { + if cmpVersion(selected, m.Version) >= 0 { + // The selected version is already at least m, so no upgrade is needed. + return nil + } + } else { + selected = "none" + } + + if l.isDisqualified(m) { + candidates, err := versions(ctx, m.Path, CheckAllowed) + if err != nil { + // This is likely a transient error reaching the repository, + // rather than a permanent error with the retrieved version. + // + // TODO(golang.org/issue/31730, golang.org/issue/30134): + // decode what to do based on the actual error. + return err + } + + // Skip to candidates < m.Version. + i := sort.Search(len(candidates), func(i int) bool { + return semver.Compare(candidates[i], m.Version) >= 0 + }) + candidates = candidates[:i] + + for l.isDisqualified(m) { + n := len(candidates) + if n == 0 || cmpVersion(selected, candidates[n-1]) >= 0 { + // We couldn't find a suitable candidate above the already-selected version. + // Retain that version unmodified. + return nil + } + m.Version, candidates = candidates[n-1], candidates[:n-1] + } + } + + l.selected[m.Path] = m.Version + return nil +} + +// isDisqualified reports whether m (or its transitive dependencies) would +// violate l's maximum version limits if added to the module requirement graph. +func (l *versionLimiter) isDisqualified(m module.Version) bool { + if m.Version == "none" || m == Target { + // version "none" has no requirements, and the dependencies of Target are + // tautological. + return false + } + + if dq, seen := l.disqualified[m]; seen { + return dq + } + l.disqualified[m] = false + + if max, ok := l.max[m.Path]; ok && cmpVersion(m.Version, max) > 0 { + l.disqualify(m) + return true + } + + summary, err := goModSummary(m) + if err != nil { + // If we can't load the requirements, we couldn't load the go.mod file. + // There are a number of reasons this can happen, but this usually + // means an older version of the module had a missing or invalid + // go.mod file. For example, if example.com/mod released v2.0.0 before + // migrating to modules (v2.0.0+incompatible), then added a valid go.mod + // in v2.0.1, downgrading from v2.0.1 would cause this error. + // + // TODO(golang.org/issue/31730, golang.org/issue/30134): if the error + // is transient (we couldn't download go.mod), return the error from + // Downgrade. Currently, we can't tell what kind of error it is. + l.disqualify(m) + return true + } + + for _, r := range summary.require { + if l.isDisqualified(r) { + l.disqualify(m) + return true + } + + // r and its dependencies are (perhaps provisionally) ok. + // + // However, if there are cycles in the requirement graph, we may have only + // checked a portion of the requirement graph so far, and r (and thus m) may + // yet be disqualified by some path we have not yet visited. Remember this edge + // so that we can disqualify m and its dependents if that occurs. + l.requiredBy[r] = append(l.requiredBy[r], m) + } + + return false +} + +// disqualify records that m (or one of its transitive dependencies) +// violates l's maximum version limits. +func (l *versionLimiter) disqualify(m module.Version) { + if l.disqualified[m] { + return + } + l.disqualified[m] = true + + for _, p := range l.requiredBy[m] { + l.disqualify(p) + } + // Now that we have disqualified the modules that depend on m, we can forget + // about them — we won't need to disqualify them again. + delete(l.requiredBy, m) +} diff --git a/src/cmd/go/internal/modload/mvs.go b/src/cmd/go/internal/modload/mvs.go index 31015194f9..5f52017a74 100644 --- a/src/cmd/go/internal/modload/mvs.go +++ b/src/cmd/go/internal/modload/mvs.go @@ -16,6 +16,25 @@ import ( "golang.org/x/mod/semver" ) +// cmpVersion implements the comparison for versions in the module loader. +// +// It is consistent with semver.Compare except that as a special case, +// the version "" is considered higher than all other versions. +// The main module (also known as the target) has no version and must be chosen +// over other versions of the same module in the module dependency graph. +func cmpVersion(v1, v2 string) int { + if v2 == "" { + if v1 == "" { + return 0 + } + return -1 + } + if v1 == "" { + return 1 + } + return semver.Compare(v1, v2) +} + // mvsReqs implements mvs.Reqs for module semantic versions, // with any exclusions or replacements applied internally. type mvsReqs struct { @@ -47,7 +66,7 @@ func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) { // be chosen over other versions of the same module in the module dependency // graph. func (*mvsReqs) Max(v1, v2 string) string { - if v1 != "" && (v2 == "" || semver.Compare(v1, v2) == -1) { + if cmpVersion(v1, v2) < 0 { return v2 } return v1 @@ -86,12 +105,12 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string, return versions, err } -// Previous returns the tagged version of m.Path immediately prior to +// previousVersion returns the tagged version of m.Path immediately prior to // m.Version, or version "none" if no prior version is tagged. // // Since the version of Target is not found in the version list, // it has no previous version. -func (*mvsReqs) Previous(m module.Version) (module.Version, error) { +func previousVersion(m module.Version) (module.Version, error) { // TODO(golang.org/issue/38714): thread tracing context through MVS. if m == Target { @@ -111,3 +130,7 @@ func (*mvsReqs) Previous(m module.Version) (module.Version, error) { } return module.Version{Path: m.Path, Version: "none"}, nil } + +func (*mvsReqs) Previous(m module.Version) (module.Version, error) { + return previousVersion(m) +} diff --git a/src/cmd/go/testdata/script/mod_get_downup_artifact.txt b/src/cmd/go/testdata/script/mod_get_downup_artifact.txt index b35d4c4fd0..c20583b22a 100644 --- a/src/cmd/go/testdata/script/mod_get_downup_artifact.txt +++ b/src/cmd/go/testdata/script/mod_get_downup_artifact.txt @@ -61,14 +61,8 @@ go list -m all stdout '^example.com/a v0.1.0 ' stdout '^example.com/b v0.1.0 ' stdout '^example.com/c v0.1.0 ' - - # BUG: d should remain at v0.1.0, because it is not transitively imported by a - # with b@v0.1.0. Today, it is spuriously upgraded to v0.2.0. -stdout '^example.com/d v0.2.0 ' - - # BUG: e should not be added, because it is not transitively imported by a - # with b@v0.1.0. Today, it is spuriously added. -stdout '^example.com/e v0.1.0 ' +stdout '^example.com/d v0.1.0 ' +! stdout '^example.com/e ' -- go.mod -- module example.com/m -- GitLab From 2ceb79db526eabff880a8a03caab07258883b216 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 22 Feb 2021 17:05:32 -0500 Subject: [PATCH 0280/1298] cmd/go/internal/modload: make EditBuildList report whether the build list was changed For #36460 Change-Id: I8dd6e6f998a217a4287212815ce61209df6f007f Reviewed-on: https://go-review.googlesource.com/c/go/+/296609 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/modget/get.go | 11 +++++------ src/cmd/go/internal/modload/buildlist.go | 17 +++++++++++------ src/cmd/go/internal/work/build.go | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 9340a582e5..6b416d3622 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -30,7 +30,6 @@ import ( "fmt" "os" "path/filepath" - "reflect" "runtime" "sort" "strings" @@ -1635,7 +1634,8 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi } } - if err := modload.EditBuildList(ctx, additions, resolved); err != nil { + changed, err := modload.EditBuildList(ctx, additions, resolved) + if err != nil { var constraint *modload.ConstraintError if !errors.As(err, &constraint) { base.Errorf("go get: %v", err) @@ -1654,12 +1654,11 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi } return false } - - buildList := modload.LoadAllModules(ctx) - if reflect.DeepEqual(r.buildList, buildList) { + if !changed { return false } - r.buildList = buildList + + r.buildList = modload.LoadAllModules(ctx) r.buildListVersion = make(map[string]string, len(r.buildList)) for _, m := range r.buildList { r.buildListVersion[m.Path] = m.Version diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 5de26357e1..3412548efc 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -12,6 +12,7 @@ import ( "context" "fmt" "os" + "reflect" "strings" "golang.org/x/mod/module" @@ -81,12 +82,12 @@ func Selected(path string) (version string) { // If the versions listed in mustSelect are mutually incompatible (due to one of // the listed modules requiring a higher version of another), EditBuildList // returns a *ConstraintError and leaves the build list in its previous state. -func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error { +func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (changed bool, err error) { LoadModFile(ctx) final, err := editBuildList(ctx, buildList, add, mustSelect) if err != nil { - return err + return false, err } selected := make(map[string]module.Version, len(final)) @@ -106,14 +107,18 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error } if !inconsistent { - buildList = final additionalExplicitRequirements = make([]string, 0, len(mustSelect)) for _, m := range mustSelect { if m.Version != "none" { additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path) } } - return nil + changed := false + if !reflect.DeepEqual(buildList, final) { + buildList = final + changed = true + } + return changed, nil } // We overshot one or more of the modules in mustSelect, which means that @@ -136,7 +141,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error m, queue = queue[0], queue[1:] required, err := reqs.Required(m) if err != nil { - return err + return false, err } for _, r := range required { if _, ok := reason[r]; !ok { @@ -164,7 +169,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error } } - return &ConstraintError{ + return false, &ConstraintError{ Conflicts: conflicts, } } diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 0e7af6d33f..a80eb27798 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -836,7 +836,7 @@ func installOutsideModule(ctx context.Context, args []string) { // Since we are in NoRoot mode, the build list initially contains only // the dummy command-line-arguments module. Add a requirement on the // module that provides the packages named on the command line. - if err := modload.EditBuildList(ctx, nil, []module.Version{installMod}); err != nil { + if _, err := modload.EditBuildList(ctx, nil, []module.Version{installMod}); err != nil { base.Fatalf("go install %s: %v", args[0], err) } -- GitLab From f9ed8b3f1e180d3cd8534897103683e8165df5f0 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 28 Oct 2020 21:47:32 -0400 Subject: [PATCH 0281/1298] cmd/go/internal/mvs: factor out an incremental implementation The new Graph type implements an incremental version of the MVS algorithm, with requirements pushed in by the caller instead of pulled by an internal MVS traversal. To avoid redundancy going forward (and to ensure adequate test coverage of the incremental implementation), the existing buildList function is reimplemented in terms of Graph. For #36460 Change-Id: Idd0b6ab8f17cc41d83a2a4c25a95f82e9ce1eab0 Reviewed-on: https://go-review.googlesource.com/c/go/+/244760 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Michael Matloob --- src/cmd/go/internal/mvs/errors.go | 10 +- src/cmd/go/internal/mvs/graph.go | 223 ++++++++++++++++++++++++++++++ src/cmd/go/internal/mvs/mvs.go | 167 +++++++--------------- 3 files changed, 282 insertions(+), 118 deletions(-) create mode 100644 src/cmd/go/internal/mvs/graph.go diff --git a/src/cmd/go/internal/mvs/errors.go b/src/cmd/go/internal/mvs/errors.go index 5564965fb5..bf183cea9e 100644 --- a/src/cmd/go/internal/mvs/errors.go +++ b/src/cmd/go/internal/mvs/errors.go @@ -31,13 +31,15 @@ type buildListErrorElem struct { // occurred at a module found along the given path of requirements and/or // upgrades, which must be non-empty. // -// The isUpgrade function reports whether a path step is due to an upgrade. -// A nil isUpgrade function indicates that none of the path steps are due to upgrades. -func NewBuildListError(err error, path []module.Version, isUpgrade func(from, to module.Version) bool) *BuildListError { +// The isVersionChange function reports whether a path step is due to an +// explicit upgrade or downgrade (as opposed to an existing requirement in a +// go.mod file). A nil isVersionChange function indicates that none of the path +// steps are due to explicit version changes. +func NewBuildListError(err error, path []module.Version, isVersionChange func(from, to module.Version) bool) *BuildListError { stack := make([]buildListErrorElem, 0, len(path)) for len(path) > 1 { reason := "requires" - if isUpgrade != nil && isUpgrade(path[0], path[1]) { + if isVersionChange != nil && isVersionChange(path[0], path[1]) { reason = "updating to" } stack = append(stack, buildListErrorElem{ diff --git a/src/cmd/go/internal/mvs/graph.go b/src/cmd/go/internal/mvs/graph.go new file mode 100644 index 0000000000..c5de4866bf --- /dev/null +++ b/src/cmd/go/internal/mvs/graph.go @@ -0,0 +1,223 @@ +// Copyright 2020 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 mvs + +import ( + "fmt" + + "golang.org/x/mod/module" +) + +// Graph implements an incremental version of the MVS algorithm, with the +// requirements pushed by the caller instead of pulled by the MVS traversal. +type Graph struct { + cmp func(v1, v2 string) int + roots []module.Version + + required map[module.Version][]module.Version + + isRoot map[module.Version]bool // contains true for roots and false for reachable non-roots + selected map[string]string // path → version +} + +// NewGraph returns an incremental MVS graph containing only a set of root +// dependencies and using the given max function for version strings. +// +// The caller must ensure that the root slice is not modified while the Graph +// may be in use. +func NewGraph(cmp func(v1, v2 string) int, roots []module.Version) *Graph { + g := &Graph{ + cmp: cmp, + roots: roots[:len(roots):len(roots)], + required: make(map[module.Version][]module.Version), + isRoot: make(map[module.Version]bool), + selected: make(map[string]string), + } + + for _, m := range roots { + g.isRoot[m] = true + if g.cmp(g.Selected(m.Path), m.Version) < 0 { + g.selected[m.Path] = m.Version + } + } + + return g +} + +// Require adds the information that module m requires all modules in reqs. +// The reqs slice must not be modified after it is passed to Require. +// +// m must be reachable by some existing chain of requirements from g's target, +// and Require must not have been called for it already. +// +// If any of the modules in reqs has the same path as g's target, +// the target must have higher precedence than the version in req. +func (g *Graph) Require(m module.Version, reqs []module.Version) { + // To help catch disconnected-graph bugs, enforce that all required versions + // are actually reachable from the roots (and therefore should affect the + // selected versions of the modules they name). + if _, reachable := g.isRoot[m]; !reachable { + panic(fmt.Sprintf("%v is not reachable from any root", m)) + } + + // Truncate reqs to its capacity to avoid aliasing bugs if it is later + // returned from RequiredBy and appended to. + reqs = reqs[:len(reqs):len(reqs)] + + if _, dup := g.required[m]; dup { + panic(fmt.Sprintf("requirements of %v have already been set", m)) + } + g.required[m] = reqs + + for _, dep := range reqs { + // Mark dep reachable, regardless of whether it is selected. + if _, ok := g.isRoot[dep]; !ok { + g.isRoot[dep] = false + } + + if g.cmp(g.Selected(dep.Path), dep.Version) < 0 { + g.selected[dep.Path] = dep.Version + } + } +} + +// RequiredBy returns the slice of requirements passed to Require for m, if any, +// with its capacity reduced to its length. +// If Require has not been called for m, RequiredBy(m) returns ok=false. +// +// The caller must not modify the returned slice, but may safely append to it +// and may rely on it not to be modified. +func (g *Graph) RequiredBy(m module.Version) (reqs []module.Version, ok bool) { + reqs, ok = g.required[m] + return reqs, ok +} + +// Selected returns the selected version of the given module path. +// +// If no version is selected, Selected returns version "none". +func (g *Graph) Selected(path string) (version string) { + v, ok := g.selected[path] + if !ok { + return "none" + } + return v +} + +// BuildList returns the selected versions of all modules present in the Graph, +// beginning with the selected versions of each module path in the roots of g. +// +// The order of the remaining elements in the list is deterministic +// but arbitrary. +func (g *Graph) BuildList() []module.Version { + seenRoot := make(map[string]bool, len(g.roots)) + + var list []module.Version + for _, r := range g.roots { + if seenRoot[r.Path] { + // Multiple copies of the same root, with the same or different versions, + // are a bit of a degenerate case: we will take the transitive + // requirements of both roots into account, but only the higher one can + // possibly be selected. However — especially given that we need the + // seenRoot map for later anyway — it is simpler to support this + // degenerate case than to forbid it. + continue + } + + if v := g.Selected(r.Path); v != "none" { + list = append(list, module.Version{Path: r.Path, Version: v}) + } + seenRoot[r.Path] = true + } + uniqueRoots := list + + for path, version := range g.selected { + if !seenRoot[path] { + list = append(list, module.Version{Path: path, Version: version}) + } + } + module.Sort(list[len(uniqueRoots):]) + + return list +} + +// WalkBreadthFirst invokes f once, in breadth-first order, for each module +// version other than "none" that appears in the graph, regardless of whether +// that version is selected. +func (g *Graph) WalkBreadthFirst(f func(m module.Version)) { + var queue []module.Version + enqueued := make(map[module.Version]bool) + for _, m := range g.roots { + if m.Version != "none" { + queue = append(queue, m) + enqueued[m] = true + } + } + + for len(queue) > 0 { + m := queue[0] + queue = queue[1:] + + f(m) + + reqs, _ := g.RequiredBy(m) + for _, r := range reqs { + if !enqueued[r] && r.Version != "none" { + queue = append(queue, r) + enqueued[r] = true + } + } + } +} + +// FindPath reports a shortest requirement path starting at one of the roots of +// the graph and ending at a module version m for which f(m) returns true, or +// nil if no such path exists. +func (g *Graph) FindPath(f func(module.Version) bool) []module.Version { + // firstRequires[a] = b means that in a breadth-first traversal of the + // requirement graph, the module version a was first required by b. + firstRequires := make(map[module.Version]module.Version) + + queue := g.roots + for _, m := range g.roots { + firstRequires[m] = module.Version{} + } + + for len(queue) > 0 { + m := queue[0] + queue = queue[1:] + + if f(m) { + // Construct the path reversed (because we're starting from the far + // endpoint), then reverse it. + path := []module.Version{m} + for { + m = firstRequires[m] + if m.Path == "" { + break + } + path = append(path, m) + } + + i, j := 0, len(path)-1 + for i < j { + path[i], path[j] = path[j], path[i] + i++ + j-- + } + + return path + } + + reqs, _ := g.RequiredBy(m) + for _, r := range reqs { + if _, seen := firstRequires[r]; !seen { + queue = append(queue, r) + firstRequires[r] = m + } + } + } + + return nil +} diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go index e30a40c97e..6969f90f2e 100644 --- a/src/cmd/go/internal/mvs/mvs.go +++ b/src/cmd/go/internal/mvs/mvs.go @@ -10,7 +10,6 @@ import ( "fmt" "sort" "sync" - "sync/atomic" "cmd/go/internal/par" @@ -91,151 +90,91 @@ func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) { } func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) { - // Explore work graph in parallel in case reqs.Required - // does high-latency network operations. - type modGraphNode struct { - m module.Version - required []module.Version - upgrade module.Version - err error + cmp := func(v1, v2 string) int { + if reqs.Max(v1, v2) != v1 { + return -1 + } + if reqs.Max(v2, v1) != v2 { + return 1 + } + return 0 } + var ( mu sync.Mutex - modGraph = map[module.Version]*modGraphNode{} - min = map[string]string{} // maps module path to minimum required version - haveErr int32 + g = NewGraph(cmp, []module.Version{target}) + upgrades = map[module.Version]module.Version{} + errs = map[module.Version]error{} // (non-nil errors only) ) - setErr := func(n *modGraphNode, err error) { - n.err = err - atomic.StoreInt32(&haveErr, 1) - } + // Explore work graph in parallel in case reqs.Required + // does high-latency network operations. var work par.Work work.Add(target) work.Do(10, func(item interface{}) { m := item.(module.Version) - node := &modGraphNode{m: m} - mu.Lock() - modGraph[m] = node + var required []module.Version + var err error if m.Version != "none" { - if v, ok := min[m.Path]; !ok || reqs.Max(v, m.Version) != v { - min[m.Path] = m.Version - } + required, err = reqs.Required(m) } - mu.Unlock() - if m.Version != "none" { - required, err := reqs.Required(m) - if err != nil { - setErr(node, err) - return - } - node.required = required - for _, r := range node.required { - work.Add(r) + u := m + if upgrade != nil { + upgradeTo, upErr := upgrade(m) + if upErr == nil { + u = upgradeTo + } else if err == nil { + err = upErr } } - if upgrade != nil { - u, err := upgrade(m) - if err != nil { - setErr(node, err) - return - } - if u != m { - node.upgrade = u - work.Add(u) - } + mu.Lock() + if err != nil { + errs[m] = err + } + if u != m { + upgrades[m] = u + required = append([]module.Version{u}, required...) + } + g.Require(m, required) + mu.Unlock() + + for _, r := range required { + work.Add(r) } }) // If there was an error, find the shortest path from the target to the // node where the error occurred so we can report a useful error message. - if haveErr != 0 { - // neededBy[a] = b means a was added to the module graph by b. - neededBy := make(map[*modGraphNode]*modGraphNode) - q := make([]*modGraphNode, 0, len(modGraph)) - q = append(q, modGraph[target]) - for len(q) > 0 { - node := q[0] - q = q[1:] - - if node.err != nil { - pathUpgrade := map[module.Version]module.Version{} - - // Construct the error path reversed (from the error to the main module), - // then reverse it to obtain the usual order (from the main module to - // the error). - errPath := []module.Version{node.m} - for n, prev := neededBy[node], node; n != nil; n, prev = neededBy[n], n { - if n.upgrade == prev.m { - pathUpgrade[n.m] = prev.m - } - errPath = append(errPath, n.m) - } - i, j := 0, len(errPath)-1 - for i < j { - errPath[i], errPath[j] = errPath[j], errPath[i] - i++ - j-- - } - - isUpgrade := func(from, to module.Version) bool { - return pathUpgrade[from] == to - } - - return nil, NewBuildListError(node.err, errPath, isUpgrade) - } + if len(errs) > 0 { + errPath := g.FindPath(func(m module.Version) bool { + return errs[m] != nil + }) + if len(errPath) == 0 { + panic("internal error: could not reconstruct path to module with error") + } - neighbors := node.required - if node.upgrade.Path != "" { - neighbors = append(neighbors, node.upgrade) - } - for _, neighbor := range neighbors { - nn := modGraph[neighbor] - if neededBy[nn] != nil { - continue - } - neededBy[nn] = node - q = append(q, nn) + err := errs[errPath[len(errPath)-1]] + isUpgrade := func(from, to module.Version) bool { + if u, ok := upgrades[from]; ok { + return u == to } + return false } + return nil, NewBuildListError(err.(error), errPath, isUpgrade) } // The final list is the minimum version of each module found in the graph. - - if v := min[target.Path]; v != target.Version { + list := g.BuildList() + if v := list[0]; v != target { // target.Version will be "" for modload, the main client of MVS. // "" denotes the main module, which has no version. However, MVS treats // version strings as opaque, so "" is not a special value here. // See golang.org/issue/31491, golang.org/issue/29773. - panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) // TODO: Don't panic. + panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) } - - list := []module.Version{target} - for path, vers := range min { - if path != target.Path { - list = append(list, module.Version{Path: path, Version: vers}) - } - - n := modGraph[module.Version{Path: path, Version: vers}] - required := n.required - for _, r := range required { - if r.Version == "none" { - continue - } - v := min[r.Path] - if r.Path != target.Path && reqs.Max(v, r.Version) != v { - panic(fmt.Sprintf("mistake: version %q does not satisfy requirement %+v", v, r)) // TODO: Don't panic. - } - } - } - - tail := list[1:] - sort.Slice(tail, func(i, j int) bool { - return tail[i].Path < tail[j].Path - }) return list, nil } -- GitLab From aa26687e457d825fc9c580e8c029b768e0e70d38 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 10 Mar 2021 16:06:47 -0500 Subject: [PATCH 0282/1298] runtime, time: disable preemption in addtimer The timerpMask optimization updates a mask of Ps (potentially) containing timers in pidleget / pidleput. For correctness, it depends on the assumption that new timers can only be added to a P's own heap. addtimer violates this assumption if it is preempted after computing pp. That G may then run on a different P, but adding a timer to the original P's heap. Avoid this by disabling preemption while pp is in use. Other uses of doaddtimer should be OK: * moveTimers: always moves to the current P's heap * modtimer, cleantimers, addAdjustedTimers, runtimer: does not add net new timers to the heap while locked Fixes #44868 Change-Id: I4a5d080865e854931d0a3a09a51ca36879101d72 Reviewed-on: https://go-review.googlesource.com/c/go/+/300610 Trust: Michael Pratt Run-TryBot: Michael Pratt Reviewed-by: Michael Knyszek Reviewed-by: Ian Lance Taylor TryBot-Result: Go Bot --- src/runtime/time.go | 5 +++++ src/time/sleep_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/runtime/time.go b/src/runtime/time.go index 8ab2a03430..dee6a674e4 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -263,6 +263,9 @@ func addtimer(t *timer) { when := t.when + // Disable preemption while using pp to avoid changing another P's heap. + mp := acquirem() + pp := getg().m.p.ptr() lock(&pp.timersLock) cleantimers(pp) @@ -270,6 +273,8 @@ func addtimer(t *timer) { unlock(&pp.timersLock) wakeNetPoller(when) + + releasem(mp) } // doaddtimer adds t to the current P's heap. diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index 084ac33f51..6ee0631a85 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -511,6 +511,22 @@ func TestZeroTimerStopPanics(t *testing.T) { tr.Stop() } +// Test that zero duration timers aren't missed by the scheduler. Regression test for issue 44868. +func TestZeroTimer(t *testing.T) { + if testing.Short() { + t.Skip("-short") + } + + for i := 0; i < 1000000; i++ { + s := Now() + ti := NewTimer(0) + <-ti.C + if diff := Since(s); diff > 2*Second { + t.Errorf("Expected time to get value from Timer channel in less than 2 sec, took %v", diff) + } + } +} + // Benchmark timer latency when the thread that creates the timer is busy with // other work and the timers must be serviced by other threads. // https://golang.org/issue/38860 -- GitLab From 1bad3831a0afe76d3403f564e89be6b76f8c6d98 Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Tue, 9 Mar 2021 16:54:56 -0600 Subject: [PATCH 0283/1298] cmd/internal/obj: remove param element from ppc64 optab This is rarely used, and is implied based on the memory type of the operand. This is a step towards simplifying the MOV* pseudo opcodes on ppc64. Similarly, remove the bogus param value from AVMULESB. Change-Id: Ibad4d045ec6d8c5163a468b2db1dfb762ef674ee Reviewed-on: https://go-review.googlesource.com/c/go/+/300177 Run-TryBot: Paul Murphy TryBot-Result: Go Bot Reviewed-by: Lynn Boger Trust: Ian Lance Taylor --- src/cmd/internal/obj/ppc64/asm9.go | 257 +++++++++++++++-------------- 1 file changed, 136 insertions(+), 121 deletions(-) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 648a41b5c7..e979cabddf 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -72,7 +72,6 @@ type Optab struct { a6 uint8 // p.To (obj.Addr) type_ int8 // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r size int8 // Text space in bytes to lay operation - param int16 // Implied base register for pseudo-registers } // optab contains an array to be sliced of accepted operand combinations for an @@ -202,73 +201,73 @@ var optab = []Optab{ {as: AFMUL, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 32, size: 4}, /* store, short offset */ - {as: AMOVD, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVD, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVW, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVWZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVBZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVB, a1: C_REG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AMOVD, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVW, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVBZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVB, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AMOVBU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVBZU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVBU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, /* load, short offset */ - {as: AMOVD, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVD, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVW, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVWZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVBZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4, param: REGSB}, - {as: AMOVB, a1: C_SEXT, a6: C_REG, type_: 9, size: 8, param: REGSB}, - {as: AMOVD, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVW, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVBZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4, param: REGSP}, - {as: AMOVB, a1: C_SAUTO, a6: C_REG, type_: 9, size: 8, param: REGSP}, - {as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4, param: REGZERO}, - {as: AMOVB, a1: C_SOREG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, - {as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 9, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVB, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, + {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, + {as: AMOVD, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVB, a1: C_SEXT, a6: C_REG, type_: 9, size: 8}, + {as: AMOVD, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVB, a1: C_SAUTO, a6: C_REG, type_: 9, size: 8}, + {as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVB, a1: C_SOREG, a6: C_REG, type_: 9, size: 8}, + {as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 9, size: 8}, /* store, long offset */ - {as: AMOVD, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVW, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVBZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVB, a1: C_REG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AMOVD, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVW, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVBZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVB, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVWZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVBZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, - {as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AMOVD, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, {as: AMOVD, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, {as: AMOVW, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, {as: AMOVWZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, @@ -276,21 +275,21 @@ var optab = []Optab{ {as: AMOVB, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, /* load, long offset */ - {as: AMOVD, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVW, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVBZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8, param: REGSB}, - {as: AMOVB, a1: C_LEXT, a6: C_REG, type_: 37, size: 12, param: REGSB}, - {as: AMOVD, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVW, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVBZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8, param: REGSP}, - {as: AMOVB, a1: C_LAUTO, a6: C_REG, type_: 37, size: 12, param: REGSP}, - {as: AMOVD, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVWZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8, param: REGZERO}, - {as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 37, size: 12, param: REGZERO}, + {as: AMOVD, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVWZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVB, a1: C_LEXT, a6: C_REG, type_: 37, size: 12}, + {as: AMOVD, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVWZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVB, a1: C_LAUTO, a6: C_REG, type_: 37, size: 12}, + {as: AMOVD, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVWZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 37, size: 12}, {as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, {as: AMOVW, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, {as: AMOVWZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, @@ -304,31 +303,31 @@ var optab = []Optab{ {as: AMOVD, a1: C_TOCADDR, a6: C_REG, type_: 95, size: 8}, /* load constant */ - {as: AMOVD, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, - {as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVD, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVD, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVD, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ - {as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVW, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVW, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVW, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_SECON, a6: C_REG, type_: 3, size: 4, param: REGSB}, /* TO DO: check */ - {as: AMOVWZ, a1: C_SACON, a6: C_REG, type_: 3, size: 4, param: REGSP}, - {as: AMOVWZ, a1: C_LECON, a6: C_REG, type_: 26, size: 8, param: REGSB}, - {as: AMOVWZ, a1: C_LACON, a6: C_REG, type_: 26, size: 8, param: REGSP}, - {as: AMOVWZ, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, - {as: AMOVWZ, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVD, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ + {as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVW, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ + {as: AMOVWZ, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVWZ, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVWZ, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, /* load unsigned/long constants (TO DO: check) */ - {as: AMOVD, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVD, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, {as: AMOVD, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, - {as: AMOVW, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVW, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, {as: AMOVW, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, - {as: AMOVWZ, a1: C_UCON, a6: C_REG, type_: 3, size: 4, param: REGZERO}, + {as: AMOVWZ, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, {as: AMOVWZ, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 45, size: 4}, {as: AMOVHBR, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, @@ -353,21 +352,21 @@ var optab = []Optab{ {as: ABC, a1: C_SCON, a2: C_REG, a6: C_LR, type_: 18, size: 4}, {as: ABC, a1: C_SCON, a2: C_REG, a6: C_CTR, type_: 18, size: 4}, {as: ABC, a6: C_ZOREG, type_: 15, size: 8}, - {as: AFMOVD, a1: C_SEXT, a6: C_FREG, type_: 8, size: 4, param: REGSB}, - {as: AFMOVD, a1: C_SAUTO, a6: C_FREG, type_: 8, size: 4, param: REGSP}, - {as: AFMOVD, a1: C_SOREG, a6: C_FREG, type_: 8, size: 4, param: REGZERO}, - {as: AFMOVD, a1: C_LEXT, a6: C_FREG, type_: 36, size: 8, param: REGSB}, - {as: AFMOVD, a1: C_LAUTO, a6: C_FREG, type_: 36, size: 8, param: REGSP}, - {as: AFMOVD, a1: C_LOREG, a6: C_FREG, type_: 36, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_SEXT, a6: C_FREG, type_: 8, size: 4}, + {as: AFMOVD, a1: C_SAUTO, a6: C_FREG, type_: 8, size: 4}, + {as: AFMOVD, a1: C_SOREG, a6: C_FREG, type_: 8, size: 4}, + {as: AFMOVD, a1: C_LEXT, a6: C_FREG, type_: 36, size: 8}, + {as: AFMOVD, a1: C_LAUTO, a6: C_FREG, type_: 36, size: 8}, + {as: AFMOVD, a1: C_LOREG, a6: C_FREG, type_: 36, size: 8}, {as: AFMOVD, a1: C_ZCON, a6: C_FREG, type_: 24, size: 4}, {as: AFMOVD, a1: C_ADDCON, a6: C_FREG, type_: 24, size: 8}, {as: AFMOVD, a1: C_ADDR, a6: C_FREG, type_: 75, size: 8}, - {as: AFMOVD, a1: C_FREG, a6: C_SEXT, type_: 7, size: 4, param: REGSB}, - {as: AFMOVD, a1: C_FREG, a6: C_SAUTO, type_: 7, size: 4, param: REGSP}, - {as: AFMOVD, a1: C_FREG, a6: C_SOREG, type_: 7, size: 4, param: REGZERO}, - {as: AFMOVD, a1: C_FREG, a6: C_LEXT, type_: 35, size: 8, param: REGSB}, - {as: AFMOVD, a1: C_FREG, a6: C_LAUTO, type_: 35, size: 8, param: REGSP}, - {as: AFMOVD, a1: C_FREG, a6: C_LOREG, type_: 35, size: 8, param: REGZERO}, + {as: AFMOVD, a1: C_FREG, a6: C_SEXT, type_: 7, size: 4}, + {as: AFMOVD, a1: C_FREG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AFMOVD, a1: C_FREG, a6: C_SOREG, type_: 7, size: 4}, + {as: AFMOVD, a1: C_FREG, a6: C_LEXT, type_: 35, size: 8}, + {as: AFMOVD, a1: C_FREG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AFMOVD, a1: C_FREG, a6: C_LOREG, type_: 35, size: 8}, {as: AFMOVD, a1: C_FREG, a6: C_ADDR, type_: 74, size: 8}, {as: AFMOVSX, a1: C_ZOREG, a2: C_REG, a6: C_FREG, type_: 45, size: 4}, {as: AFMOVSX, a1: C_ZOREG, a6: C_FREG, type_: 45, size: 4}, @@ -442,7 +441,7 @@ var optab = []Optab{ {as: AVSUBE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector subtract extended, va-form */ /* Vector multiply */ - {as: AVMULESB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4, param: 9}, /* vector multiply, vx-form */ + {as: AVMULESB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector multiply, vx-form */ {as: AVPMSUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector polynomial multiply & sum, vx-form */ {as: AVMSUMUDM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector multiply-sum, va-form */ @@ -684,6 +683,22 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int { return 0 } +// Get the implied register of a operand which doesn't specify one. These show up +// in handwritten asm like "MOVD R5, foosymbol" where a base register is not supplied, +// or "MOVD R5, foo+10(SP) or pseudo-register is used. The other common case is when +// generating constants in register like "MOVD $constant, Rx". +func getimpliedreg(a *obj.Addr) int { + switch oclass(a) { + case C_ZOREG, C_SOREG, C_LOREG, C_ADDCON, C_ANDCON, C_UCON, C_SCON, C_LCON: + return REGZERO + case C_SEXT, C_LEXT, C_SECON, C_LECON: + return REGSB + case C_SAUTO, C_LAUTO, C_SACON, C_LACON: + return REGSP + } + return 0 +} + func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p := cursym.Func().Text if p == nil || p.Link == nil { // handle external functions and ELF section symbols @@ -2506,7 +2521,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { v := int32(d) r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) { c.ctxt.Diag("literal operation on R0\n%v", p) @@ -2579,7 +2594,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.To.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.To) } v := c.regoff(&p.To) if p.To.Type == obj.TYPE_MEM && p.To.Index != 0 { @@ -2615,7 +2630,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } v := c.regoff(&p.From) if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 { @@ -2646,7 +2661,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } v := c.regoff(&p.From) if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 { @@ -3036,7 +3051,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { v := c.regoff(&p.From) r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v))) o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v)) @@ -3180,7 +3195,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.To.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.To) } // Offsets in DS form stores must be a multiple of 4 inst := c.opstore(p.As) @@ -3195,7 +3210,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v))) o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v)) @@ -3205,7 +3220,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { r := int(p.From.Reg) if r == 0 { - r = int(o.param) + r = getimpliedreg(&p.From) } o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v))) o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v)) -- GitLab From fdded79e6e3256118af182b42714d4d56f2000b0 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 9 Mar 2021 18:24:51 -0800 Subject: [PATCH 0284/1298] cmd/compile: fix handling of partially inferred type arguments In the case of partially inferred type arguments, we need to use the IndexExpr as the key in g.info.Inferred[] rather than the CallExpr. Added an extra fromStrings1 call in the settable.go test that tests partially inferred type arguments. This new call uses a new concrete type SettableString as well. I also added another implementation fromStrings3 (derived from a go2go tests) that typechecks but intentionally causes a panic. Change-Id: I74d35c5a741f72f37160a96fbec939451157f392 Reviewed-on: https://go-review.googlesource.com/c/go/+/300309 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/expr.go | 12 +++++- test/typeparam/settable.go | 55 +++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index b99f5a4cdd..06aa91199c 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -96,7 +96,17 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { case *syntax.CallExpr: fun := g.expr(expr.Fun) - if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 { + + // The key for the Inferred map is usually the expr. + key := syntax.Expr(expr) + if _, ok := expr.Fun.(*syntax.IndexExpr); ok { + // If the Fun is an IndexExpr, then this may be a + // partial type inference case. In this case, we look up + // the IndexExpr in the Inferred map. + // TODO(gri): should types2 always record the callExpr as the key? + key = syntax.Expr(expr.Fun) + } + if inferred, ok := g.info.Inferred[key]; ok && len(inferred.Targs) > 0 { targs := make([]ir.Node, len(inferred.Targs)) for i, targ := range inferred.Targs { targs[i] = ir.TypeNode(g.typ(targ)) diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go index f42c6574fe..29874fb189 100644 --- a/test/typeparam/settable.go +++ b/test/typeparam/settable.go @@ -11,11 +11,14 @@ import ( "strconv" ) +// Various implementations of fromStrings(). + type _Setter[B any] interface { Set(string) type *B } +// Takes two type parameters where PT = *T func fromStrings1[T any, PT _Setter[T]](s []string) []T { result := make([]T, len(s)) for i, v := range s { @@ -28,6 +31,7 @@ func fromStrings1[T any, PT _Setter[T]](s []string) []T { return result } +// Takes one type parameter and a set function func fromStrings2[T any](s []string, set func(*T, string)) []T { results := make([]T, len(s)) for i, v := range s { @@ -36,24 +40,65 @@ func fromStrings2[T any](s []string, set func(*T, string)) []T { return results } -type Settable int +type _Setter2 interface { + Set(string) +} + +// Takes only one type parameter, but causes a panic (see below) +func fromStrings3[T _Setter2](s []string) []T { + results := make([]T, len(s)) + for i, v := range s { + // Panics if T is a pointer type because receiver is T(nil). + results[i].Set(v) + } + return results +} + +// Two concrete types with the appropriate Set method. + +type SettableInt int -func (p *Settable) Set(s string) { +func (p *SettableInt) Set(s string) { i, err := strconv.Atoi(s) if err != nil { panic(err) } - *p = Settable(i) + *p = SettableInt(i) +} + +type SettableString struct { + s string +} + +func (x *SettableString) Set(s string) { + x.s = s } func main() { - s := fromStrings1[Settable, *Settable]([]string{"1"}) + s := fromStrings1[SettableInt, *SettableInt]([]string{"1"}) if len(s) != 1 || s[0] != 1 { panic(fmt.Sprintf("got %v, want %v", s, []int{1})) } - s = fromStrings2([]string{"1"}, func(p *Settable, s string) { p.Set(s) }) + // Test out constraint type inference, which should determine that the second + // type param is *SettableString. + ps := fromStrings1[SettableString]([]string{"x", "y"}) + if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) { + panic(s) + } + + s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) }) if len(s) != 1 || s[0] != 1 { panic(fmt.Sprintf("got %v, want %v", s, []int{1})) } + + defer func() { + if recover() == nil { + panic("did not panic as expected") + } + }() + // This should type check but should panic at run time, + // because it will make a slice of *SettableInt and then call + // Set on a nil value. + fromStrings3[*SettableInt]([]string{"1"}) } -- GitLab From 68f3344fe95dde95685b0d7fbbf74d13f3e9ee04 Mon Sep 17 00:00:00 2001 From: eric fang Date: Tue, 2 Mar 2021 06:05:00 +0000 Subject: [PATCH 0285/1298] cmd/compile: remove 8-byte alignment requirement of stack slot on ppc64 This CL applies CL 267999 to ppc64. Fixes #42385 Change-Id: I6462d647d1abdf7cec99607c40ef4d1fed1941e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/297770 Reviewed-by: eric fang Reviewed-by: Cherry Zhang Trust: eric fang --- src/cmd/compile/internal/ssagen/pgen.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index c2225ce950..8fa5980dab 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -19,7 +19,6 @@ import ( "cmd/internal/obj" "cmd/internal/objabi" "cmd/internal/src" - "cmd/internal/sys" ) // cmpstackvarlt reports whether the stack variable a sorts before b. @@ -133,9 +132,6 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { } else { lastHasPtr = false } - if Arch.LinkArch.InFamily(sys.PPC64) { - s.stksize = types.Rnd(s.stksize, int64(types.PtrSize)) - } n.SetFrameOffset(-s.stksize) } -- GitLab From 3a3b8164fdcb071955284c13cda6ee0f29fc8bd3 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Mon, 1 Mar 2021 10:34:08 +0800 Subject: [PATCH 0286/1298] cmd/dist: refactor test constraints for misc/cgo/testsantizers Currently, the cmd/dist runs test cases in misc/cgo/testsantizers only when memeory sanitizer is supported, but the tsan tests in misc/cgo/testsanitizers do not require support for -msan option, which makes tsan tests can not be run on some unsupported -msan option platforms. Therefore, this patch moves the test constraints from cmd/dist to msan_test.go, so that the tsan tests in misc/cgo/testsanitizers can be run on any system where the C compiler supports -fsanitize=thread option. Change-Id: I779c92eedd0270050f1a0b1a69ecce50c3712bc9 Reviewed-on: https://go-review.googlesource.com/c/go/+/297774 Trust: fannie zhang Run-TryBot: fannie zhang TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- misc/cgo/testsanitizers/cc_test.go | 11 +++++++++++ misc/cgo/testsanitizers/cshared_test.go | 11 +++++++++++ misc/cgo/testsanitizers/msan_test.go | 13 +++++++++++++ src/cmd/dist/test.go | 16 +++------------- src/cmd/internal/sys/supported.go | 3 ++- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/misc/cgo/testsanitizers/cc_test.go b/misc/cgo/testsanitizers/cc_test.go index 0192a663dd..dab13364b8 100644 --- a/misc/cgo/testsanitizers/cc_test.go +++ b/misc/cgo/testsanitizers/cc_test.go @@ -440,3 +440,14 @@ func hangProneCmd(name string, arg ...string) *exec.Cmd { } return cmd } + +// mSanSupported is a copy of the function cmd/internal/sys.MSanSupported, +// because the internal pacakage can't be used here. +func mSanSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "arm64" + default: + return false + } +} diff --git a/misc/cgo/testsanitizers/cshared_test.go b/misc/cgo/testsanitizers/cshared_test.go index 56063ea620..b98360c4ae 100644 --- a/misc/cgo/testsanitizers/cshared_test.go +++ b/misc/cgo/testsanitizers/cshared_test.go @@ -19,6 +19,12 @@ func TestShared(t *testing.T) { if err != nil { t.Fatal(err) } + + GOARCH, err := goEnv("GOARCH") + if err != nil { + t.Fatal(err) + } + libExt := "so" if GOOS == "darwin" { libExt = "dylib" @@ -41,6 +47,11 @@ func TestShared(t *testing.T) { for _, tc := range cases { tc := tc name := strings.TrimSuffix(tc.src, ".go") + //The memory sanitizer tests require support for the -msan option. + if tc.sanitizer == "memory" && !mSanSupported(GOOS, GOARCH) { + t.Logf("skipping %s test on %s/%s; -msan option is not supported.", name, GOOS, GOARCH) + continue + } t.Run(name, func(t *testing.T) { t.Parallel() config := configure(tc.sanitizer) diff --git a/misc/cgo/testsanitizers/msan_test.go b/misc/cgo/testsanitizers/msan_test.go index 5e2f9759ba..2a3494fbfc 100644 --- a/misc/cgo/testsanitizers/msan_test.go +++ b/misc/cgo/testsanitizers/msan_test.go @@ -10,6 +10,19 @@ import ( ) func TestMSAN(t *testing.T) { + goos, err := goEnv("GOOS") + if err != nil { + t.Fatal(err) + } + goarch, err := goEnv("GOARCH") + if err != nil { + t.Fatal(err) + } + // The msan tests require support for the -msan option. + if !mSanSupported(goos, goarch) { + t.Skipf("skipping on %s/%s; -msan option is not supported.", goos, goarch) + } + t.Parallel() requireOvercommit(t) config := configure("memory") diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 0c8e2c56bc..cbf3ec6d88 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -736,8 +736,9 @@ func (t *tester) registerTests() { if gohostos == "linux" && goarch == "amd64" { t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".") } - if mSanSupported(goos, goarch) { - t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") + if goos == "linux" { + // because syscall.SysProcAttri struct used in misc/cgo/testsanitizers is only built on linux. + t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") } if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" { t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".") @@ -1640,17 +1641,6 @@ func raceDetectorSupported(goos, goarch string) bool { } } -// mSanSupported is a copy of the function cmd/internal/sys.MSanSupported, -// which can't be used here because cmd/dist has to be buildable by Go 1.4. -func mSanSupported(goos, goarch string) bool { - switch goos { - case "linux": - return goarch == "amd64" || goarch == "arm64" - default: - return false - } -} - // isUnsupportedVMASize reports whether the failure is caused by an unsupported // VMA for the race detector (for example, running the race detector on an // arm64 machine configured with 39-bit VMA) diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 291acf0862..fa477b837f 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -23,7 +23,8 @@ func RaceDetectorSupported(goos, goarch string) bool { } // MSanSupported reports whether goos/goarch supports the memory -// sanitizer option. There is a copy of this function in cmd/dist/test.go. +// sanitizer option. +// There is a copy of this function in misc/cgo/testsanitizers/cc_test.go. func MSanSupported(goos, goarch string) bool { switch goos { case "linux": -- GitLab From 79e3ee52f48411eb7c4edfe3daa55e2ecf7a6c61 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 10 Mar 2021 10:06:11 +0100 Subject: [PATCH 0287/1298] internal/syscall/unix: unify GetRandom implementation The implementation of GetRandom for Linux, FreeBSD and DragonflyBSD can be shared. Also remove GRND_INSECURE on DragonflyBSD as pointed out by Ian in the review of CL 269999. Change-Id: I5bf4c1bd51ddb2ad600652a57e0bc1bafa1cf40d Reviewed-on: https://go-review.googlesource.com/c/go/+/299133 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/internal/syscall/unix/getrandom.go | 40 +++++++++++++++++++ .../syscall/unix/getrandom_dragonfly.go | 37 +---------------- .../syscall/unix/getrandom_freebsd.go | 34 +--------------- src/internal/syscall/unix/getrandom_linux.go | 33 --------------- 4 files changed, 42 insertions(+), 102 deletions(-) create mode 100644 src/internal/syscall/unix/getrandom.go diff --git a/src/internal/syscall/unix/getrandom.go b/src/internal/syscall/unix/getrandom.go new file mode 100644 index 0000000000..d2c58c0f6f --- /dev/null +++ b/src/internal/syscall/unix/getrandom.go @@ -0,0 +1,40 @@ +// Copyright 2021 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. + +//go:build dragonfly || freebsd || linux +// +build dragonfly freebsd linux + +package unix + +import ( + "sync/atomic" + "syscall" + "unsafe" +) + +var getrandomUnsupported int32 // atomic + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +// GetRandom calls the getrandom system call. +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&getrandomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + r1, _, errno := syscall.Syscall(getrandomTrap, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags)) + if errno != 0 { + if errno == syscall.ENOSYS { + atomic.StoreInt32(&getrandomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} diff --git a/src/internal/syscall/unix/getrandom_dragonfly.go b/src/internal/syscall/unix/getrandom_dragonfly.go index b345b4c00c..fbf78f9de8 100644 --- a/src/internal/syscall/unix/getrandom_dragonfly.go +++ b/src/internal/syscall/unix/getrandom_dragonfly.go @@ -4,19 +4,8 @@ package unix -import ( - "sync/atomic" - "syscall" - "unsafe" -) - -var randomUnsupported int32 // atomic - // DragonFlyBSD getrandom system call number. -const randomTrap uintptr = 550 - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr +const getrandomTrap uintptr = 550 const ( // GRND_RANDOM is only set for portability purpose, no-op on DragonFlyBSD. @@ -24,28 +13,4 @@ const ( // GRND_NONBLOCK means return EAGAIN rather than blocking. GRND_NONBLOCK GetRandomFlag = 0x0002 - - // GRND_INSECURE is an GRND_NONBLOCK alias - GRND_INSECURE GetRandomFlag = 0x0004 ) - -// GetRandom calls the DragonFlyBSD getrandom system call. -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, syscall.ENOSYS - } - r1, _, errno := syscall.Syscall(randomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == syscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} diff --git a/src/internal/syscall/unix/getrandom_freebsd.go b/src/internal/syscall/unix/getrandom_freebsd.go index f1ba5730c9..8c4f3dff82 100644 --- a/src/internal/syscall/unix/getrandom_freebsd.go +++ b/src/internal/syscall/unix/getrandom_freebsd.go @@ -4,19 +4,8 @@ package unix -import ( - "sync/atomic" - "syscall" - "unsafe" -) - -var randomUnsupported int32 // atomic - // FreeBSD getrandom system call number. -const randomTrap uintptr = 563 - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr +const getrandomTrap uintptr = 563 const ( // GRND_NONBLOCK means return EAGAIN rather than blocking. @@ -25,24 +14,3 @@ const ( // GRND_RANDOM is only set for portability purpose, no-op on FreeBSD. GRND_RANDOM GetRandomFlag = 0x0002 ) - -// GetRandom calls the FreeBSD getrandom system call. -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, syscall.ENOSYS - } - r1, _, errno := syscall.Syscall(randomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == syscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} diff --git a/src/internal/syscall/unix/getrandom_linux.go b/src/internal/syscall/unix/getrandom_linux.go index 490d516978..8ccd8d328a 100644 --- a/src/internal/syscall/unix/getrandom_linux.go +++ b/src/internal/syscall/unix/getrandom_linux.go @@ -4,17 +4,6 @@ package unix -import ( - "sync/atomic" - "syscall" - "unsafe" -) - -var randomUnsupported int32 // atomic - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr - const ( // GRND_NONBLOCK means return EAGAIN rather than blocking. GRND_NONBLOCK GetRandomFlag = 0x0001 @@ -22,25 +11,3 @@ const ( // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. GRND_RANDOM GetRandomFlag = 0x0002 ) - -// GetRandom calls the Linux getrandom system call. -// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, syscall.ENOSYS - } - r1, _, errno := syscall.Syscall(getrandomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == syscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} -- GitLab From 9ece63f0647ec34cc729ad71a87254193014dcca Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 10 Mar 2021 10:26:20 +0100 Subject: [PATCH 0288/1298] crypto/rand, internal/syscall/unix: add support for getrandom syscall on solaris The getrandom syscall is available on Solaris and Illumos, see https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html and https://illumos.org/man/2/getrandom Change-Id: Id1c65d6a5b2fbc80d20b43d8b32dab137ca950ca Reviewed-on: https://go-review.googlesource.com/c/go/+/299134 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/crypto/rand/rand_batched.go | 4 +- src/crypto/rand/rand_batched_test.go | 4 +- src/crypto/rand/rand_solaris.go | 10 ++++ .../syscall/unix/getrandom_solaris.go | 53 +++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/crypto/rand/rand_solaris.go create mode 100644 src/internal/syscall/unix/getrandom_solaris.go diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go index 538769a868..d7c5bf3562 100644 --- a/src/crypto/rand/rand_batched.go +++ b/src/crypto/rand/rand_batched.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux || freebsd || dragonfly -// +build linux freebsd dragonfly +//go:build linux || freebsd || dragonfly || solaris +// +build linux freebsd dragonfly solaris package rand diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go index 814f15201a..2d20922c82 100644 --- a/src/crypto/rand/rand_batched_test.go +++ b/src/crypto/rand/rand_batched_test.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux || freebsd || dragonfly -// +build linux freebsd dragonfly +//go:build linux || freebsd || dragonfly || solaris +// +build linux freebsd dragonfly solaris package rand diff --git a/src/crypto/rand/rand_solaris.go b/src/crypto/rand/rand_solaris.go new file mode 100644 index 0000000000..bbad0fe557 --- /dev/null +++ b/src/crypto/rand/rand_solaris.go @@ -0,0 +1,10 @@ +// Copyright 2021 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 rand + +// maxGetRandomRead is the maximum number of bytes to ask for in one call to the +// getrandom() syscall. Across all the Solaris platforms, 256 bytes is the +// lowest number of bytes returned atomically per call. +const maxGetRandomRead = 1 << 8 diff --git a/src/internal/syscall/unix/getrandom_solaris.go b/src/internal/syscall/unix/getrandom_solaris.go new file mode 100644 index 0000000000..d86775cd98 --- /dev/null +++ b/src/internal/syscall/unix/getrandom_solaris.go @@ -0,0 +1,53 @@ +// Copyright 2021 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 unix + +import ( + "sync/atomic" + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_getrandom getrandom "libc.so" + +//go:linkname procGetrandom libc_getrandom + +var procGetrandom uintptr + +var getrandomUnsupported int32 // atomic + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +const ( + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0001 + + // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. + GRND_RANDOM GetRandomFlag = 0x0002 +) + +// GetRandom calls the getrandom system call. +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&getrandomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + r1, _, errno := syscall6(uintptr(unsafe.Pointer(&procGetrandom)), + 3, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags), + 0, 0, 0) + if errno != 0 { + if errno == syscall.ENOSYS { + atomic.StoreInt32(&getrandomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} -- GitLab From b8e9ec856c2b2d717ab14e85f43e00b532c4370a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 10 Mar 2021 07:21:56 -0700 Subject: [PATCH 0289/1298] syscall: use runtime.KeepAlive for ProcThreadAttributeList arguments It turns out that if you write Go pointers to Go memory, the Go compiler must be involved so that it generates various calls to the GC in the process. Letting Windows write Go pointers to Go memory violated this. So, we replace that with just a boring call to runtime.KeepAlive. That's not a great API, but this is all internal code anyway. We fix it up more elegantly for external consumption in x/sys/windows with CL 300369. Fixes #44900. Change-Id: Id6599a793af9c4815f6c9387b00796923f32cb97 Reviewed-on: https://go-review.googlesource.com/c/go/+/300349 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/syscall/exec_windows.go | 3 +++ src/syscall/syscall_windows.go | 2 +- src/syscall/syscall_windows_test.go | 36 ----------------------------- src/syscall/types_windows.go | 8 +------ 4 files changed, 5 insertions(+), 44 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index b20a27d28b..253e9e8c1f 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -7,6 +7,7 @@ package syscall import ( + "runtime" "sync" "unicode/utf16" "unsafe" @@ -368,6 +369,8 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle return 0, 0, err } defer CloseHandle(Handle(pi.Thread)) + runtime.KeepAlive(fd) + runtime.KeepAlive(sys) return int(pi.ProcessId), uintptr(pi.Process), nil } diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 05a7d3027d..65af6637ae 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -1257,7 +1257,7 @@ func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LI return nil, err } // size is guaranteed to be ≥1 by initializeProcThreadAttributeList. - al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]unsafe.Pointer, (size+ptrSize-1)/ptrSize)[0])) + al := (*_PROC_THREAD_ATTRIBUTE_LIST)(unsafe.Pointer(&make([]byte, size)[0])) err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size) if err != nil { return nil, err diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index d5e8d58b5a..a9ae54752b 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -7,11 +7,8 @@ package syscall_test import ( "os" "path/filepath" - "runtime" "syscall" "testing" - "time" - "unsafe" ) func TestWin32finddata(t *testing.T) { @@ -78,36 +75,3 @@ func TestTOKEN_ALL_ACCESS(t *testing.T) { t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", syscall.TOKEN_ALL_ACCESS) } } - -func TestProcThreadAttributeListPointers(t *testing.T) { - list, err := syscall.NewProcThreadAttributeList(1) - if err != nil { - t.Errorf("unable to create ProcThreadAttributeList: %v", err) - } - done := make(chan struct{}) - fds := make([]syscall.Handle, 20) - runtime.SetFinalizer(&fds[0], func(*syscall.Handle) { - close(done) - }) - err = syscall.UpdateProcThreadAttribute(list, 0, syscall.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fds[0]), uintptr(len(fds))*unsafe.Sizeof(fds[0]), nil, nil) - if err != nil { - syscall.DeleteProcThreadAttributeList(list) - t.Errorf("unable to update ProcThreadAttributeList: %v", err) - return - } - runtime.GC() - runtime.GC() - select { - case <-done: - t.Error("ProcThreadAttributeList was garbage collected unexpectedly") - default: - } - syscall.DeleteProcThreadAttributeList(list) - runtime.GC() - runtime.GC() - select { - case <-done: - case <-time.After(time.Second): - t.Error("ProcThreadAttributeList was not garbage collected after a second") - } -} diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index 31fe7664c9..384b5b4f2c 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -4,8 +4,6 @@ package syscall -import "unsafe" - const ( // Windows errors. ERROR_FILE_NOT_FOUND Errno = 2 @@ -493,11 +491,7 @@ type StartupInfo struct { } type _PROC_THREAD_ATTRIBUTE_LIST struct { - // This is of type unsafe.Pointer, not of type byte or uintptr, because - // the contents of it is mostly a list of pointers, and in most cases, - // that's a list of pointers to Go-allocated objects. In order to keep - // the GC from collecting these objects, we declare this as unsafe.Pointer. - _ [1]unsafe.Pointer + _ [1]byte } const ( -- GitLab From 0fc370c5d26353a865a29a01f093942c949d530a Mon Sep 17 00:00:00 2001 From: "Matt T. Proud" Date: Thu, 25 Feb 2021 01:03:35 +0100 Subject: [PATCH 0290/1298] docs: clarify when APIs use context.Background. The Go standard library retrofitted context support onto existing APIs using context.Background and later offered variants that directly supported user-defined context value specification. This commit makes that behavior clear in documentation and suggests context-aware alternatives if the user is looking for one. An example motivation is supporting code for use in systems that expect APIs to be cancelable for lifecycle correctness or load shedding/management reasons, as alluded to in https://blog.golang.org/context-and-structs. Updates #44143 Change-Id: I2d7f954ddf9b48264d5ebc8d0007058ff9bddf14 Reviewed-on: https://go-review.googlesource.com/c/go/+/296152 Reviewed-by: Ian Lance Taylor Reviewed-by: Jean de Klerk Trust: Jean de Klerk Run-TryBot: Jean de Klerk TryBot-Result: Go Bot --- src/crypto/tls/tls.go | 6 ++++++ src/database/sql/sql.go | 42 ++++++++++++++++++++++++++++++++++++ src/net/dial.go | 9 ++++++++ src/net/http/request.go | 2 +- src/net/http/socks_bundle.go | 2 ++ src/net/lookup.go | 21 ++++++++++++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go index a389873d32..4989364958 100644 --- a/src/crypto/tls/tls.go +++ b/src/crypto/tls/tls.go @@ -111,6 +111,9 @@ func (timeoutError) Temporary() bool { return true } // // DialWithDialer interprets a nil configuration as equivalent to the zero // configuration; see the documentation of Config for the defaults. +// +// DialWithDialer uses context.Background internally; to specify the context, +// use Dialer.DialContext with NetDialer set to the desired dialer. func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { return dial(context.Background(), dialer, network, addr, config) } @@ -224,6 +227,9 @@ type Dialer struct { // handshake, returning the resulting TLS connection. // // The returned Conn, if any, will always be of type *Conn. +// +// Dial uses context.Background internally; to specify the context, +// use DialContext. func (d *Dialer) Dial(network, addr string) (net.Conn, error) { return d.DialContext(context.Background(), network, addr) } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 37bcb0d091..12cc524c63 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -813,6 +813,9 @@ func (db *DB) PingContext(ctx context.Context) error { // Ping verifies a connection to the database is still alive, // establishing a connection if necessary. +// +// Ping uses context.Background internally; to specify the context, use +// PingContext. func (db *DB) Ping() error { return db.PingContext(context.Background()) } @@ -1481,6 +1484,9 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) { // returned statement. // The caller must call the statement's Close method // when the statement is no longer needed. +// +// Prepare uses context.Background internally; to specify the context, use +// PrepareContext. func (db *DB) Prepare(query string) (*Stmt, error) { return db.PrepareContext(context.Background(), query) } @@ -1551,6 +1557,9 @@ func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{} // Exec executes a query without returning any rows. // The args are for any placeholder parameters in the query. +// +// Exec uses context.Background internally; to specify the context, use +// ExecContext. func (db *DB) Exec(query string, args ...interface{}) (Result, error) { return db.ExecContext(context.Background(), query, args...) } @@ -1621,6 +1630,9 @@ func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{ // Query executes a query that returns rows, typically a SELECT. // The args are for any placeholder parameters in the query. +// +// Query uses context.Background internally; to specify the context, use +// QueryContext. func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { return db.QueryContext(context.Background(), query, args...) } @@ -1719,6 +1731,9 @@ func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interfa // If the query selects no rows, the *Row's Scan will return ErrNoRows. // Otherwise, the *Row's Scan scans the first selected row and discards // the rest. +// +// QueryRow uses context.Background internally; to specify the context, use +// QueryRowContext. func (db *DB) QueryRow(query string, args ...interface{}) *Row { return db.QueryRowContext(context.Background(), query, args...) } @@ -1750,6 +1765,9 @@ func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) { // Begin starts a transaction. The default isolation level is dependent on // the driver. +// +// Begin uses context.Background internally; to specify the context, use +// BeginTx. func (db *DB) Begin() (*Tx, error) { return db.BeginTx(context.Background(), nil) } @@ -2255,6 +2273,9 @@ func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) { // be used once the transaction has been committed or rolled back. // // To use an existing prepared statement on this transaction, see Tx.Stmt. +// +// Prepare uses context.Background internally; to specify the context, use +// PrepareContext. func (tx *Tx) Prepare(query string) (*Stmt, error) { return tx.PrepareContext(context.Background(), query) } @@ -2358,6 +2379,9 @@ func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { // // The returned statement operates within the transaction and will be closed // when the transaction has been committed or rolled back. +// +// Stmt uses context.Background internally; to specify the context, use +// StmtContext. func (tx *Tx) Stmt(stmt *Stmt) *Stmt { return tx.StmtContext(context.Background(), stmt) } @@ -2374,6 +2398,9 @@ func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{} // Exec executes a query that doesn't return rows. // For example: an INSERT and UPDATE. +// +// Exec uses context.Background internally; to specify the context, use +// ExecContext. func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) { return tx.ExecContext(context.Background(), query, args...) } @@ -2389,6 +2416,9 @@ func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{ } // Query executes a query that returns rows, typically a SELECT. +// +// Query uses context.Background internally; to specify the context, use +// QueryContext. func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { return tx.QueryContext(context.Background(), query, args...) } @@ -2410,6 +2440,9 @@ func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interfa // If the query selects no rows, the *Row's Scan will return ErrNoRows. // Otherwise, the *Row's Scan scans the first selected row and discards // the rest. +// +// QueryRow uses context.Background internally; to specify the context, use +// QueryRowContext. func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { return tx.QueryRowContext(context.Background(), query, args...) } @@ -2516,6 +2549,9 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, er // Exec executes a prepared statement with the given arguments and // returns a Result summarizing the effect of the statement. +// +// Exec uses context.Background internally; to specify the context, use +// ExecContext. func (s *Stmt) Exec(args ...interface{}) (Result, error) { return s.ExecContext(context.Background(), args...) } @@ -2687,6 +2723,9 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er // Query executes a prepared query statement with the given arguments // and returns the query results as a *Rows. +// +// Query uses context.Background internally; to specify the context, use +// QueryContext. func (s *Stmt) Query(args ...interface{}) (*Rows, error) { return s.QueryContext(context.Background(), args...) } @@ -2726,6 +2765,9 @@ func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row { // // var name string // err := nameByUseridStmt.QueryRow(id).Scan(&name) +// +// QueryRow uses context.Background internally; to specify the context, use +// QueryRowContext. func (s *Stmt) QueryRow(args ...interface{}) *Row { return s.QueryRowContext(context.Background(), args...) } diff --git a/src/net/dial.go b/src/net/dial.go index 13a312a91a..486ced0f2a 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -344,6 +344,9 @@ type sysDialer struct { // // See func Dial for a description of the network and address // parameters. +// +// Dial uses context.Background internally; to specify the context, use +// DialContext. func (d *Dialer) Dial(network, address string) (Conn, error) { return d.DialContext(context.Background(), network, address) } @@ -701,6 +704,9 @@ type sysListener struct { // // See func Dial for a description of the network and address // parameters. +// +// Listen uses context.Background internally; to specify the context, use +// ListenConfig.Listen. func Listen(network, address string) (Listener, error) { var lc ListenConfig return lc.Listen(context.Background(), network, address) @@ -728,6 +734,9 @@ func Listen(network, address string) (Listener, error) { // // See func Dial for a description of the network and address // parameters. +// +// ListenPacket uses context.Background internally; to specify the context, use +// ListenConfig.ListenPacket. func ListenPacket(network, address string) (PacketConn, error) { var lc ListenConfig return lc.ListenPacket(context.Background(), network, address) diff --git a/src/net/http/request.go b/src/net/http/request.go index adba5406e9..5251ebea66 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -823,7 +823,7 @@ func validMethod(method string) bool { return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1 } -// NewRequest wraps NewRequestWithContext using the background context. +// NewRequest wraps NewRequestWithContext using context.Background. func NewRequest(method, url string, body io.Reader) (*Request, error) { return NewRequestWithContext(context.Background(), method, url, body) } diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go index e446669589..fc22391039 100644 --- a/src/net/http/socks_bundle.go +++ b/src/net/http/socks_bundle.go @@ -362,6 +362,8 @@ func (d *socksDialer) DialWithConn(ctx context.Context, c net.Conn, network, add // Unlike DialContext, it returns a raw transport connection instead // of a forward proxy connection. // +// Dial uses context.Background internally. +// // Deprecated: Use DialContext or DialWithConn instead. func (d *socksDialer) Dial(network, address string) (net.Conn, error) { if err := d.validateTarget(network, address); err != nil { diff --git a/src/net/lookup.go b/src/net/lookup.go index 5f7119872a..03599503bd 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -166,6 +166,9 @@ func (r *Resolver) getLookupGroup() *singleflight.Group { // LookupHost looks up the given host using the local resolver. // It returns a slice of that host's addresses. +// +// LookupHost uses context.Background internally; to specify the context, use +// Resolver.LookupHost. func LookupHost(host string) (addrs []string, err error) { return DefaultResolver.LookupHost(context.Background(), host) } @@ -353,6 +356,9 @@ func ipAddrsEface(addrs []IPAddr) []interface{} { } // LookupPort looks up the port for the given network and service. +// +// LookupPort uses context.Background internally; to specify the context, use +// Resolver.LookupPort. func LookupPort(network, service string) (port int, err error) { return DefaultResolver.LookupPort(context.Background(), network, service) } @@ -389,6 +395,9 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. +// +// LookupCNAME uses context.Background internally; to specify the context, use +// Resolver.LookupCNAME. func LookupCNAME(host string) (cname string, err error) { return DefaultResolver.lookupCNAME(context.Background(), host) } @@ -434,6 +443,9 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) ( } // LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// LookupMX uses context.Background internally; to specify the context, use +// Resolver.LookupMX. func LookupMX(name string) ([]*MX, error) { return DefaultResolver.lookupMX(context.Background(), name) } @@ -444,6 +456,9 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { } // LookupNS returns the DNS NS records for the given domain name. +// +// LookupNS uses context.Background internally; to specify the context, use +// Resolver.LookupNS. func LookupNS(name string) ([]*NS, error) { return DefaultResolver.lookupNS(context.Background(), name) } @@ -454,6 +469,9 @@ func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { } // LookupTXT returns the DNS TXT records for the given domain name. +// +// LookupTXT uses context.Background internally; to specify the context, use +// Resolver.LookupTXT. func LookupTXT(name string) ([]string, error) { return DefaultResolver.lookupTXT(context.Background(), name) } @@ -468,6 +486,9 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) // // When using the host C library resolver, at most one result will be // returned. To bypass the host resolver, use a custom Resolver. +// +// LookupAddr uses context.Background internally; to specify the context, use +// Resolver.LookupAddr. func LookupAddr(addr string) (names []string, err error) { return DefaultResolver.lookupAddr(context.Background(), addr) } -- GitLab From 415ca3f1f0fa05a98561752e0787f59b77f19645 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 10 Mar 2021 19:35:22 -0800 Subject: [PATCH 0291/1298] test: add test that caused a gofrontend internal error For #44383 Change-Id: I3610105dad3574e210e226d3ba80a4ba5a7eeaa6 Reviewed-on: https://go-review.googlesource.com/c/go/+/300789 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick Reviewed-by: Than McIntosh Reviewed-by: Cherry Zhang --- test/fixedbugs/issue44383.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 test/fixedbugs/issue44383.go diff --git a/test/fixedbugs/issue44383.go b/test/fixedbugs/issue44383.go new file mode 100644 index 0000000000..d2d57524d1 --- /dev/null +++ b/test/fixedbugs/issue44383.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2021 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 44383: gofrontend internal compiler error + +package main + +func main() { + var b1, b2 byte + f := func() int { + var m map[byte]int + return m[b1/b2] + } + f() +} -- GitLab From f009b5b2268a7fcdfe046057cbf2a75306dbfc5e Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 22 Oct 2020 16:55:55 +0000 Subject: [PATCH 0292/1298] runtime: support register ABI for finalizers This change modifies runfinq to properly pass arguments to finalizers in registers via reflectcall. For #40724. Change-Id: I414c0eff466ef315a0eb10507994e598dd29ccb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/300112 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/runtime/abi_test.go | 116 +++++++++++++++++++++++++++++++++++++ src/runtime/export_test.go | 15 +++++ src/runtime/mfinal.go | 46 ++++++++++----- src/runtime/stubs.go | 28 +++++++++ 4 files changed, 191 insertions(+), 14 deletions(-) create mode 100644 src/runtime/abi_test.go diff --git a/src/runtime/abi_test.go b/src/runtime/abi_test.go new file mode 100644 index 0000000000..fa365c0832 --- /dev/null +++ b/src/runtime/abi_test.go @@ -0,0 +1,116 @@ +// Copyright 2021 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 goexperiment.regabi +//go:build goexperiment.regabi + +// This file contains tests specific to making sure the register ABI +// works in a bunch of contexts in the runtime. + +package runtime_test + +import ( + "internal/abi" + "internal/testenv" + "os" + "os/exec" + "runtime" + "strings" + "testing" + "time" +) + +var regConfirmRun int + +//go:registerparams +func regFinalizerPointer(v *Tint) (int, float32, [10]byte) { + regConfirmRun = *(*int)(v) + return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +} + +//go:registerparams +func regFinalizerIface(v Tinter) (int, float32, [10]byte) { + regConfirmRun = *(*int)(v.(*Tint)) + return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +} + +func TestFinalizerRegisterABI(t *testing.T) { + testenv.MustHaveExec(t) + + // Actually run the test in a subprocess because we don't want + // finalizers from other tests interfering. + if os.Getenv("TEST_FINALIZER_REGABI") != "1" { + cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestFinalizerRegisterABI", "-test.v")) + cmd.Env = append(cmd.Env, "TEST_FINALIZER_REGABI=1") + out, err := cmd.CombinedOutput() + if !strings.Contains(string(out), "PASS\n") || err != nil { + t.Fatalf("%s\n(exit status %v)", string(out), err) + } + return + } + + // Optimistically clear any latent finalizers from e.g. the testing + // package before continuing. + // + // It's possible that a finalizer only becomes available to run + // after this point, which would interfere with the test and could + // cause a crash, but because we're running in a separate process + // it's extremely unlikely. + runtime.GC() + runtime.GC() + + // fing will only pick the new IntRegArgs up if it's currently + // sleeping and wakes up, so wait for it to go to sleep. + success := false + for i := 0; i < 100; i++ { + if runtime.FinalizerGAsleep() { + success = true + break + } + time.Sleep(20 * time.Millisecond) + } + if !success { + t.Fatal("finalizer not asleep?") + } + + argRegsBefore := runtime.SetIntArgRegs(abi.IntArgRegs) + defer runtime.SetIntArgRegs(argRegsBefore) + + tests := []struct { + name string + fin interface{} + confirmValue int + }{ + {"Pointer", regFinalizerPointer, -1}, + {"Interface", regFinalizerIface, -2}, + } + for i := range tests { + test := &tests[i] + t.Run(test.name, func(t *testing.T) { + regConfirmRun = 0 + + x := new(Tint) + *x = (Tint)(test.confirmValue) + runtime.SetFinalizer(x, test.fin) + + runtime.KeepAlive(x) + + // Queue the finalizer. + runtime.GC() + runtime.GC() + + for i := 0; i < 100; i++ { + time.Sleep(10 * time.Millisecond) + if regConfirmRun != 0 { + break + } + } + if regConfirmRun == 0 { + t.Fatal("finalizer failed to execute") + } else if regConfirmRun != test.confirmValue { + t.Fatalf("wrong finalizer executed? regConfirmRun = %d", regConfirmRun) + } + }) + } +} diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 5a87024b8a..195b7b0519 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -1220,3 +1220,18 @@ func (th *TimeHistogram) Count(bucket, subBucket uint) (uint64, bool) { func (th *TimeHistogram) Record(duration int64) { (*timeHistogram)(th).record(duration) } + +func SetIntArgRegs(a int) int { + lock(&finlock) + old := intArgRegs + intArgRegs = a + unlock(&finlock) + return old +} + +func FinalizerGAsleep() bool { + lock(&finlock) + result := fingwait + unlock(&finlock) + return result +} diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index e92ec80e3c..fd318d49a8 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -163,6 +163,7 @@ func runfinq() { var ( frame unsafe.Pointer framecap uintptr + argRegs int ) for { @@ -176,6 +177,7 @@ func runfinq() { goparkunlock(&finlock, waitReasonFinalizerWait, traceEvGoBlock, 1) continue } + argRegs = intArgRegs unlock(&finlock) if raceenabled { racefingo() @@ -184,7 +186,22 @@ func runfinq() { for i := fb.cnt; i > 0; i-- { f := &fb.fin[i-1] - framesz := unsafe.Sizeof((interface{})(nil)) + f.nret + var regs abi.RegArgs + var framesz uintptr + if argRegs > 0 { + // The args can always be passed in registers if they're + // available, because platforms we support always have no + // argument registers available, or more than 2. + // + // But unfortunately because we can have an arbitrary + // amount of returns and it would be complex to try and + // figure out how many of those can get passed in registers, + // just conservatively assume none of them do. + framesz = f.nret + } else { + // Need to pass arguments on the stack too. + framesz = unsafe.Sizeof((interface{})(nil)) + f.nret + } if framecap < framesz { // The frame does not contain pointers interesting for GC, // all not yet finalized objects are stored in finq. @@ -197,33 +214,34 @@ func runfinq() { if f.fint == nil { throw("missing type in runfinq") } - // frame is effectively uninitialized - // memory. That means we have to clear - // it before writing to it to avoid - // confusing the write barrier. - *(*[2]uintptr)(frame) = [2]uintptr{} + r := frame + if argRegs > 0 { + r = unsafe.Pointer(®s.Ints) + } else { + // frame is effectively uninitialized + // memory. That means we have to clear + // it before writing to it to avoid + // confusing the write barrier. + *(*[2]uintptr)(frame) = [2]uintptr{} + } switch f.fint.kind & kindMask { case kindPtr: // direct use of pointer - *(*unsafe.Pointer)(frame) = f.arg + *(*unsafe.Pointer)(r) = f.arg case kindInterface: ityp := (*interfacetype)(unsafe.Pointer(f.fint)) // set up with empty interface - (*eface)(frame)._type = &f.ot.typ - (*eface)(frame).data = f.arg + (*eface)(r)._type = &f.ot.typ + (*eface)(r).data = f.arg if len(ityp.mhdr) != 0 { // convert to interface with methods // this conversion is guaranteed to succeed - we checked in SetFinalizer - (*iface)(frame).tab = assertE2I(ityp, (*eface)(frame)._type) + (*iface)(r).tab = assertE2I(ityp, (*eface)(r)._type) } default: throw("bad kind in runfinq") } fingRunning = true - // Pass a dummy RegArgs for now. - // - // TODO(mknyszek): Pass arguments in registers. - var regs abi.RegArgs reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz), uint32(framesz), ®s) fingRunning = false diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 5011d7199e..a2e04a64a5 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -396,3 +396,31 @@ func addmoduledata() // Injected by the signal handler for panicking signals. On many platforms it just // jumps to sigpanic. func sigpanic0() + +// intArgRegs is used by the various register assignment +// algorithm implementations in the runtime. These include:. +// - Finalizers (mfinal.go) +// - Windows callbacks (syscall_windows.go) +// +// Both are stripped-down versions of the algorithm since they +// only have to deal with a subset of cases (finalizers only +// take a pointer or interface argument, Go Windows callbacks +// don't support floating point). +// +// It should be modified with care and are generally only +// modified when testing this package. +// +// It should never be set higher than its internal/abi +// constant counterparts, because the system relies on a +// structure that is at least large enough to hold the +// registers the system supports. +// +// Currently it's set to zero because using the actual +// constant will break every part of the toolchain that +// uses finalizers or Windows callbacks to call functions +// The value that is currently commented out there should be +// the actual value once we're ready to use the register ABI +// everywhere. +// +// Protected by finlock. +var intArgRegs = 0 // abi.IntArgRegs -- GitLab From 0a655598e150ee8ddd96573744c4b60735658f32 Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Wed, 10 Mar 2021 14:32:27 -0600 Subject: [PATCH 0293/1298] cmd/link: fix glink resolver generation on ppc64le AddSymRef grows the section to fit the relocation. This was not being accounted for. Instead, add a relocation and explicitly populate it so we patch the desired instructions. Change-Id: I583147e2545aea34c854f9d35ca920c57be60b90 Reviewed-on: https://go-review.googlesource.com/c/go/+/300949 Run-TryBot: Paul Murphy Run-TryBot: Lynn Boger Reviewed-by: Cherry Zhang TryBot-Result: Go Bot Trust: Lynn Boger --- src/cmd/link/internal/ppc64/asm.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 602f0b5299..83df8a7a13 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -1039,8 +1039,11 @@ func ensureglinkresolver(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilde glink.AddUint32(ctxt.Arch, 0x7800f082) // srdi r0,r0,2 // r11 = address of the first byte of the PLT - glink.AddSymRef(ctxt.Arch, ctxt.PLT, 0, objabi.R_ADDRPOWER, 8) - + r, _ := glink.AddRel(objabi.R_ADDRPOWER) + r.SetSym(ctxt.PLT) + r.SetSiz(8) + r.SetOff(int32(glink.Size())) + r.SetAdd(0) glink.AddUint32(ctxt.Arch, 0x3d600000) // addis r11,0,.plt@ha glink.AddUint32(ctxt.Arch, 0x396b0000) // addi r11,r11,.plt@l -- GitLab From bbf79793bdeda04d520377406024d7bb66aa62dc Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 25 Feb 2021 09:32:38 -0800 Subject: [PATCH 0294/1298] io/fs: clarify additional File interface docs Emphasize ReadDirFile. It isn't really optional, and all filesystems have at least one directory ("."). The remaining two additional interfaces are optimizations. Call them that. Fully qualify package package io identifiers. Change-Id: Ibc425a5dfd27e08c2c10c353f780e4a6304cfd87 Reviewed-on: https://go-review.googlesource.com/c/go/+/296390 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/io/fs/fs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go index 3d2e2ee2ac..e1be32478e 100644 --- a/src/io/fs/fs.go +++ b/src/io/fs/fs.go @@ -73,8 +73,8 @@ func ValidPath(name string) bool { // A File provides access to a single file. // The File interface is the minimum implementation required of the file. -// A file may implement additional interfaces, such as -// ReadDirFile, ReaderAt, or Seeker, to provide additional or optimized functionality. +// Directory files should also implement ReadDirFile. +// A file may implement io.ReaderAt or io.Seeker as optimizations. type File interface { Stat() (FileInfo, error) Read([]byte) (int, error) -- GitLab From 1853411d8376570295711f9084d494d458822578 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 25 Feb 2021 09:44:35 -0800 Subject: [PATCH 0295/1298] testing/fstest: test that ReadDirFile on a non-dir fails ReadDirFile implementations should return an error for non-directories. Change-Id: I99888562cb6cf829017904ae8c1e8887a416c4cd Reviewed-on: https://go-review.googlesource.com/c/go/+/296391 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/testing/fstest/testfs.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 736bbf0590..89c5fa19af 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -119,6 +119,9 @@ func (t *fsTester) openDir(dir string) fs.ReadDirFile { t.errorf("%s: Open: %v", dir, err) return nil } + // It'd be nice to test here that f.Read fails, because f is a directory. + // However, FreeBSD supports calling read on a directory. + // See https://groups.google.com/g/golang-dev/c/rh8jwxyG1PQ. d, ok := f.(fs.ReadDirFile) if !ok { f.Close() @@ -514,6 +517,12 @@ func (t *fsTester) checkFile(file string) { return } + if dir, ok := f.(fs.ReadDirFile); ok { + if _, err := dir.ReadDir(-1); err == nil { + t.errorf("%s: ReadDir of non-dir file should return an error", file) + } + } + data, err := ioutil.ReadAll(f) if err != nil { f.Close() -- GitLab From 86d66784297f83f67088cea768611621048160da Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 25 Feb 2021 11:10:57 -0800 Subject: [PATCH 0296/1298] testing/fstest: clarify TestFS docs The sentence starts "fsys must only contain", which leads the reader to believe that fsys must not contain others. The rapid reversal leads to confusion. I had to read it several times to be sure I'd parsed it correctly. Remove "only"; rely on the rest of the sentence to clarify. Change-Id: I9fb7935aed4f9839344d3a00b761d20981fba864 Reviewed-on: https://go-review.googlesource.com/c/go/+/296529 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/testing/fstest/testfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 89c5fa19af..27c603167f 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -23,7 +23,7 @@ import ( // opening and checking that each file behaves correctly. // It also checks that the file system contains at least the expected files. // As a special case, if no expected files are listed, fsys must be empty. -// Otherwise, fsys must only contain at least the listed files: it can also contain others. +// Otherwise, fsys must contain at least the listed files; it can also contain others. // The contents of fsys must not change concurrently with TestFS. // // If TestFS finds any misbehaviors, it returns an error reporting all of them. -- GitLab From ae9cd1299cd927dca511344eec1ca16cf91ca758 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 16 Dec 2020 20:22:58 -0800 Subject: [PATCH 0297/1298] hash/maphash: manually inline setSeed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides a minor performance win. name old time/op new time/op delta Hash8Bytes-8 16.5ns ± 2% 16.5ns ± 4% ~ (p=0.407 n=27+29) Hash320Bytes-8 58.5ns ± 2% 55.0ns ± 2% -6.01% (p=0.000 n=29+28) Hash1K-8 195ns ± 1% 190ns ± 2% -2.23% (p=0.000 n=30+30) Hash8K-8 1.59µs ± 2% 1.57µs ± 2% -0.88% (p=0.002 n=30+30) name old speed new speed delta Hash8Bytes-8 484MB/s ± 2% 485MB/s ± 4% ~ (p=0.417 n=27+29) Hash320Bytes-8 5.47GB/s ± 2% 5.82GB/s ± 2% +6.39% (p=0.000 n=29+28) Hash1K-8 5.26GB/s ± 1% 5.39GB/s ± 2% +2.29% (p=0.000 n=30+30) Hash8K-8 5.16GB/s ± 2% 5.21GB/s ± 2% +0.89% (p=0.002 n=30+30) Updates #42710 Change-Id: Ia0d7264b648f96099202de21c6b69a9c1776f6c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/278759 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/hash/maphash/maphash.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hash/maphash/maphash.go b/src/hash/maphash/maphash.go index f7ef1b41e8..c45964f89e 100644 --- a/src/hash/maphash/maphash.go +++ b/src/hash/maphash/maphash.go @@ -68,7 +68,9 @@ type Hash struct { // which does call h.initSeed.) func (h *Hash) initSeed() { if h.seed.s == 0 { - h.setSeed(MakeSeed()) + seed := MakeSeed() + h.seed = seed + h.state = seed } } @@ -123,17 +125,12 @@ func (h *Hash) Seed() Seed { // Two Hash objects with different seeds will very likely behave differently. // Any bytes added to h before this call will be discarded. func (h *Hash) SetSeed(seed Seed) { - h.setSeed(seed) - h.n = 0 -} - -// setSeed sets seed without discarding accumulated data. -func (h *Hash) setSeed(seed Seed) { if seed.s == 0 { panic("maphash: use of uninitialized Seed") } h.seed = seed h.state = seed + h.n = 0 } // Reset discards all bytes added to h. -- GitLab From 64d323f45a5d6a36cdcb190bed56424a633af3ad Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 16 Dec 2020 19:38:39 -0800 Subject: [PATCH 0298/1298] hash/maphash: optimize Write and WriteString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing code makes copies of every byte it hashes. When passed a large chunk of memory, Write and WriteString can skip the copying and initSeed for most of it. To ensure that Write, WriteByte, and WriteString continue to generate output that depends only on the sequence of bytes, expand the grouping test to include WriteString and interleaved calls. Also, make the test process a lot more data, to ensure that Write* handled full buffers correctly. name old time/op new time/op delta Hash8Bytes-8 17.1ns ± 3% 16.5ns ± 2% -3.26% (p=0.000 n=29+27) Hash320Bytes-8 74.9ns ± 2% 58.5ns ± 2% -21.86% (p=0.000 n=30+29) Hash1K-8 246ns ± 3% 195ns ± 1% -20.82% (p=0.000 n=29+30) Hash8K-8 1.87µs ± 2% 1.59µs ± 2% -15.04% (p=0.000 n=26+30) name old speed new speed delta Hash8Bytes-8 468MB/s ± 3% 484MB/s ± 2% +3.36% (p=0.000 n=29+27) Hash320Bytes-8 4.28GB/s ± 2% 5.47GB/s ± 2% +27.97% (p=0.000 n=30+29) Hash1K-8 4.17GB/s ± 3% 5.26GB/s ± 1% +26.28% (p=0.000 n=29+30) Hash8K-8 4.38GB/s ± 2% 5.16GB/s ± 2% +17.70% (p=0.000 n=26+30) Updates #42710 Change-Id: If3cdec1580ffb3e36fab9865e5a9d089c0a34bec Reviewed-on: https://go-review.googlesource.com/c/go/+/278758 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/hash/maphash/maphash.go | 78 ++++++++++++++++++++++++-------- src/hash/maphash/maphash_test.go | 57 +++++++++++++++++++---- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/hash/maphash/maphash.go b/src/hash/maphash/maphash.go index c45964f89e..5cc0c581c7 100644 --- a/src/hash/maphash/maphash.go +++ b/src/hash/maphash/maphash.go @@ -13,7 +13,10 @@ // package maphash -import "unsafe" +import ( + "internal/unsafeheader" + "unsafe" +) // A Seed is a random value that selects the specific hash function // computed by a Hash. If two Hashes use the same Seeds, they @@ -54,13 +57,19 @@ type Seed struct { // If multiple goroutines must compute the same seeded hash, // each can declare its own Hash and call SetSeed with a common Seed. type Hash struct { - _ [0]func() // not comparable - seed Seed // initial seed used for this hash - state Seed // current hash of all flushed bytes - buf [64]byte // unflushed byte buffer - n int // number of unflushed bytes + _ [0]func() // not comparable + seed Seed // initial seed used for this hash + state Seed // current hash of all flushed bytes + buf [bufSize]byte // unflushed byte buffer + n int // number of unflushed bytes } +// bufSize is the size of the Hash write buffer. +// The buffer ensures that writes depend only on the sequence of bytes, +// not the sequence of WriteByte/Write/WriteString calls, +// by always calling rthash with a full buffer (except for the tail). +const bufSize = 64 + // initSeed seeds the hash if necessary. // initSeed is called lazily before any operation that actually uses h.seed/h.state. // Note that this does not include Write/WriteByte/WriteString in the case @@ -89,27 +98,58 @@ func (h *Hash) WriteByte(b byte) error { // It always writes all of b and never fails; the count and error result are for implementing io.Writer. func (h *Hash) Write(b []byte) (int, error) { size := len(b) - for h.n+len(b) > len(h.buf) { + // Deal with bytes left over in h.buf. + // h.n <= bufSize is always true. + // Checking it is ~free and it lets the compiler eliminate a bounds check. + if h.n > 0 && h.n <= bufSize { k := copy(h.buf[h.n:], b) - h.n = len(h.buf) + h.n += k + if h.n < bufSize { + // Copied the entirety of b to h.buf. + return size, nil + } b = b[k:] h.flush() + // No need to set h.n = 0 here; it happens just before exit. + } + // Process as many full buffers as possible, without copying, and calling initSeed only once. + if len(b) > bufSize { + h.initSeed() + for len(b) > bufSize { + h.state.s = rthash(&b[0], bufSize, h.state.s) + b = b[bufSize:] + } } - h.n += copy(h.buf[h.n:], b) + // Copy the tail. + copy(h.buf[:], b) + h.n = len(b) return size, nil } // WriteString adds the bytes of s to the sequence of bytes hashed by h. // It always writes all of s and never fails; the count and error result are for implementing io.StringWriter. func (h *Hash) WriteString(s string) (int, error) { + // WriteString mirrors Write. See Write for comments. size := len(s) - for h.n+len(s) > len(h.buf) { + if h.n > 0 && h.n <= bufSize { k := copy(h.buf[h.n:], s) - h.n = len(h.buf) + h.n += k + if h.n < bufSize { + return size, nil + } s = s[k:] h.flush() } - h.n += copy(h.buf[h.n:], s) + if len(s) > bufSize { + h.initSeed() + for len(s) > bufSize { + ptr := (*byte)((*unsafeheader.String)(unsafe.Pointer(&s)).Data) + h.state.s = rthash(ptr, bufSize, h.state.s) + s = s[bufSize:] + } + } + copy(h.buf[:], s) + h.n = len(s) return size, nil } @@ -147,7 +187,7 @@ func (h *Hash) flush() { panic("maphash: flush of partially full buffer") } h.initSeed() - h.state.s = rthash(h.buf[:], h.state.s) + h.state.s = rthash(&h.buf[0], h.n, h.state.s) h.n = 0 } @@ -160,7 +200,7 @@ func (h *Hash) flush() { // by using bit masking, shifting, or modular arithmetic. func (h *Hash) Sum64() uint64 { h.initSeed() - return rthash(h.buf[:h.n], h.state.s) + return rthash(&h.buf[0], h.n, h.state.s) } // MakeSeed returns a new random seed. @@ -181,18 +221,18 @@ func MakeSeed() Seed { //go:linkname runtime_fastrand runtime.fastrand func runtime_fastrand() uint32 -func rthash(b []byte, seed uint64) uint64 { - if len(b) == 0 { +func rthash(ptr *byte, len int, seed uint64) uint64 { + if len == 0 { return seed } // The runtime hasher only works on uintptr. For 64-bit // architectures, we use the hasher directly. Otherwise, // we use two parallel hashers on the lower and upper 32 bits. if unsafe.Sizeof(uintptr(0)) == 8 { - return uint64(runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b)))) + return uint64(runtime_memhash(unsafe.Pointer(ptr), uintptr(seed), uintptr(len))) } - lo := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed), uintptr(len(b))) - hi := runtime_memhash(unsafe.Pointer(&b[0]), uintptr(seed>>32), uintptr(len(b))) + lo := runtime_memhash(unsafe.Pointer(ptr), uintptr(seed), uintptr(len)) + hi := runtime_memhash(unsafe.Pointer(ptr), uintptr(seed>>32), uintptr(len)) return uint64(hi)<<32 | uint64(lo) } diff --git a/src/hash/maphash/maphash_test.go b/src/hash/maphash/maphash_test.go index daf6eb4786..78cdfc0e73 100644 --- a/src/hash/maphash/maphash_test.go +++ b/src/hash/maphash/maphash_test.go @@ -5,6 +5,7 @@ package maphash import ( + "bytes" "hash" "testing" ) @@ -34,19 +35,57 @@ func TestSeededHash(t *testing.T) { } func TestHashGrouping(t *testing.T) { - b := []byte("foo") - h1 := new(Hash) - h2 := new(Hash) - h2.SetSeed(h1.Seed()) - h1.Write(b) - for _, x := range b { - err := h2.WriteByte(x) + b := bytes.Repeat([]byte("foo"), 100) + hh := make([]*Hash, 7) + for i := range hh { + hh[i] = new(Hash) + } + for _, h := range hh[1:] { + h.SetSeed(hh[0].Seed()) + } + hh[0].Write(b) + hh[1].WriteString(string(b)) + + writeByte := func(h *Hash, b byte) { + err := h.WriteByte(b) if err != nil { t.Fatalf("WriteByte: %v", err) } } - if h1.Sum64() != h2.Sum64() { - t.Errorf("hash of \"foo\" and \"f\",\"o\",\"o\" not identical") + writeSingleByte := func(h *Hash, b byte) { + _, err := h.Write([]byte{b}) + if err != nil { + t.Fatalf("Write single byte: %v", err) + } + } + writeStringSingleByte := func(h *Hash, b byte) { + _, err := h.WriteString(string([]byte{b})) + if err != nil { + t.Fatalf("WriteString single byte: %v", err) + } + } + + for i, x := range b { + writeByte(hh[2], x) + writeSingleByte(hh[3], x) + if i == 0 { + writeByte(hh[4], x) + } else { + writeSingleByte(hh[4], x) + } + writeStringSingleByte(hh[5], x) + if i == 0 { + writeByte(hh[6], x) + } else { + writeStringSingleByte(hh[6], x) + } + } + + sum := hh[0].Sum64() + for i, h := range hh { + if sum != h.Sum64() { + t.Errorf("hash %d not identical to a single Write", i) + } } } -- GitLab From b0733ba12d1190859a95ee93edac940de8052fed Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 16 Dec 2020 20:28:43 -0800 Subject: [PATCH 0299/1298] hash/maphash: increase the buffer size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps a lot for larger writes. name old time/op new time/op delta Hash8Bytes-8 16.5ns ± 4% 16.8ns ± 2% +1.76% (p=0.000 n=29+30) Hash320Bytes-8 55.0ns ± 2% 41.4ns ± 2% -24.64% (p=0.000 n=28+28) Hash1K-8 190ns ± 2% 130ns ± 3% -31.65% (p=0.000 n=30+30) Hash8K-8 1.57µs ± 2% 1.05µs ± 3% -33.01% (p=0.000 n=30+29) name old speed new speed delta Hash8Bytes-8 485MB/s ± 4% 476MB/s ± 2% -1.73% (p=0.000 n=29+30) Hash320Bytes-8 5.82GB/s ± 2% 7.72GB/s ± 3% +32.55% (p=0.000 n=28+29) Hash1K-8 5.39GB/s ± 2% 7.88GB/s ± 3% +46.32% (p=0.000 n=30+30) Hash8K-8 5.21GB/s ± 2% 7.77GB/s ± 3% +49.28% (p=0.000 n=30+29) Updates #42710 Change-Id: Idaf4b2a8a41fc62fc16b54c9358cf2cc7009cf29 Reviewed-on: https://go-review.googlesource.com/c/go/+/278760 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/hash/maphash/maphash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash/maphash/maphash.go b/src/hash/maphash/maphash.go index 5cc0c581c7..d022d746a7 100644 --- a/src/hash/maphash/maphash.go +++ b/src/hash/maphash/maphash.go @@ -68,7 +68,7 @@ type Hash struct { // The buffer ensures that writes depend only on the sequence of bytes, // not the sequence of WriteByte/Write/WriteString calls, // by always calling rthash with a full buffer (except for the tail). -const bufSize = 64 +const bufSize = 128 // initSeed seeds the hash if necessary. // initSeed is called lazily before any operation that actually uses h.seed/h.state. -- GitLab From 43d5f213e22029039f234edd1ac72c4ff9dd5ae9 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 7 Jan 2021 19:25:05 -0800 Subject: [PATCH 0300/1298] cmd/compile: optimize multi-register shifts on amd64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amd64 can shift in bits from another register instead of filling with 0/1. This pattern is helpful when implementing 128 bit shifts or arbitrary length shifts. In the standard library, it shows up in pure Go math/big. Benchmarks results on amd64 with -tags=math_big_pure_go. name old time/op new time/op delta NonZeroShifts/1/shrVU-8 4.45ns ± 3% 4.39ns ± 1% -1.28% (p=0.000 n=30+27) NonZeroShifts/1/shlVU-8 4.13ns ± 4% 4.10ns ± 2% ~ (p=0.254 n=29+28) NonZeroShifts/2/shrVU-8 5.55ns ± 1% 5.63ns ± 2% +1.42% (p=0.000 n=28+29) NonZeroShifts/2/shlVU-8 5.70ns ± 2% 5.14ns ± 1% -9.82% (p=0.000 n=29+28) NonZeroShifts/3/shrVU-8 6.79ns ± 2% 6.35ns ± 2% -6.46% (p=0.000 n=28+29) NonZeroShifts/3/shlVU-8 6.69ns ± 1% 6.25ns ± 1% -6.60% (p=0.000 n=28+27) NonZeroShifts/4/shrVU-8 7.79ns ± 2% 7.06ns ± 2% -9.48% (p=0.000 n=30+30) NonZeroShifts/4/shlVU-8 7.82ns ± 1% 7.24ns ± 1% -7.37% (p=0.000 n=28+29) NonZeroShifts/5/shrVU-8 8.90ns ± 3% 7.93ns ± 1% -10.84% (p=0.000 n=29+26) NonZeroShifts/5/shlVU-8 8.68ns ± 1% 7.92ns ± 1% -8.76% (p=0.000 n=29+29) NonZeroShifts/10/shrVU-8 14.4ns ± 1% 12.3ns ± 2% -14.79% (p=0.000 n=28+29) NonZeroShifts/10/shlVU-8 14.1ns ± 1% 11.9ns ± 2% -15.55% (p=0.000 n=28+27) NonZeroShifts/100/shrVU-8 118ns ± 1% 96ns ± 3% -18.82% (p=0.000 n=30+29) NonZeroShifts/100/shlVU-8 120ns ± 2% 98ns ± 2% -18.46% (p=0.000 n=29+28) NonZeroShifts/1000/shrVU-8 1.10µs ± 1% 0.88µs ± 2% -19.63% (p=0.000 n=29+30) NonZeroShifts/1000/shlVU-8 1.10µs ± 2% 0.88µs ± 2% -20.28% (p=0.000 n=29+28) NonZeroShifts/10000/shrVU-8 10.9µs ± 1% 8.7µs ± 1% -19.78% (p=0.000 n=28+27) NonZeroShifts/10000/shlVU-8 10.9µs ± 2% 8.7µs ± 1% -19.64% (p=0.000 n=29+27) NonZeroShifts/100000/shrVU-8 111µs ± 2% 90µs ± 2% -19.39% (p=0.000 n=28+29) NonZeroShifts/100000/shlVU-8 113µs ± 2% 90µs ± 2% -20.43% (p=0.000 n=30+27) The assembly version is still faster, unfortunately, but the gap is narrowing. Speedup from pure Go to assembly: name old time/op new time/op delta NonZeroShifts/1/shrVU-8 4.39ns ± 1% 3.45ns ± 2% -21.36% (p=0.000 n=27+29) NonZeroShifts/1/shlVU-8 4.10ns ± 2% 3.47ns ± 3% -15.42% (p=0.000 n=28+30) NonZeroShifts/2/shrVU-8 5.63ns ± 2% 3.97ns ± 0% -29.40% (p=0.000 n=29+25) NonZeroShifts/2/shlVU-8 5.14ns ± 1% 3.77ns ± 2% -26.65% (p=0.000 n=28+26) NonZeroShifts/3/shrVU-8 6.35ns ± 2% 4.79ns ± 2% -24.52% (p=0.000 n=29+29) NonZeroShifts/3/shlVU-8 6.25ns ± 1% 4.42ns ± 1% -29.29% (p=0.000 n=27+26) NonZeroShifts/4/shrVU-8 7.06ns ± 2% 5.64ns ± 1% -20.05% (p=0.000 n=30+29) NonZeroShifts/4/shlVU-8 7.24ns ± 1% 5.34ns ± 2% -26.23% (p=0.000 n=29+29) NonZeroShifts/5/shrVU-8 7.93ns ± 1% 6.56ns ± 2% -17.26% (p=0.000 n=26+30) NonZeroShifts/5/shlVU-8 7.92ns ± 1% 6.27ns ± 1% -20.79% (p=0.000 n=29+25) NonZeroShifts/10/shrVU-8 12.3ns ± 2% 10.2ns ± 2% -17.21% (p=0.000 n=29+29) NonZeroShifts/10/shlVU-8 11.9ns ± 2% 10.5ns ± 2% -12.45% (p=0.000 n=27+29) NonZeroShifts/100/shrVU-8 95.9ns ± 3% 77.7ns ± 1% -19.00% (p=0.000 n=29+30) NonZeroShifts/100/shlVU-8 97.5ns ± 2% 66.8ns ± 2% -31.47% (p=0.000 n=28+30) NonZeroShifts/1000/shrVU-8 884ns ± 2% 705ns ± 1% -20.17% (p=0.000 n=30+28) NonZeroShifts/1000/shlVU-8 880ns ± 2% 590ns ± 1% -32.96% (p=0.000 n=28+25) NonZeroShifts/10000/shrVU-8 8.74µs ± 1% 7.34µs ± 3% -15.94% (p=0.000 n=27+30) NonZeroShifts/10000/shlVU-8 8.73µs ± 1% 6.00µs ± 1% -31.25% (p=0.000 n=27+28) NonZeroShifts/100000/shrVU-8 89.6µs ± 2% 75.5µs ± 2% -15.80% (p=0.000 n=29+29) NonZeroShifts/100000/shlVU-8 89.6µs ± 2% 68.0µs ± 3% -24.09% (p=0.000 n=27+30) Change-Id: I18f58d8f5513d737d9cdf09b8f9d14011ffe3958 Reviewed-on: https://go-review.googlesource.com/c/go/+/297050 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/amd64/ssa.go | 9 ++++ src/cmd/compile/internal/ssa/gen/AMD64.rules | 3 ++ src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 4 ++ src/cmd/compile/internal/ssa/opGen.go | 36 +++++++++++++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 48 ++++++++++++++++++++ test/codegen/shift.go | 13 ++++++ 6 files changed, 113 insertions(+) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index af398c814a..3798c37b34 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -253,6 +253,15 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64BTRL, ssa.OpAMD64BTRQ: opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg()) + case ssa.OpAMD64SHRDQ, ssa.OpAMD64SHLDQ: + p := s.Prog(v.Op.Asm()) + lo, hi, bits := v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg() + p.From.Type = obj.TYPE_REG + p.From.Reg = bits + p.To.Type = obj.TYPE_REG + p.To.Reg = lo + p.SetFrom3Reg(hi) + case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU: // Arg[0] (the dividend) is in AX. // Arg[1] (the divisor) can be in any other register. diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index c61b460a56..bece886c0d 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -902,6 +902,9 @@ ((SHRB|SARB)const x [0]) => x ((ROLQ|ROLL|ROLW|ROLB)const x [0]) => x +// Multi-register shifts +(ORQ (SH(R|L)Q lo bits) (SH(L|R)Q hi (NEGQ bits))) => (SH(R|L)DQ lo hi bits) + // Note: the word and byte shifts keep the low 5 bits (not the low 4 or 3 bits) // because the x86 instructions are defined to use all 5 bits of the shift even // for the small shifts. I don't think we'll ever generate a weird shift (e.g. diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 5f5ebaaa35..6bf5be9e47 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -122,6 +122,7 @@ func init() { gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly} gp21sb = regInfo{inputs: []regMask{gpspsbg, gpsp}, outputs: gponly} gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}} + gp31shift = regInfo{inputs: []regMask{gp, gp, cx}, outputs: []regMask{gp}} gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax, dx}} gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax} gp21flags = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}} @@ -408,6 +409,9 @@ func init() { {name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> auxint, shift amount 0-15 {name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> auxint, shift amount 0-7 + {name: "SHRDQ", argLength: 3, reg: gp31shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg2, shifting in bits from arg1 (==(arg1<<64+arg0)>>arg2, keeping low 64 bits), shift amount is mod 64 + {name: "SHLDQ", argLength: 3, reg: gp31shift, asm: "SHLQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 << arg2, shifting in bits from arg1 (==(arg0<<64+arg1)<>25] } + +// 128 bit shifts + +func check128bitShifts(x, y uint64, bits uint) (uint64, uint64) { + s := bits & 63 + ŝ := (64 - bits) & 63 + // check that the shift operation has two commas (three operands) + // amd64:"SHRQ.*,.*," + shr := x>>s | y<<ŝ + // amd64:"SHLQ.*,.*," + shl := x<>ŝ + return shr, shl +} -- GitLab From 4dd9c7cadcbe689ef607931ed839456509e59104 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Fri, 11 Dec 2020 17:03:17 -0500 Subject: [PATCH 0301/1298] cmd/go: remove some fsyncs when writing files cache.Trim, dowloadZip, rewriteVersionList, writeDiskCache all use renameio.WriteFile to write their respective files to disk. For the uses in cache.Trim and downloadZip, instead do of renameio.WriteFile, do a truncate to the length of the file, then write the relevant bytes so that a corrupt file (which would contain null bytes because of the truncate) could be detected. For rewriteVersionList, use lockedfile.Transform to do the write (which does a truncate as part of the write too. writeDiskCache stays the same in this CL. Also desete renameio methods that aren't used and remove the renameio.WriteFile wrapper and just use renameio.WriteToFile which it wraps. There is a possibility of corrupt files in the cache (which was true even before this CL) so later CLs will add facilities to clear corrupt files in the cache. Change-Id: I0d0bda40095e4cb898314315bf313e71650d8d25 Reviewed-on: https://go-review.googlesource.com/c/go/+/277412 Trust: Michael Matloob Run-TryBot: Michael Matloob TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/cache/cache.go | 23 +++++-- src/cmd/go/internal/modfetch/cache.go | 64 ++++++++++++------ src/cmd/go/internal/modfetch/fetch.go | 66 +++++++++++++++---- src/cmd/go/internal/renameio/renameio.go | 8 +-- src/cmd/go/internal/renameio/renameio_test.go | 2 +- 5 files changed, 118 insertions(+), 45 deletions(-) diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index 41f921641d..d592d70497 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -19,7 +19,7 @@ import ( "strings" "time" - "cmd/go/internal/renameio" + "cmd/go/internal/lockedfile" ) // An ActionID is a cache action key, the hash of a complete description of a @@ -294,10 +294,17 @@ func (c *Cache) Trim() { // We maintain in dir/trim.txt the time of the last completed cache trim. // If the cache has been trimmed recently enough, do nothing. // This is the common case. - data, _ := renameio.ReadFile(filepath.Join(c.dir, "trim.txt")) - t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64) - if err == nil && now.Sub(time.Unix(t, 0)) < trimInterval { - return + // If the trim file is corrupt, detected if the file can't be parsed, or the + // trim time is too far in the future, attempt the trim anyway. It's possible that + // the cache was full when the corruption happened. Attempting a trim on + // an empty cache is cheap, so there wouldn't be a big performance hit in that case. + if data, err := lockedfile.Read(filepath.Join(c.dir, "trim.txt")); err == nil { + if t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64); err == nil { + lastTrim := time.Unix(t, 0) + if d := now.Sub(lastTrim); d < trimInterval && d > -mtimeInterval { + return + } + } } // Trim each of the 256 subdirectories. @@ -311,7 +318,11 @@ func (c *Cache) Trim() { // Ignore errors from here: if we don't write the complete timestamp, the // cache will appear older than it is, and we'll trim it again next time. - renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666) + var b bytes.Buffer + fmt.Fprintf(&b, "%d", now.Unix()) + if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0666); err != nil { + return + } } // trimSubdir trims a single cache subdirectory. diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 10f774568d..50a2898f24 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -104,7 +104,9 @@ func DownloadDir(m module.Version) (string, error) { // Check if a .ziphash file exists. It should be created before the // zip is extracted, but if it was deleted (by another program?), we need - // to re-calculate it. + // to re-calculate it. Note that checkMod will repopulate the ziphash + // file if it doesn't exist, but if the module is excluded by checks + // through GONOSUMDB or GOPRIVATE, that check and repopulation won't happen. ziphashPath, err := CachePath(m, "ziphash") if err != nil { return dir, err @@ -326,7 +328,7 @@ func InfoFile(path, version string) (string, error) { } // Stat should have populated the disk cache for us. - file, _, err := readDiskStat(path, version) + file, err := CachePath(module.Version{Path: path, Version: version}, "info") if err != nil { return "", err } @@ -378,7 +380,7 @@ func GoModFile(path, version string) (string, error) { return "", err } // GoMod should have populated the disk cache for us. - file, _, err := readDiskGoMod(path, version) + file, err := CachePath(module.Version{Path: path, Version: version}, "mod") if err != nil { return "", err } @@ -590,27 +592,34 @@ func writeDiskCache(file string, data []byte) error { // rewriteVersionList rewrites the version list in dir // after a new *.mod file has been written. -func rewriteVersionList(dir string) { +func rewriteVersionList(dir string) (err error) { if filepath.Base(dir) != "@v" { base.Fatalf("go: internal error: misuse of rewriteVersionList") } listFile := filepath.Join(dir, "list") - // We use a separate lockfile here instead of locking listFile itself because - // we want to use Rename to write the file atomically. The list may be read by - // a GOPROXY HTTP server, and if we crash midway through a rewrite (or if the - // HTTP server ignores our locking and serves the file midway through a - // rewrite) it's better to serve a stale list than a truncated one. - unlock, err := lockedfile.MutexAt(listFile + ".lock").Lock() + // Lock listfile when writing to it to try to avoid corruption to the file. + // Under rare circumstances, for instance, if the system loses power in the + // middle of a write it is possible for corrupt data to be written. This is + // not a problem for the go command itself, but may be an issue if the the + // cache is being served by a GOPROXY HTTP server. This will be corrected + // the next time a new version of the module is fetched and the file is rewritten. + // TODO(matloob): golang.org/issue/43313 covers adding a go mod verify + // command that removes module versions that fail checksums. It should also + // remove list files that are detected to be corrupt. + f, err := lockedfile.Edit(listFile) if err != nil { - base.Fatalf("go: can't lock version list lockfile: %v", err) + return err } - defer unlock() - + defer func() { + if cerr := f.Close(); cerr != nil && err == nil { + err = cerr + } + }() infos, err := os.ReadDir(dir) if err != nil { - return + return err } var list []string for _, info := range infos { @@ -635,14 +644,29 @@ func rewriteVersionList(dir string) { buf.WriteString(v) buf.WriteString("\n") } - old, _ := renameio.ReadFile(listFile) - if bytes.Equal(buf.Bytes(), old) { - return + if fi, err := f.Stat(); err == nil && int(fi.Size()) == buf.Len() { + old := make([]byte, buf.Len()+1) + if n, err := f.ReadAt(old, 0); err == io.EOF && n == buf.Len() && bytes.Equal(buf.Bytes(), old) { + return nil // No edit needed. + } } - - if err := renameio.WriteFile(listFile, buf.Bytes(), 0666); err != nil { - base.Fatalf("go: failed to write version list: %v", err) + // Remove existing contents, so that when we truncate to the actual size it will zero-fill, + // and we will be able to detect (some) incomplete writes as files containing trailing NUL bytes. + if err := f.Truncate(0); err != nil { + return err } + // Reserve the final size and zero-fill. + if err := f.Truncate(int64(buf.Len())); err != nil { + return err + } + // Write the actual contents. If this fails partway through, + // the remainder of the file should remain as zeroes. + if _, err := f.Write(buf.Bytes()); err != nil { + f.Truncate(0) + return err + } + + return nil } func checkCacheDir() error { diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 7b4ce2154c..4ee490c5ea 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -8,6 +8,8 @@ import ( "archive/zip" "bytes" "context" + "crypto/sha256" + "encoding/base64" "errors" "fmt" "io" @@ -296,12 +298,6 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e } } - // Sync the file before renaming it: otherwise, after a crash the reader may - // observe a 0-length file instead of the actual contents. - // See https://golang.org/issue/22397#issuecomment-380831736. - if err := f.Sync(); err != nil { - return err - } if err := f.Close(); err != nil { return err } @@ -332,7 +328,21 @@ func hashZip(mod module.Version, zipfile, ziphashfile string) error { if err := checkModSum(mod, hash); err != nil { return err } - return renameio.WriteFile(ziphashfile, []byte(hash), 0666) + hf, err := lockedfile.Create(ziphashfile) + if err != nil { + return err + } + if err := hf.Truncate(int64(len(hash))); err != nil { + return err + } + if _, err := hf.WriteAt([]byte(hash), 0); err != nil { + return err + } + if err := hf.Close(); err != nil { + return err + } + + return nil } // makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir @@ -483,11 +493,24 @@ func checkMod(mod module.Version) { if err != nil { base.Fatalf("verifying %v", module.VersionError(mod, err)) } - data, err := renameio.ReadFile(ziphash) + data, err := lockedfile.Read(ziphash) if err != nil { base.Fatalf("verifying %v", module.VersionError(mod, err)) } - h := strings.TrimSpace(string(data)) + data = bytes.TrimSpace(data) + if !isValidSum(data) { + // Recreate ziphash file from zip file and use that to check the mod sum. + zip, err := CachePath(mod, "zip") + if err != nil { + base.Fatalf("verifying %v", module.VersionError(mod, err)) + } + err = hashZip(mod, zip, ziphash) + if err != nil { + base.Fatalf("verifying %v", module.VersionError(mod, err)) + } + return + } + h := string(data) if !strings.HasPrefix(h, "h1:") { base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h))) } @@ -632,11 +655,32 @@ func Sum(mod module.Version) string { if err != nil { return "" } - data, err := renameio.ReadFile(ziphash) + data, err := lockedfile.Read(ziphash) if err != nil { return "" } - return strings.TrimSpace(string(data)) + data = bytes.TrimSpace(data) + if !isValidSum(data) { + return "" + } + return string(data) +} + +// isValidSum returns true if data is the valid contents of a zip hash file. +// Certain critical files are written to disk by first truncating +// then writing the actual bytes, so that if the write fails +// the corrupt file should contain at least one of the null +// bytes written by the truncate operation. +func isValidSum(data []byte) bool { + if bytes.IndexByte(data, '\000') >= 0 { + return false + } + + if len(data) != len("h1:")+base64.StdEncoding.EncodedLen(sha256.Size) { + return false + } + + return true } // WriteGoSum writes the go.sum file if it needs to be updated. diff --git a/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go index 9788171d6e..811f4573a0 100644 --- a/src/cmd/go/internal/renameio/renameio.go +++ b/src/cmd/go/internal/renameio/renameio.go @@ -31,12 +31,6 @@ func Pattern(filename string) string { // // That ensures that the final location, if it exists, is always a complete file. func WriteFile(filename string, data []byte, perm fs.FileMode) (err error) { - return WriteToFile(filename, bytes.NewReader(data), perm) -} - -// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader -// instead of a slice. -func WriteToFile(filename string, data io.Reader, perm fs.FileMode) (err error) { f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm) if err != nil { return err @@ -51,7 +45,7 @@ func WriteToFile(filename string, data io.Reader, perm fs.FileMode) (err error) } }() - if _, err := io.Copy(f, data); err != nil { + if _, err := io.Copy(f, bytes.NewReader(data)); err != nil { return err } // Sync the file before renaming it: otherwise, after a crash the reader may diff --git a/src/cmd/go/internal/renameio/renameio_test.go b/src/cmd/go/internal/renameio/renameio_test.go index dc3c1415db..1c8d7e311d 100644 --- a/src/cmd/go/internal/renameio/renameio_test.go +++ b/src/cmd/go/internal/renameio/renameio_test.go @@ -82,7 +82,7 @@ func TestConcurrentReadsAndWrites(t *testing.T) { } time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond) - data, err := ReadFile(path) + data, err := robustio.ReadFile(path) if err == nil { atomic.AddInt64(&readSuccesses, 1) } else if robustio.IsEphemeralError(err) { -- GitLab From b3896fc331c36a539f825f1f656cef3f9cdffd3f Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 11 Mar 2021 15:04:16 -0500 Subject: [PATCH 0302/1298] net/http: revert change to generated file from CL 296152 This file is generated, so the fix needs to happen upstream. The file can then be regenerated using 'go generate net/http'. Updates #44143 Change-Id: I13a1e7677470ba84a06976e5bbe24f4ce1e7cfb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/301069 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills Reviewed-by: David Chase TryBot-Result: Go Bot --- src/net/http/socks_bundle.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go index fc22391039..e446669589 100644 --- a/src/net/http/socks_bundle.go +++ b/src/net/http/socks_bundle.go @@ -362,8 +362,6 @@ func (d *socksDialer) DialWithConn(ctx context.Context, c net.Conn, network, add // Unlike DialContext, it returns a raw transport connection instead // of a forward proxy connection. // -// Dial uses context.Background internally. -// // Deprecated: Use DialContext or DialWithConn instead. func (d *socksDialer) Dial(network, address string) (net.Conn, error) { if err := d.validateTarget(network, address); err != nil { -- GitLab From 7fc638d6f1679f2e35862555531bf479c3e5b99c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 23 Dec 2020 19:49:39 -0800 Subject: [PATCH 0303/1298] cmd: move GOEXPERIMENT knob from make.bash to cmd/go This CL changes GOEXPERIMENT to act like other GO[CONFIG] environment variables. Namely, that it can be set at make.bash time to provide a default value used by the toolchain, but then can be manually set when running either cmd/go or the individual tools (compiler, assembler, linker). For example, it's now possible to test rsc.io/tmp/fieldtrack by simply running: GOEXPERIMENT=fieldtrack go test -gcflags=-l rsc.io/tmp/fieldtrack \ -ldflags=-k=rsc.io/tmp/fieldtrack.tracked without needing to re-run make.bash. (-gcflags=-l is needed because the compiler's inlining abilities have improved, so calling a function with a for loop is no longer sufficient to suppress inlining.) Fixes #42681. Change-Id: I2cf8995d5d0d05f6785a2ee1d3b54b2cfb3331ca Reviewed-on: https://go-review.googlesource.com/c/go/+/300991 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/cmd/asm/internal/lex/input.go | 10 ++++++++++ src/cmd/dist/build.go | 16 ++++------------ src/cmd/dist/buildruntime.go | 6 ++---- src/cmd/go/internal/cfg/cfg.go | 13 +++++++------ src/cmd/go/internal/work/exec.go | 8 ++++++++ src/cmd/go/internal/work/gc.go | 12 ------------ src/cmd/internal/objabi/util.go | 25 +++++++++++++------------ src/cmd/link/internal/ld/main.go | 2 ++ src/internal/cfg/cfg.go | 1 + src/runtime/heapdump.go | 2 +- src/runtime/internal/sys/arch.go | 2 ++ src/runtime/proc.go | 2 +- 12 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go index da4ebe6d6e..1d4d4be7bd 100644 --- a/src/cmd/asm/internal/lex/input.go +++ b/src/cmd/asm/internal/lex/input.go @@ -45,6 +45,16 @@ func NewInput(name string) *Input { // predefine installs the macros set by the -D flag on the command line. func predefine(defines flags.MultiFlag) map[string]*Macro { macros := make(map[string]*Macro) + + if *flags.CompilingRuntime && objabi.Regabi_enabled != 0 { + const name = "GOEXPERIMENT_REGABI" + macros[name] = &Macro{ + name: name, + args: nil, + tokens: Tokenize("1"), + } + } + for _, name := range defines { value := "1" i := strings.IndexRune(name, '=') diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 158cedbadc..b2d13e7db4 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -39,6 +39,7 @@ var ( goextlinkenabled string gogcflags string // For running built compiler goldflags string + goexperiment string workdir string tooldir string oldgoos string @@ -194,6 +195,9 @@ func xinit() { goextlinkenabled = b } + goexperiment = os.Getenv("GOEXPERIMENT") + // TODO(mdempsky): Validate known experiments? + gogcflags = os.Getenv("BOOT_GO_GCFLAGS") goldflags = os.Getenv("BOOT_GO_LDFLAGS") @@ -834,18 +838,6 @@ func runInstall(pkg string, ch chan struct{}) { goasmh := pathf("%s/go_asm.h", workdir) if IsRuntimePackagePath(pkg) { asmArgs = append(asmArgs, "-compiling-runtime") - if os.Getenv("GOEXPERIMENT") == "regabi" { - // In order to make it easier to port runtime assembly - // to the register ABI, we introduce a macro - // indicating the experiment is enabled. - // - // Note: a similar change also appears in - // cmd/go/internal/work/gc.go. - // - // TODO(austin): Remove this once we commit to the - // register ABI (#40724). - asmArgs = append(asmArgs, "-D=GOEXPERIMENT_REGABI=1") - } } // Collect symabis from assembly code. diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go index 2744951597..e0a101a353 100644 --- a/src/cmd/dist/buildruntime.go +++ b/src/cmd/dist/buildruntime.go @@ -20,7 +20,6 @@ import ( // package sys // // const TheVersion = -// const Goexperiment = // const StackGuardMultiplier = // func mkzversion(dir, file string) { @@ -30,7 +29,6 @@ func mkzversion(dir, file string) { fmt.Fprintf(&buf, "package sys\n") fmt.Fprintln(&buf) fmt.Fprintf(&buf, "const TheVersion = `%s`\n", findgoversion()) - fmt.Fprintf(&buf, "const Goexperiment = `%s`\n", os.Getenv("GOEXPERIMENT")) fmt.Fprintf(&buf, "const StackGuardMultiplierDefault = %d\n", stackGuardMultiplierDefault()) writefile(buf.String(), file, writeSkipSame) @@ -48,10 +46,10 @@ func mkzversion(dir, file string) { // const defaultGOPPC64 = // const defaultGOOS = runtime.GOOS // const defaultGOARCH = runtime.GOARCH +// const defaultGOEXPERIMENT = // const defaultGO_EXTLINK_ENABLED = // const version = // const stackGuardMultiplierDefault = -// const goexperiment = // // The use of runtime.GOOS and runtime.GOARCH makes sure that // a cross-compiled compiler expects to compile for its own target @@ -77,11 +75,11 @@ func mkzbootstrap(file string) { fmt.Fprintf(&buf, "const defaultGOPPC64 = `%s`\n", goppc64) fmt.Fprintf(&buf, "const defaultGOOS = runtime.GOOS\n") fmt.Fprintf(&buf, "const defaultGOARCH = runtime.GOARCH\n") + fmt.Fprintf(&buf, "const defaultGOEXPERIMENT = `%s`\n", goexperiment) fmt.Fprintf(&buf, "const defaultGO_EXTLINK_ENABLED = `%s`\n", goextlinkenabled) fmt.Fprintf(&buf, "const defaultGO_LDSO = `%s`\n", defaultldso) fmt.Fprintf(&buf, "const version = `%s`\n", findgoversion()) fmt.Fprintf(&buf, "const stackGuardMultiplierDefault = %d\n", stackGuardMultiplierDefault()) - fmt.Fprintf(&buf, "const goexperiment = `%s`\n", os.Getenv("GOEXPERIMENT")) writefile(buf.String(), file, writeSkipSame) } diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index 810189c15d..a91b6a57b9 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -252,12 +252,13 @@ var ( GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod")) // Used in envcmd.MkEnv and build ID computations. - GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM)) - GO386 = envOr("GO386", objabi.GO386) - GOMIPS = envOr("GOMIPS", objabi.GOMIPS) - GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64) - GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64)) - GOWASM = envOr("GOWASM", fmt.Sprint(objabi.GOWASM)) + GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM)) + GO386 = envOr("GO386", objabi.GO386) + GOMIPS = envOr("GOMIPS", objabi.GOMIPS) + GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64) + GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64)) + GOWASM = envOr("GOWASM", fmt.Sprint(objabi.GOWASM)) + GOEXPERIMENT = envOr("GOEXPERIMENT", objabi.GOEXPERIMENT) GOPROXY = envOr("GOPROXY", "https://proxy.golang.org,direct") GOSUMDB = envOr("GOSUMDB", "sum.golang.org") diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 3980c5f898..bd5ae46739 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -276,6 +276,10 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) + if exp := cfg.Getenv("GOEXPERIMENT"); exp != "" { + fmt.Fprintf(h, "GOEXPERIMENT=%q\n", exp) + } + // TODO(rsc): Convince compiler team not to add more magic environment variables, // or perhaps restrict the environment variables passed to subprocesses. // Because these are clumsy, undocumented special-case hacks @@ -1246,6 +1250,10 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) + if exp := cfg.Getenv("GOEXPERIMENT"); exp != "" { + fmt.Fprintf(h, "GOEXPERIMENT=%q\n", exp) + } + // The linker writes source file paths that say GOROOT_FINAL, but // only if -trimpath is not specified (see ld() in gc.go). gorootFinal := cfg.GOROOT_FINAL diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 2087855b3c..3cb7c5aff3 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -343,18 +343,6 @@ func asmArgs(a *Action, p *load.Package) []interface{} { } if objabi.IsRuntimePackagePath(pkgpath) { args = append(args, "-compiling-runtime") - if objabi.Regabi_enabled != 0 { - // In order to make it easier to port runtime assembly - // to the register ABI, we introduce a macro - // indicating the experiment is enabled. - // - // Note: a similar change also appears in - // cmd/dist/build.go. - // - // TODO(austin): Remove this once we commit to the - // register ABI (#40724). - args = append(args, "-D=GOEXPERIMENT_REGABI=1") - } } if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" { diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index 1f99f8ed5d..de8e6de4e6 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -21,17 +21,18 @@ func envOr(key, value string) string { var ( defaultGOROOT string // set by linker - GOROOT = envOr("GOROOT", defaultGOROOT) - GOARCH = envOr("GOARCH", defaultGOARCH) - GOOS = envOr("GOOS", defaultGOOS) - GO386 = envOr("GO386", defaultGO386) - GOARM = goarm() - GOMIPS = gomips() - GOMIPS64 = gomips64() - GOPPC64 = goppc64() - GOWASM = gowasm() - GO_LDSO = defaultGO_LDSO - Version = version + GOROOT = envOr("GOROOT", defaultGOROOT) + GOARCH = envOr("GOARCH", defaultGOARCH) + GOOS = envOr("GOOS", defaultGOOS) + GOEXPERIMENT = envOr("GOEXPERIMENT", defaultGOEXPERIMENT) + GO386 = envOr("GO386", defaultGO386) + GOARM = goarm() + GOMIPS = gomips() + GOMIPS64 = gomips64() + GOPPC64 = goppc64() + GOWASM = gowasm() + GO_LDSO = defaultGO_LDSO + Version = version ) const ( @@ -124,7 +125,7 @@ func Getgoextlinkenabled() string { } func init() { - for _, f := range strings.Split(goexperiment, ",") { + for _, f := range strings.Split(GOEXPERIMENT, ",") { if f != "" { addexp(f) } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 68dee18598..8e9a9b9207 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -119,6 +119,8 @@ func Main(arch *sys.Arch, theArch Arch) { addstrdata1(ctxt, "runtime.defaultGOROOT="+final) addstrdata1(ctxt, "cmd/internal/objabi.defaultGOROOT="+final) + addstrdata1(ctxt, "runtime/internal/sys.GOEXPERIMENT="+objabi.GOEXPERIMENT) + // TODO(matloob): define these above and then check flag values here if ctxt.Arch.Family == sys.AMD64 && objabi.GOOS == "plan9" { flag.BoolVar(&flag8, "8", false, "use 64-bit addresses in symbol table") diff --git a/src/internal/cfg/cfg.go b/src/internal/cfg/cfg.go index 553021374d..815994b679 100644 --- a/src/internal/cfg/cfg.go +++ b/src/internal/cfg/cfg.go @@ -39,6 +39,7 @@ const KnownEnv = ` GOCACHE GOENV GOEXE + GOEXPERIMENT GOFLAGS GOGCCFLAGS GOHOSTARCH diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 1b8c19b476..e0913162a4 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -532,7 +532,7 @@ func dumpparams() { dumpint(uint64(arenaStart)) dumpint(uint64(arenaEnd)) dumpstr(sys.GOARCH) - dumpstr(sys.Goexperiment) + dumpstr(sys.GOEXPERIMENT) dumpint(uint64(ncpu)) } diff --git a/src/runtime/internal/sys/arch.go b/src/runtime/internal/sys/arch.go index 3c99a2f7da..f00c55913f 100644 --- a/src/runtime/internal/sys/arch.go +++ b/src/runtime/internal/sys/arch.go @@ -52,3 +52,5 @@ const MinFrameSize = _MinFrameSize // StackAlign is the required alignment of the SP register. // The stack must be at least word aligned, but some architectures require more. const StackAlign = _StackAlign + +var GOEXPERIMENT string // set by cmd/link diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 5f372bb063..8db3b767d1 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -6027,7 +6027,7 @@ func setMaxThreads(in int) (out int) { } func haveexperiment(name string) bool { - x := sys.Goexperiment + x := sys.GOEXPERIMENT for x != "" { xname := "" i := bytealg.IndexByteString(x, ',') -- GitLab From 71a6c13164f2151c14ebaeccdfcb3633fc8b618e Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 10 Mar 2021 19:28:28 -0800 Subject: [PATCH 0304/1298] cmd/compile: call types.CheckSize() in g.typ() Restore code to call types.CheckSize() in g.typ(). There are certain cases (involving maps) where we need to do CheckSize here. In general, the old typechecker calls CheckSize() a lot, and we want to eliminate calling it eventually, so should get do types.CheckSize() when we create a new concrete type. However, the test typeparams/cons.go does not work with just calling types.CheckSize() in g.typ() (which is why I disabled the calls originally). The reason is that g.typ() is called recursively within types.go, so it can be called on a partially-created recursive type, which leads to an error in CheckSize(). So, we need to call CheckSize() only on fully-created top-level types. So, I divided typ() into typ() and typ1(), where typ() is now the external entry point, and typ1() is called within types.go. Now, typ() can call CheckSize() safely. I also added in an extra condition - we do not currently need to call CheckSize() on non-fully-instantiated types, since they will not make it to the backend. That could change a bit with dictionaries. Fixes #44895 Change-Id: I783aa7d2999dd882ddbd99a7c19a6ff6ee420102 Reviewed-on: https://go-review.googlesource.com/c/go/+/300989 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/types.go | 54 ++++++++++++++----------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index 96bf75d594..58b7262455 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -30,6 +30,23 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg { // typ converts a types2.Type to a types.Type, including caching of previously // translated types. func (g *irgen) typ(typ types2.Type) *types.Type { + res := g.typ1(typ) + + // Calculate the size for all concrete types seen by the frontend. The old + // typechecker calls CheckSize() a lot, and we want to eliminate calling + // it eventually, so we should do it here instead. We only call it for + // top-level types (i.e. we do it here rather in typ1), to make sure that + // recursive types have been fully constructed before we call CheckSize. + if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() { + types.CheckSize(res) + } + return res +} + +// typ1 is like typ, but doesn't call CheckSize, since it may have only +// constructed part of a recursive type. Should not be called from outside this +// file (g.typ is the "external" entry point). +func (g *irgen) typ1(typ types2.Type) *types.Type { // Cache type2-to-type mappings. Important so that each defined generic // type (instantiated or not) has a single types.Type representation. // Also saves a lot of computation and memory by avoiding re-translating @@ -38,13 +55,6 @@ func (g *irgen) typ(typ types2.Type) *types.Type { if !ok { res = g.typ0(typ) g.typs[typ] = res - - // Ensure we calculate the size for all concrete types seen by - // the frontend. This is another heavy hammer for something that - // should really be the backend's responsibility instead. - //if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() { - // types.CheckSize(res) - //} } return res } @@ -121,12 +131,12 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // instantiated type. rparams := make([]*types.Type, len(typ.TArgs())) for i, targ := range typ.TArgs() { - rparams[i] = g.typ(targ) + rparams[i] = g.typ1(targ) } ntyp.SetRParams(rparams) //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam()) - ntyp.SetUnderlying(g.typ(typ.Underlying())) + ntyp.SetUnderlying(g.typ1(typ.Underlying())) g.fillinMethods(typ, ntyp) return ntyp } @@ -137,23 +147,23 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { return obj.Type() case *types2.Array: - return types.NewArray(g.typ(typ.Elem()), typ.Len()) + return types.NewArray(g.typ1(typ.Elem()), typ.Len()) case *types2.Chan: - return types.NewChan(g.typ(typ.Elem()), dirs[typ.Dir()]) + return types.NewChan(g.typ1(typ.Elem()), dirs[typ.Dir()]) case *types2.Map: - return types.NewMap(g.typ(typ.Key()), g.typ(typ.Elem())) + return types.NewMap(g.typ1(typ.Key()), g.typ1(typ.Elem())) case *types2.Pointer: - return types.NewPtr(g.typ(typ.Elem())) + return types.NewPtr(g.typ1(typ.Elem())) case *types2.Signature: return g.signature(nil, typ) case *types2.Slice: - return types.NewSlice(g.typ(typ.Elem())) + return types.NewSlice(g.typ1(typ.Elem())) case *types2.Struct: fields := make([]*types.Field, typ.NumFields()) for i := range fields { v := typ.Field(i) - f := types.NewField(g.pos(v), g.selector(v), g.typ(v.Type())) + f := types.NewField(g.pos(v), g.selector(v), g.typ1(v.Type())) f.Note = typ.Tag(i) if v.Embedded() { f.Embedded = 1 @@ -167,7 +177,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { for i := range embeddeds { // TODO(mdempsky): Get embedding position. e := typ.EmbeddedType(i) - embeddeds[i] = types.NewField(src.NoXPos, nil, g.typ(e)) + embeddeds[i] = types.NewField(src.NoXPos, nil, g.typ1(e)) } methods := make([]*types.Field, typ.NumExplicitMethods()) @@ -190,7 +200,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { // TODO(danscales): we don't currently need to use the bounds // anywhere, so eventually we can probably remove. - bound := g.typ(typ.Bound()) + bound := g.typ1(typ.Bound()) *tp.Methods() = *bound.Methods() return tp @@ -205,8 +215,6 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { fields[i] = g.param(typ.At(i)) } t := types.NewStruct(types.LocalPkg, fields) - //types.CheckSize(t) - // Can only set after doing the types.CheckSize() t.StructType().Funarg = types.FunargResults return t @@ -223,7 +231,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { if typ.NumMethods() != 0 { targs := make([]ir.Node, len(typ.TArgs())) for i, targ := range typ.TArgs() { - targs[i] = ir.TypeNode(g.typ(targ)) + targs[i] = ir.TypeNode(g.typ1(targ)) } methods := make([]*types.Field, typ.NumMethods()) @@ -256,7 +264,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) { rparams := types2.AsSignature(m.Type()).RParams() tparams := make([]*types.Field, len(rparams)) for i, rparam := range rparams { - tparams[i] = types.NewField(src.NoXPos, nil, g.typ(rparam.Type())) + tparams[i] = types.NewField(src.NoXPos, nil, g.typ1(rparam.Type())) } assert(len(tparams) == len(targs)) subst := &subster{ @@ -286,7 +294,7 @@ func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type tparams := make([]*types.Field, len(tparams2)) for i := range tparams { tp := tparams2[i] - tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ(tp.Type())) + tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type())) } do := func(typ *types2.Tuple) []*types.Field { @@ -306,7 +314,7 @@ func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type } func (g *irgen) param(v *types2.Var) *types.Field { - return types.NewField(g.pos(v), g.sym(v), g.typ(v.Type())) + return types.NewField(g.pos(v), g.sym(v), g.typ1(v.Type())) } func (g *irgen) sym(obj types2.Object) *types.Sym { -- GitLab From a607408403df7515f831fef64991222673a50a68 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Wed, 20 Jan 2021 17:58:21 +0800 Subject: [PATCH 0305/1298] cmd/internal/obj/arm64: add support for op(extended register) with RSP arguments Refer to ARM reference manual, like add(extended register) instructions, the extension is encoded in the "option" field. If "Rd" or "Rn" is RSP and "option" is "010" then LSL is preferred. Therefore, the instrution "add Rm< Run-TryBot: fannie zhang TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/asm/testdata/arm64.s | 10 ++++ .../asm/internal/asm/testdata/arm64error.s | 3 ++ src/cmd/internal/obj/arm64/asm7.go | 46 +++++++++++++++++-- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 8635708320..d859171103 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -64,6 +64,16 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 CMN R1.SXTX<<2, R10 // 5fe921ab CMPW R2.UXTH<<3, R11 // 7f2d226b CMNW R1.SXTB, R9 // 3f81212b + ADD R1<<1, RSP, R3 // e367218b + ADDW R1<<2, R3, RSP // 7f48210b + SUB R1<<3, RSP // ff6f21cb + SUBS R1<<4, RSP, R3 // e37321eb + ADDS R1<<1, RSP, R4 // e46721ab + CMP R1<<2, RSP // ff6b21eb + CMN R1<<3, RSP // ff6f21ab + ADDS R1<<1, ZR, R4 // e40701ab + ADD R3<<50, ZR, ZR // ffcb038b + CMP R4<<24, ZR // ff6304eb CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b CMPW $40960, R0 // 1f284071 CMPW $27745, R2 // 3b8c8d525f001b6b diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 1c8eaa1752..64bade2051 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -368,4 +368,7 @@ TEXT errors(SB),$0 CASPD (R2, R3), (R2), (R9, R10) // ERROR "destination register pair must start from even register" CASPD (R2, R4), (R2), (R8, R9) // ERROR "source register pair must be contiguous" CASPD (R2, R3), (R2), (R8, R10) // ERROR "destination register pair must be contiguous" + ADD R1>>2, RSP, R3 // ERROR "illegal combination" + ADDS R2<<3, R3, RSP // ERROR "unexpected SP reference" + CMP R1<<5, RSP // ERROR "the left shift amount out of range 0 to 4" RET diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index e9f18e1bf0..275799aad3 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -321,15 +321,17 @@ var optab = []Optab{ {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0}, {AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0}, {AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_RSP, C_NONE, C_RSP, 107, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_NONE, C_NONE, C_RSP, 107, 4, 0, 0, 0}, {AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, {ACMP, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0}, + {ACMP, C_SHIFT, C_RSP, C_NONE, C_NONE, 107, 4, 0, 0, 0}, {ANEG, C_SHIFT, C_NONE, C_NONE, C_REG, 26, 4, 0, 0, 0}, {AADD, C_REG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0}, {AADD, C_REG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, {ACMP, C_REG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0}, {AADD, C_EXTREG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0}, {AADD, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, - {AMVN, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, {ACMP, C_EXTREG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0}, {AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, {AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0}, @@ -5458,6 +5460,41 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { c.ctxt.Diag("illegal destination register: %v\n", p) } o1 |= enc | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31) + + case 107: // op R<> 10) & 63 + shift := (p.From.Offset >> 22) & 3 + if shift != 0 { + c.ctxt.Diag("illegal combination: %v", p) + break + } + + if amount > 4 { + c.ctxt.Diag("the left shift amount out of range 0 to 4: %v", p) + break + } + rf := (p.From.Offset >> 16) & 31 + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + if r == 0 { + r = rt + } + + o1 = c.opxrrr(p, p.As, false) + o1 |= uint32(rf)<<16 | uint32(amount&7)<<10 | (uint32(r&31) << 5) | uint32(rt&31) } out[0] = o1 out[1] = o2 @@ -6394,11 +6431,10 @@ func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 { func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 { extension := uint32(0) if !extend { - switch a { - case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS: + if isADDop(a) { extension = LSL0_64 - - case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW: + } + if isADDWop(a) { extension = LSL0_32 } } -- GitLab From 71330963c080960f2f398fcd711a1fa14f68d503 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 11 Mar 2021 22:34:45 +0800 Subject: [PATCH 0306/1298] internal/poll: fix some grammar errors Change-Id: I25a6424bce9d372fa46e8bdd856095845d3397bf Reviewed-on: https://go-review.googlesource.com/c/go/+/300889 Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/internal/poll/splice_linux.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go index 971f754f43..49350b1ddc 100644 --- a/src/internal/poll/splice_linux.go +++ b/src/internal/poll/splice_linux.go @@ -160,9 +160,9 @@ type splicePipe struct { data int } -// splicePipePool caches pipes to avoid high frequency construction and destruction of pipe buffers. -// The garbage collector will free all pipes in the sync.Pool in periodically, thus we need to set up -// a finalizer for each pipe to close the its file descriptors before the actual GC. +// splicePipePool caches pipes to avoid high-frequency construction and destruction of pipe buffers. +// The garbage collector will free all pipes in the sync.Pool periodically, thus we need to set up +// a finalizer for each pipe to close its file descriptors before the actual GC. var splicePipePool = sync.Pool{New: newPoolPipe} func newPoolPipe() interface{} { @@ -175,10 +175,10 @@ func newPoolPipe() interface{} { return p } -// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from cache. +// getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from the cache. // // Note that it may fail to create a new pipe buffer by newPipe(), in which case getPipe() will return a generic error -// and system call name splice in string as the indication. +// and system call name splice in a string as the indication. func getPipe() (*splicePipe, string, error) { v := splicePipePool.Get() if v == nil { -- GitLab From e87c4bb3ef9d1f0aee3c9cc9fec8bef7fcadd6d8 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 10 Mar 2021 17:27:30 -0800 Subject: [PATCH 0307/1298] cmd/compile: fix noder.Addr() to not call typechecker Simple change to avoid calling the old typechecker in noder.Addr(). This fixes cases where generic code calls a pointer method with a non-pointer receiver. Added test typeparam/lockable.go that now works with this change. For lockable.go to work, also fix incorrect check to decide whether to translate an OXDOT now or later. We should delay translating an OXDOT until instantiation (because we don't know how embedding, etc. will work) if the receiver has any typeparam, not just if the receiver type is a simple typeparam. We also have to handle OXDOT for now in IsAddressable(), until we can remove calls to the old typechecker in (*irgen).funcBody(). Change-Id: I77ee5efcef9a8f6c7133564106a32437e36ba4bb Reviewed-on: https://go-review.googlesource.com/c/go/+/300990 Run-TryBot: Dan Scales TryBot-Result: Go Bot Trust: Dan Scales Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/ir/expr.go | 7 ++++ src/cmd/compile/internal/noder/expr.go | 2 +- src/cmd/compile/internal/noder/helpers.go | 9 ++-- test/typeparam/lockable.go | 50 +++++++++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 test/typeparam/lockable.go diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 65ed3cff66..2d62b22d8c 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -740,6 +740,13 @@ func IsAddressable(n Node) bool { case ODEREF, ODOTPTR: return true + case OXDOT: + // TODO(danscales): remove this case as we remove calls to the old + // typechecker in (*irgen).funcBody(). + if base.Flag.G == 0 { + return false + } + fallthrough case ODOT: n := n.(*SelectorExpr) return IsAddressable(n.X) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 06aa91199c..989ebf236e 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -188,7 +188,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { // than in typecheck.go. func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.SelectorExpr) ir.Node { x := g.expr(expr.X) - if x.Type().Kind() == types.TTYPEPARAM { + if x.Type().HasTParam() { // Leave a method call on a type param as an OXDOT, since it can // only be fully transformed once it has an instantiated type. n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value)) diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 4cb6bc3eab..2b084ff311 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -54,8 +54,11 @@ func Nil(pos src.XPos, typ *types.Type) ir.Node { // Expressions func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr { - // TODO(mdempsky): Avoid typecheck.Expr. Probably just need to set OPTRLIT when appropriate. - n := typecheck.Expr(typecheck.NodAddrAt(pos, x)).(*ir.AddrExpr) + n := typecheck.NodAddrAt(pos, x) + switch x.Op() { + case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT: + n.SetOp(ir.OPTRLIT) + } typed(types.NewPtr(x.Type()), n) return n } @@ -125,7 +128,7 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) n.IsDDD = dots if fun.Op() == ir.OXDOT { - if fun.(*ir.SelectorExpr).X.Type().Kind() != types.TTYPEPARAM { + if !fun.(*ir.SelectorExpr).X.Type().HasTParam() { base.FatalfAt(pos, "Expecting type param receiver in %v", fun) } // For methods called in a generic function, don't do any extra diff --git a/test/typeparam/lockable.go b/test/typeparam/lockable.go new file mode 100644 index 0000000000..d53817521f --- /dev/null +++ b/test/typeparam/lockable.go @@ -0,0 +1,50 @@ +// run -gcflags=-G=3 + +// Copyright 2021 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 "sync" + +// A _Lockable is a value that may be safely simultaneously accessed +// from multiple goroutines via the Get and Set methods. +type _Lockable[T any] struct { + T + mu sync.Mutex +} + +// Get returns the value stored in a _Lockable. +func (l *_Lockable[T]) get() T { + l.mu.Lock() + defer l.mu.Unlock() + return l.T +} + +// set sets the value in a _Lockable. +func (l *_Lockable[T]) set(v T) { + l.mu.Lock() + defer l.mu.Unlock() + l.T = v +} + +func main() { + sl := _Lockable[string]{T: "a"} + if got := sl.get(); got != "a" { + panic(got) + } + sl.set("b") + if got := sl.get(); got != "b" { + panic(got) + } + + il := _Lockable[int]{T: 1} + if got := il.get(); got != 1 { + panic(got) + } + il.set(2) + if got := il.get(); got != 2 { + panic(got) + } +} -- GitLab From e8b82789cda6c9d9e3dfc9a652b4d7a823b834f2 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 11 Mar 2021 14:22:16 +0800 Subject: [PATCH 0308/1298] A+C: add new e-mail addresses for Andy Pan Change-Id: I2be9cba124b407f27823b3a3778331b6118112cd Reviewed-on: https://go-review.googlesource.com/c/go/+/300470 Reviewed-by: Ian Lance Taylor Reviewed-by: Emmanuel Odeke --- AUTHORS | 2 +- CONTRIBUTORS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index eb05706811..1763ab88d8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -145,7 +145,7 @@ Andy Davis Andy Finkenstadt Andy Lindeman Andy Maloney -Andy Pan +Andy Pan Andy Walker Anfernee Yongkun Gui Angelo Bulfone diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b176a03328..5574026b75 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -240,7 +240,7 @@ Andy Davis Andy Finkenstadt Andy Lindeman Andy Maloney -Andy Pan +Andy Pan Andy Walker Andy Wang Andy Williams -- GitLab From 9289c120025be6fef3a27732229a38df3ebf47c7 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 12 Mar 2021 15:45:18 +0000 Subject: [PATCH 0309/1298] Revert "testing/fstest: test that ReadDirFile on a non-dir fails" This reverts commit 1853411d8376570295711f9084d494d458822578. Reason for revert: broke plan 9 builder. fixes #44967 Change-Id: Ib89448d37f7ab8bb05dbd89ce744431d807eb4da Reviewed-on: https://go-review.googlesource.com/c/go/+/301190 Reviewed-by: Bryan C. Mills Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder --- src/testing/fstest/testfs.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 27c603167f..e0ad60a17b 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -119,9 +119,6 @@ func (t *fsTester) openDir(dir string) fs.ReadDirFile { t.errorf("%s: Open: %v", dir, err) return nil } - // It'd be nice to test here that f.Read fails, because f is a directory. - // However, FreeBSD supports calling read on a directory. - // See https://groups.google.com/g/golang-dev/c/rh8jwxyG1PQ. d, ok := f.(fs.ReadDirFile) if !ok { f.Close() @@ -517,12 +514,6 @@ func (t *fsTester) checkFile(file string) { return } - if dir, ok := f.(fs.ReadDirFile); ok { - if _, err := dir.ReadDir(-1); err == nil { - t.errorf("%s: ReadDir of non-dir file should return an error", file) - } - } - data, err := ioutil.ReadAll(f) if err != nil { f.Close() -- GitLab From 086357e8f617c325339fdaedd13563dbdb05b00d Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 12 Mar 2021 11:21:38 -0500 Subject: [PATCH 0310/1298] cmd/go: include default GOEXPERIMENT in build config Currently, the build config includes GOEXPERIMENT environment variable if it is not empty, but that doesn't take the default value (set at make.bash/bat/rc time) into consideration. This may cause standard library packages appearing stale, as the build config appears changed. This CL changes it to use cfg.GOEXPERIMENT variable, which includes the default value (if it is not overwritten). May fix regabi and staticlockranking builders. Change-Id: I242f887167f8e99192010be5c1a046eb88ab0c2a Reviewed-on: https://go-review.googlesource.com/c/go/+/301269 Trust: Cherry Zhang Run-TryBot: Cherry Zhang Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/internal/work/exec.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index bd5ae46739..fd3d3e03bb 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -276,7 +276,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) - if exp := cfg.Getenv("GOEXPERIMENT"); exp != "" { + if exp := cfg.GOEXPERIMENT; exp != "" { fmt.Fprintf(h, "GOEXPERIMENT=%q\n", exp) } @@ -1250,7 +1250,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) - if exp := cfg.Getenv("GOEXPERIMENT"); exp != "" { + if exp := cfg.GOEXPERIMENT; exp != "" { fmt.Fprintf(h, "GOEXPERIMENT=%q\n", exp) } -- GitLab From 735647d92e839f9ac3a91864a2c34263338a35e6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 8 Mar 2021 15:36:28 -0800 Subject: [PATCH 0311/1298] runtime: add alignment info to sizeclasses.go comments I was curious about the minimum possible alignment for each size class and the minimum size to guarantee any particular alignment (e.g., to know at what class size you can start assuming heap bits are byte- or word-aligned). Change-Id: I205b750286e8914986533c4f60712c420c3e63e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/299909 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Michael Knyszek Trust: Matthew Dempsky --- src/runtime/mksizeclasses.go | 26 ++++++- src/runtime/sizeclasses.go | 145 +++++++++++++++++++---------------- 2 files changed, 101 insertions(+), 70 deletions(-) diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go index b4a117d343..8b9bbe01e6 100644 --- a/src/runtime/mksizeclasses.go +++ b/src/runtime/mksizeclasses.go @@ -37,6 +37,7 @@ import ( "go/format" "io" "log" + "math/bits" "os" ) @@ -242,8 +243,9 @@ nextk: } func printComment(w io.Writer, classes []class) { - fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste") + fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste", "min align") prevSize := 0 + var minAligns [32]int for i, c := range classes { if i == 0 { continue @@ -252,8 +254,28 @@ func printComment(w io.Writer, classes []class) { objects := spanSize / c.size tailWaste := spanSize - c.size*(spanSize/c.size) maxWaste := float64((c.size-prevSize-1)*objects+tailWaste) / float64(spanSize) + alignBits := bits.TrailingZeros(uint(c.size)) + for i := range minAligns { + if i > alignBits { + minAligns[i] = 0 + } else if minAligns[i] == 0 { + minAligns[i] = c.size + } + } prevSize = c.size - fmt.Fprintf(w, "// %5d %9d %10d %7d %10d %8.2f%%\n", i, c.size, spanSize, objects, tailWaste, 100*maxWaste) + fmt.Fprintf(w, "// %5d %9d %10d %7d %10d %8.2f%% %9d\n", i, c.size, spanSize, objects, tailWaste, 100*maxWaste, 1< Date: Thu, 11 Mar 2021 15:45:52 -0800 Subject: [PATCH 0312/1298] runtime: simplify divmagic for span calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's both simpler and faster to just unconditionally do two 32-bit multiplies rather than a bunch of branching to try to avoid them. This is safe thanks to the tight bounds derived in [1] and verified during mksizeclasses.go. Benchstat results below for compilebench benchmarks on my P920. See also [2] for micro benchmarks comparing the new functions against the originals (as well as several basic attempts at optimizing them). name old time/op new time/op delta Template 295ms ± 3% 290ms ± 1% -1.95% (p=0.000 n=20+20) Unicode 113ms ± 3% 110ms ± 2% -2.32% (p=0.000 n=21+17) GoTypes 1.78s ± 1% 1.76s ± 1% -1.23% (p=0.000 n=21+20) Compiler 119ms ± 2% 117ms ± 4% -1.53% (p=0.007 n=20+20) SSA 14.3s ± 1% 13.8s ± 1% -3.12% (p=0.000 n=17+20) Flate 173ms ± 2% 170ms ± 1% -1.64% (p=0.000 n=20+19) GoParser 278ms ± 2% 273ms ± 2% -1.92% (p=0.000 n=20+19) Reflect 686ms ± 3% 671ms ± 3% -2.18% (p=0.000 n=19+20) Tar 255ms ± 2% 248ms ± 2% -2.90% (p=0.000 n=20+20) XML 335ms ± 3% 327ms ± 2% -2.34% (p=0.000 n=20+20) LinkCompiler 799ms ± 1% 799ms ± 1% ~ (p=0.925 n=20+20) ExternalLinkCompiler 1.90s ± 1% 1.90s ± 0% ~ (p=0.327 n=20+20) LinkWithoutDebugCompiler 385ms ± 1% 386ms ± 1% ~ (p=0.251 n=18+20) [Geo mean] 512ms 504ms -1.61% name old user-time/op new user-time/op delta Template 286ms ± 4% 282ms ± 4% -1.42% (p=0.025 n=21+20) Unicode 104ms ± 9% 102ms ±14% ~ (p=0.294 n=21+20) GoTypes 1.75s ± 3% 1.72s ± 2% -1.36% (p=0.000 n=21+20) Compiler 109ms ±11% 108ms ± 8% ~ (p=0.187 n=21+19) SSA 14.0s ± 1% 13.5s ± 2% -3.25% (p=0.000 n=16+20) Flate 166ms ± 4% 164ms ± 4% -1.34% (p=0.032 n=19+19) GoParser 268ms ± 4% 263ms ± 4% -1.71% (p=0.011 n=18+20) Reflect 666ms ± 3% 654ms ± 4% -1.77% (p=0.002 n=18+20) Tar 245ms ± 5% 236ms ± 6% -3.34% (p=0.000 n=20+20) XML 320ms ± 4% 314ms ± 3% -2.01% (p=0.001 n=19+18) LinkCompiler 744ms ± 4% 747ms ± 3% ~ (p=0.627 n=20+19) ExternalLinkCompiler 1.71s ± 3% 1.72s ± 2% ~ (p=0.149 n=20+20) LinkWithoutDebugCompiler 345ms ± 6% 342ms ± 8% ~ (p=0.355 n=20+20) [Geo mean] 484ms 477ms -1.50% [1] Daniel Lemire, Owen Kaser, Nathan Kurz. 2019. "Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries." https://arxiv.org/abs/1902.01961 [2] https://github.com/mdempsky/benchdivmagic Change-Id: Ie4d214e7a908b0d979c878f2d404bd56bdf374f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/300994 Run-TryBot: Matthew Dempsky Trust: Matthew Dempsky Trust: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Michael Knyszek --- src/runtime/mbitmap.go | 48 +++++++------- src/runtime/mcentral.go | 2 +- src/runtime/mheap.go | 16 +---- src/runtime/mksizeclasses.go | 118 ++++++++++++++++------------------- src/runtime/sizeclasses.go | 10 +-- 5 files changed, 80 insertions(+), 114 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index fbfaae0f93..2d12c563b8 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -226,16 +226,25 @@ func (s *mspan) isFree(index uintptr) bool { return *bytep&mask == 0 } -func (s *mspan) objIndex(p uintptr) uintptr { - byteOffset := p - s.base() - if byteOffset == 0 { - return 0 - } - if s.baseMask != 0 { - // s.baseMask is non-0, elemsize is a power of two, so shift by s.divShift - return byteOffset >> s.divShift +// divideByElemSize returns n/s.elemsize. +// n must be within [0, s.npages*_PageSize), +// or may be exactly s.npages*_PageSize +// if s.elemsize is from sizeclasses.go. +func (s *mspan) divideByElemSize(n uintptr) uintptr { + const doubleCheck = false + + // See explanation in mksizeclasses.go's computeDivMagic. + q := uintptr((uint64(n) * uint64(s.divMul)) >> 32) + + if doubleCheck && q != n/s.elemsize { + println(n, "/", s.elemsize, "should be", n/s.elemsize, "but got", q) + throw("bad magic division") } - return uintptr(((uint64(byteOffset) >> s.divShift) * uint64(s.divMul)) >> s.divShift2) + return q +} + +func (s *mspan) objIndex(p uintptr) uintptr { + return s.divideByElemSize(p - s.base()) } func markBitsForAddr(p uintptr) markBits { @@ -388,24 +397,9 @@ func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex ui } return } - // If this span holds object of a power of 2 size, just mask off the bits to - // the interior of the object. Otherwise use the size to get the base. - if s.baseMask != 0 { - // optimize for power of 2 sized objects. - base = s.base() - base = base + (p-base)&uintptr(s.baseMask) - objIndex = (base - s.base()) >> s.divShift - // base = p & s.baseMask is faster for small spans, - // but doesn't work for large spans. - // Overall, it's faster to use the more general computation above. - } else { - base = s.base() - if p-base >= s.elemsize { - // n := (p - base) / s.elemsize, using division by multiplication - objIndex = uintptr(p-base) >> s.divShift * uintptr(s.divMul) >> s.divShift2 - base += objIndex * s.elemsize - } - } + + objIndex = s.objIndex(p) + base = s.base() + objIndex*s.elemsize return } diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go index cd20dec539..8664ed48ab 100644 --- a/src/runtime/mcentral.go +++ b/src/runtime/mcentral.go @@ -236,7 +236,7 @@ func (c *mcentral) grow() *mspan { // Use division by multiplication and shifts to quickly compute: // n := (npages << _PageShift) / size - n := (npages << _PageShift) >> s.divShift * uintptr(s.divMul) >> s.divShift2 + n := s.divideByElemSize(npages << _PageShift) s.limit = s.base() + size*n heapBitsForAddr(s.base()).initSpan(s) return s diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 1855330da5..08019a4101 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -451,14 +451,11 @@ type mspan struct { // h->sweepgen is incremented by 2 after every GC sweepgen uint32 - divMul uint16 // for divide by elemsize - divMagic.mul - baseMask uint16 // if non-0, elemsize is a power of 2, & this will get object allocation base + divMul uint32 // for divide by elemsize allocCount uint16 // number of allocated objects spanclass spanClass // size class and noscan (uint8) state mSpanStateBox // mSpanInUse etc; accessed atomically (get/set methods) needzero uint8 // needs to be zeroed before allocation - divShift uint8 // for divide by elemsize - divMagic.shift - divShift2 uint8 // for divide by elemsize - divMagic.shift2 elemsize uintptr // computed from sizeclass or from npages limit uintptr // end of data in span speciallock mutex // guards specials list @@ -1224,20 +1221,11 @@ HaveSpan: if sizeclass := spanclass.sizeclass(); sizeclass == 0 { s.elemsize = nbytes s.nelems = 1 - - s.divShift = 0 s.divMul = 0 - s.divShift2 = 0 - s.baseMask = 0 } else { s.elemsize = uintptr(class_to_size[sizeclass]) s.nelems = nbytes / s.elemsize - - m := &class_to_divmagic[sizeclass] - s.divShift = m.shift - s.divMul = m.mul - s.divShift2 = m.shift2 - s.baseMask = m.baseMask + s.divMul = class_to_divmagic[sizeclass] } // Initialize mark and allocation structures. diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go index 8b9bbe01e6..ddbf1bf7fe 100644 --- a/src/runtime/mksizeclasses.go +++ b/src/runtime/mksizeclasses.go @@ -37,6 +37,7 @@ import ( "go/format" "io" "log" + "math" "math/bits" "os" ) @@ -88,11 +89,6 @@ const ( type class struct { size int // max size npages int // number of pages - - mul int - shift uint - shift2 uint - mask int } func powerOfTwo(x int) bool { @@ -169,9 +165,9 @@ func makeClasses() []class { return classes } -// computeDivMagic computes some magic constants to implement -// the division required to compute object number from span offset. -// n / c.size is implemented as n >> c.shift * c.mul >> c.shift2 +// computeDivMagic checks that the division required to compute object +// index from span offset can be computed using 32-bit multiplication. +// n / c.size is implemented as (n * (^uint32(0)/uint32(c.size) + 1)) >> 32 // for all 0 <= n <= c.npages * pageSize func computeDivMagic(c *class) { // divisor @@ -183,62 +179,60 @@ func computeDivMagic(c *class) { // maximum input value for which the formula needs to work. max := c.npages * pageSize + // As reported in [1], if n and d are unsigned N-bit integers, we + // can compute n / d as ⌊n * c / 2^F⌋, where c is ⌈2^F / d⌉ and F is + // computed with: + // + // Algorithm 2: Algorithm to select the number of fractional bits + // and the scaled approximate reciprocal in the case of unsigned + // integers. + // + // if d is a power of two then + // Let F ← log₂(d) and c = 1. + // else + // Let F ← N + L where L is the smallest integer + // such that d ≤ (2^(N+L) mod d) + 2^L. + // end if + // + // [1] "Faster Remainder by Direct Computation: Applications to + // Compilers and Software Libraries" Daniel Lemire, Owen Kaser, + // Nathan Kurz arXiv:1902.01961 + // + // To minimize the risk of introducing errors, we implement the + // algorithm exactly as stated, rather than trying to adapt it to + // fit typical Go idioms. + N := bits.Len(uint(max)) + var F int if powerOfTwo(d) { - // If the size is a power of two, heapBitsForObject can divide even faster by masking. - // Compute this mask. - if max >= 1<<16 { - panic("max too big for power of two size") + F = int(math.Log2(float64(d))) + if d != 1<>= 1 - max >>= 1 - } - - // Find the smallest k that works. - // A small k allows us to fit the math required into 32 bits - // so we can use 32-bit multiplies and shifts on 32-bit platforms. -nextk: - for k := uint(0); ; k++ { - mul := (int(1)<>k != n/d { - continue nextk + } else { + for L := 0; ; L++ { + if d <= ((1<<(N+L))%d)+(1<= 1<<16 { - panic("mul too big") - } - if uint64(mul)*uint64(max) >= 1<<32 { - panic("mul*max too big") - } - c.mul = mul - c.shift2 = k - break } - // double-check. + // Also, noted in the paper, F is the smallest number of fractional + // bits required. We use 32 bits, because it works for all size + // classes and is fast on all CPU architectures that we support. + if F > 32 { + fmt.Printf("d=%d max=%d N=%d F=%d\n", c.size, max, N, F) + panic("size class requires more than 32 bits of precision") + } + + // Brute force double-check with the exact computation that will be + // done by the runtime. + m := ^uint32(0)/uint32(c.size) + 1 for n := 0; n <= max; n++ { - if n*c.mul>>c.shift2 != n/d { - fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n) - panic("bad multiply magic") - } - // Also check the exact computations that will be done by the runtime, - // for both 32 and 64 bit operations. - if uint32(n)*uint32(c.mul)>>uint8(c.shift2) != uint32(n/d) { - fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n) + if uint32((uint64(n)*uint64(m))>>32) != uint32(n/c.size) { + fmt.Printf("d=%d max=%d m=%d n=%d\n", d, max, m, n) panic("bad 32-bit multiply magic") } - if uint64(n)*uint64(c.mul)>>uint8(c.shift2) != uint64(n/d) { - fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n) - panic("bad 64-bit multiply magic") - } } } @@ -302,15 +296,13 @@ func printClasses(w io.Writer, classes []class) { } fmt.Fprintln(w, "}") - fmt.Fprintln(w, "type divMagic struct {") - fmt.Fprintln(w, " shift uint8") - fmt.Fprintln(w, " shift2 uint8") - fmt.Fprintln(w, " mul uint16") - fmt.Fprintln(w, " baseMask uint16") - fmt.Fprintln(w, "}") - fmt.Fprint(w, "var class_to_divmagic = [_NumSizeClasses]divMagic {") + fmt.Fprint(w, "var class_to_divmagic = [_NumSizeClasses]uint32 {") for _, c := range classes { - fmt.Fprintf(w, "{%d,%d,%d,%d},", c.shift, c.shift2, c.mul, c.mask) + if c.size == 0 { + fmt.Fprintf(w, "0,") + continue + } + fmt.Fprintf(w, "^uint32(0)/%d+1,", c.size) } fmt.Fprintln(w, "}") diff --git a/src/runtime/sizeclasses.go b/src/runtime/sizeclasses.go index d71ceeab7b..65c72cfb1a 100644 --- a/src/runtime/sizeclasses.go +++ b/src/runtime/sizeclasses.go @@ -92,14 +92,6 @@ const ( var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 24, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768} var class_to_allocnpages = [_NumSizeClasses]uint8{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, 3, 1, 3, 2, 3, 4, 5, 6, 1, 7, 6, 5, 4, 3, 5, 7, 2, 9, 7, 5, 8, 3, 10, 7, 4} - -type divMagic struct { - shift uint8 - shift2 uint8 - mul uint16 - baseMask uint16 -} - -var class_to_divmagic = [_NumSizeClasses]divMagic{{0, 0, 0, 0}, {3, 0, 1, 65528}, {4, 0, 1, 65520}, {3, 11, 683, 0}, {5, 0, 1, 65504}, {4, 11, 683, 0}, {6, 0, 1, 65472}, {4, 10, 205, 0}, {5, 9, 171, 0}, {4, 11, 293, 0}, {7, 0, 1, 65408}, {4, 13, 911, 0}, {5, 10, 205, 0}, {4, 12, 373, 0}, {6, 9, 171, 0}, {4, 13, 631, 0}, {5, 11, 293, 0}, {4, 13, 547, 0}, {8, 0, 1, 65280}, {5, 9, 57, 0}, {6, 9, 103, 0}, {5, 12, 373, 0}, {7, 7, 43, 0}, {5, 10, 79, 0}, {6, 10, 147, 0}, {5, 11, 137, 0}, {9, 0, 1, 65024}, {6, 9, 57, 0}, {7, 9, 103, 0}, {6, 11, 187, 0}, {8, 7, 43, 0}, {7, 8, 37, 0}, {10, 0, 1, 64512}, {7, 9, 57, 0}, {8, 6, 13, 0}, {7, 11, 187, 0}, {9, 5, 11, 0}, {8, 8, 37, 0}, {11, 0, 1, 63488}, {8, 9, 57, 0}, {7, 10, 49, 0}, {10, 5, 11, 0}, {7, 10, 41, 0}, {7, 9, 19, 0}, {12, 0, 1, 61440}, {8, 9, 27, 0}, {8, 10, 49, 0}, {11, 5, 11, 0}, {7, 13, 161, 0}, {7, 13, 155, 0}, {8, 9, 19, 0}, {13, 0, 1, 57344}, {8, 12, 111, 0}, {9, 9, 27, 0}, {11, 6, 13, 0}, {7, 14, 193, 0}, {12, 3, 3, 0}, {8, 13, 155, 0}, {11, 8, 37, 0}, {14, 0, 1, 49152}, {11, 8, 29, 0}, {7, 13, 55, 0}, {12, 5, 7, 0}, {8, 14, 193, 0}, {13, 3, 3, 0}, {7, 14, 77, 0}, {12, 7, 19, 0}, {15, 0, 1, 32768}} +var class_to_divmagic = [_NumSizeClasses]uint32{0, ^uint32(0)/8 + 1, ^uint32(0)/16 + 1, ^uint32(0)/24 + 1, ^uint32(0)/32 + 1, ^uint32(0)/48 + 1, ^uint32(0)/64 + 1, ^uint32(0)/80 + 1, ^uint32(0)/96 + 1, ^uint32(0)/112 + 1, ^uint32(0)/128 + 1, ^uint32(0)/144 + 1, ^uint32(0)/160 + 1, ^uint32(0)/176 + 1, ^uint32(0)/192 + 1, ^uint32(0)/208 + 1, ^uint32(0)/224 + 1, ^uint32(0)/240 + 1, ^uint32(0)/256 + 1, ^uint32(0)/288 + 1, ^uint32(0)/320 + 1, ^uint32(0)/352 + 1, ^uint32(0)/384 + 1, ^uint32(0)/416 + 1, ^uint32(0)/448 + 1, ^uint32(0)/480 + 1, ^uint32(0)/512 + 1, ^uint32(0)/576 + 1, ^uint32(0)/640 + 1, ^uint32(0)/704 + 1, ^uint32(0)/768 + 1, ^uint32(0)/896 + 1, ^uint32(0)/1024 + 1, ^uint32(0)/1152 + 1, ^uint32(0)/1280 + 1, ^uint32(0)/1408 + 1, ^uint32(0)/1536 + 1, ^uint32(0)/1792 + 1, ^uint32(0)/2048 + 1, ^uint32(0)/2304 + 1, ^uint32(0)/2688 + 1, ^uint32(0)/3072 + 1, ^uint32(0)/3200 + 1, ^uint32(0)/3456 + 1, ^uint32(0)/4096 + 1, ^uint32(0)/4864 + 1, ^uint32(0)/5376 + 1, ^uint32(0)/6144 + 1, ^uint32(0)/6528 + 1, ^uint32(0)/6784 + 1, ^uint32(0)/6912 + 1, ^uint32(0)/8192 + 1, ^uint32(0)/9472 + 1, ^uint32(0)/9728 + 1, ^uint32(0)/10240 + 1, ^uint32(0)/10880 + 1, ^uint32(0)/12288 + 1, ^uint32(0)/13568 + 1, ^uint32(0)/14336 + 1, ^uint32(0)/16384 + 1, ^uint32(0)/18432 + 1, ^uint32(0)/19072 + 1, ^uint32(0)/20480 + 1, ^uint32(0)/21760 + 1, ^uint32(0)/24576 + 1, ^uint32(0)/27264 + 1, ^uint32(0)/28672 + 1, ^uint32(0)/32768 + 1} var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv + 1]uint8{32, 33, 34, 35, 36, 37, 37, 38, 38, 39, 39, 40, 40, 40, 41, 41, 41, 42, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, 48, 48, 49, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67} -- GitLab From cdd08e615a9b92742b21a94443720b6d70452510 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 12 Mar 2021 09:51:50 -0800 Subject: [PATCH 0313/1298] cmd/go/internal/load: always set IsImportCycle when in a cycle When hitting an import cycle in reusePackage, and there is already an error set, make sure IsImportCycle is set so that we don't end up stuck in a loop. Fixes #25830 Change-Id: Iba966aea4a637dfc34ee22782a477209ac48c9bd Reviewed-on: https://go-review.googlesource.com/c/go/+/301289 Trust: Roland Shoemaker Run-TryBot: Roland Shoemaker Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot --- src/cmd/go/internal/load/pkg.go | 5 +++++ src/cmd/go/testdata/script/list_err_cycle.txt | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/cmd/go/testdata/script/list_err_cycle.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 8b12faf4cd..61fde895f8 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1323,6 +1323,11 @@ func reusePackage(p *Package, stk *ImportStack) *Package { Err: errors.New("import cycle not allowed"), IsImportCycle: true, } + } else if !p.Error.IsImportCycle { + // If the error is already set, but it does not indicate that + // we are in an import cycle, set IsImportCycle so that we don't + // end up stuck in a loop down the road. + p.Error.IsImportCycle = true } p.Incomplete = true } diff --git a/src/cmd/go/testdata/script/list_err_cycle.txt b/src/cmd/go/testdata/script/list_err_cycle.txt new file mode 100644 index 0000000000..44b82a62b0 --- /dev/null +++ b/src/cmd/go/testdata/script/list_err_cycle.txt @@ -0,0 +1,15 @@ +# Check that we don't get infinite recursion when loading a package with +# an import cycle and another error. Verifies #25830. +! go list +stderr 'found packages a \(a.go\) and b \(b.go\)' + +-- go.mod -- +module errcycle + +go 1.16 +-- a.go -- +package a + +import _ "errcycle" +-- b.go -- +package b \ No newline at end of file -- GitLab From 7240a18adbfcff5cfe750a1fa4af0fd42ade4381 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 5 Mar 2021 14:24:41 -0500 Subject: [PATCH 0314/1298] cmd/compile: test register ABI for method, interface, closure calls This is enabled with a ridiculous magic name for method, or for last input type passed, that needs to be changed to something inutterable before actual release. Ridiculous method name: MagicMethodNameForTestingRegisterABI Ridiculous last (input) type name: MagicLastTypeNameForTestingRegisterABI RLTN is tested with strings.Contains, so you can have MagicLastTypeNameForTestingRegisterABI1 and MagicLastTypeNameForTestingRegisterABI2 if that is helpful Includes test test/abi/fibish2.go Updates #44816. Change-Id: I592a6edc71ca9bebdd1d00e24edee1ceebb3e43f Reviewed-on: https://go-review.googlesource.com/c/go/+/299410 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 54 ++++++++-------- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 8 +-- .../compile/internal/ssa/gen/genericOps.go | 27 ++++++-- src/cmd/compile/internal/ssa/op.go | 47 ++++++++++++-- src/cmd/compile/internal/ssa/opGen.go | 8 +-- src/cmd/compile/internal/ssagen/ssa.go | 61 ++++++++++++++++--- test/abi/fibish2.go | 40 ++++++++++++ test/abi/fibish2.out | 1 + test/abi/fibish_closure.go | 34 +++++++++++ test/abi/fibish_closure.out | 1 + test/abi/methods.go | 51 ++++++++++++++++ test/abi/methods.out | 2 + 12 files changed, 279 insertions(+), 55 deletions(-) create mode 100644 test/abi/fibish2.go create mode 100644 test/abi/fibish2.out create mode 100644 test/abi/fibish_closure.go create mode 100644 test/abi/fibish_closure.out create mode 100644 test/abi/methods.go create mode 100644 test/abi/methods.out diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 6e2004224f..29a8f670b0 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -386,41 +386,34 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, which := selector.AuxInt if which == aux.NResults() { // mem is after the results. // rewrite v as a Copy of call -- the replacement call will produce a mem. - if call.Op == OpStaticLECall { - if leaf != selector { - panic("Unexpected selector of memory") - } - // StaticCall selector will address last element of Result. - // TODO do this for all the other call types eventually. - if aux.abiInfo == nil { - panic(badVal("aux.abiInfo nil for call", call)) - } - if existing := x.memForCall[call.ID]; existing == nil { - selector.AuxInt = int64(aux.abiInfo.OutRegistersUsed()) - x.memForCall[call.ID] = selector - } else { - selector.copyOf(existing) - } + if leaf != selector { + panic("Unexpected selector of memory") + } + if aux.abiInfo == nil { + panic(badVal("aux.abiInfo nil for call", call)) + } + if existing := x.memForCall[call.ID]; existing == nil { + selector.AuxInt = int64(aux.abiInfo.OutRegistersUsed()) + x.memForCall[call.ID] = selector } else { - leaf.copyOf(call) + selector.copyOf(existing) } + } else { leafType := removeTrivialWrapperTypes(leaf.Type) if x.canSSAType(leafType) { pt := types.NewPtr(leafType) // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input. - if call.Op == OpStaticLECall { // TODO this is temporary until all calls are register-able - // Create a "mem" for any loads that need to occur. - if mem := x.memForCall[call.ID]; mem != nil { - if mem.Block != call.Block { - panic(fmt.Errorf("selector and call need to be in same block, selector=%s; call=%s", selector.LongString(), call.LongString())) - } - call = mem - } else { - mem = call.Block.NewValue1I(call.Pos.WithNotStmt(), OpSelectN, types.TypeMem, int64(aux.abiInfo.OutRegistersUsed()), call) - x.memForCall[call.ID] = mem - call = mem + // Create a "mem" for any loads that need to occur. + if mem := x.memForCall[call.ID]; mem != nil { + if mem.Block != call.Block { + panic(fmt.Errorf("selector and call need to be in same block, selector=%s; call=%s", selector.LongString(), call.LongString())) } + call = mem + } else { + mem = call.Block.NewValue1I(call.Pos.WithNotStmt(), OpSelectN, types.TypeMem, int64(aux.abiInfo.OutRegistersUsed()), call) + x.memForCall[call.ID] = mem + call = mem } outParam := aux.abiInfo.OutParam(int(which)) if len(outParam.Registers) > 0 { @@ -1350,14 +1343,15 @@ func expandCalls(f *Func) { case OpStaticLECall: v.Op = OpStaticCall rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams()) - // TODO need to insert all the register types. v.Type = types.NewResults(append(rts, types.TypeMem)) case OpClosureLECall: v.Op = OpClosureCall - v.Type = types.TypeMem + rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams()) + v.Type = types.NewResults(append(rts, types.TypeMem)) case OpInterLECall: v.Op = OpInterCall - v.Type = types.TypeMem + rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams()) + v.Type = types.NewResults(append(rts, types.TypeMem)) } } } diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 6bf5be9e47..6c3fe1d192 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -775,10 +775,10 @@ func init() { faultOnNilArg0: true, }, - // With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific registers. - {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem - {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem - {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem + // With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific in and out registers. + {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem + {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem + {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem // arg0 = destination pointer // arg1 = source pointer diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index ee85156a42..2a5b77bad0 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -264,7 +264,7 @@ var genericOps = []opData{ // ±0 → ±0 (sign preserved) // x<0 → NaN // NaN → NaN - {name: "Sqrt", argLength: 1}, // √arg0 (floating point, double precision) + {name: "Sqrt", argLength: 1}, // √arg0 (floating point, double precision) {name: "Sqrt32", argLength: 1}, // √arg0 (floating point, single precision) // Round to integer, float64 only. @@ -396,9 +396,28 @@ var genericOps = []opData{ // TODO(josharian): ClosureCall and InterCall should have Int32 aux // to match StaticCall's 32 bit arg size limit. // TODO(drchase,josharian): could the arg size limit be bundled into the rules for CallOff? - {name: "ClosureCall", argLength: 3, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory. - {name: "StaticCall", argLength: -1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0..argN-1 are register inputs, argN=memory. auxint=arg size. Returns Result of register results, plus memory. - {name: "InterCall", argLength: 2, aux: "CallOff", call: true}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory. + + // Before lowering, LECalls receive their fixed inputs (first), memory (last), + // and a variable number of input values in the middle. + // They produce a variable number of result values. + // These values are not necessarily "SSA-able"; they can be too large, + // but in that case inputs are loaded immediately before with OpDereference, + // and outputs are stored immediately with OpStore. + // + // After call expansion, Calls have the same fixed-middle-memory arrangement of inputs, + // with the difference that the "middle" is only the register-resident inputs, + // and the non-register inputs are instead stored at ABI-defined offsets from SP + // (and the stores thread through the memory that is ultimately an input to the call). + // Outputs follow a similar pattern; register-resident outputs are the leading elements + // of a Result-typed output, with memory last, and any memory-resident outputs have been + // stored to ABI-defined locations. Each non-memory input or output fits in a register. + // + // Subsequent architecture-specific lowering only changes the opcode. + + {name: "ClosureCall", argLength: -1, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2..argN-1 are register inputs, argN=memory. auxint=arg size. Returns Result of register results, plus memory. + {name: "StaticCall", argLength: -1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0..argN-1 are register inputs, argN=memory. auxint=arg size. Returns Result of register results, plus memory. + {name: "InterCall", argLength: -1, aux: "CallOff", call: true}, // interface call. arg0=code pointer, arg1..argN-1 are register inputs, argN=memory, auxint=arg size. Returns Result of register results, plus memory. + {name: "ClosureLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded closure call. arg0=code pointer, arg1=context ptr, arg2..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. {name: "InterLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded interface call. arg0=code pointer, arg1..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem. diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 342df73d02..084098fb64 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -10,6 +10,7 @@ import ( "cmd/compile/internal/types" "cmd/internal/obj" "fmt" + "strings" ) // An Op encodes the specific operation that a Value performs. @@ -68,6 +69,27 @@ type regInfo struct { outputs []outputInfo } +func (r *regInfo) String() string { + s := "" + s += "INS:\n" + for _, i := range r.inputs { + mask := fmt.Sprintf("%64b", i.regs) + mask = strings.Replace(mask, "0", ".", -1) + s += fmt.Sprintf("%2d |%s|\n", i.idx, mask) + } + s += "OUTS:\n" + for _, i := range r.outputs { + mask := fmt.Sprintf("%64b", i.regs) + mask = strings.Replace(mask, "0", ".", -1) + s += fmt.Sprintf("%2d |%s|\n", i.idx, mask) + } + s += "CLOBBERS:\n" + mask := fmt.Sprintf("%64b", r.clobbers) + mask = strings.Replace(mask, "0", ".", -1) + s += fmt.Sprintf(" |%s|\n", mask) + return s +} + type auxType int8 type Param struct { @@ -116,20 +138,25 @@ func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo { a.reg = i return a.reg } - a.reg.inputs = append(a.reg.inputs, i.inputs...) + + k := len(i.inputs) for _, p := range a.abiInfo.InParams() { for _, r := range p.Registers { m := archRegForAbiReg(r, c) - a.reg.inputs = append(a.reg.inputs, inputInfo{idx: len(a.reg.inputs), regs: (1 << m)}) + a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)}) + k++ } } - a.reg.outputs = append(a.reg.outputs, i.outputs...) + a.reg.inputs = append(a.reg.inputs, i.inputs...) // These are less constrained, thus should come last + k = len(i.outputs) for _, p := range a.abiInfo.OutParams() { for _, r := range p.Registers { m := archRegForAbiReg(r, c) - a.reg.outputs = append(a.reg.outputs, outputInfo{idx: len(a.reg.outputs), regs: (1 << m)}) + a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)}) + k++ } } + a.reg.outputs = append(a.reg.outputs, i.outputs...) a.reg.clobbers = i.clobbers return a.reg } @@ -299,12 +326,20 @@ func StaticAuxCall(sym *obj.LSym, args []Param, results []Param, paramResultInfo // InterfaceAuxCall returns an AuxCall for an interface call. func InterfaceAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} + var reg *regInfo + if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { + reg = ®Info{} + } + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo, reg: reg} } // ClosureAuxCall returns an AuxCall for a closure call. func ClosureAuxCall(args []Param, results []Param, paramResultInfo *abi.ABIParamResultInfo) *AuxCall { - return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo} + var reg *regInfo + if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 { + reg = ®Info{} + } + return &AuxCall{Fn: nil, args: args, results: results, abiInfo: paramResultInfo, reg: reg} } func (*AuxCall) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index e65c4c4a18..322e1c2283 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -13275,7 +13275,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLclosure", auxType: auxCallOff, - argLen: 3, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ @@ -13289,7 +13289,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLinter", auxType: auxCallOff, - argLen: 2, + argLen: -1, clobberFlags: true, call: true, reg: regInfo{ @@ -35596,7 +35596,7 @@ var opcodeTable = [...]opInfo{ { name: "ClosureCall", auxType: auxCallOff, - argLen: 3, + argLen: -1, call: true, generic: true, }, @@ -35610,7 +35610,7 @@ var opcodeTable = [...]opInfo{ { name: "InterCall", auxType: auxCallOff, - argLen: 2, + argLen: -1, call: true, generic: true, }, diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f1f244cce6..7e461f4fe8 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -217,6 +217,10 @@ func AbiForFunc(fn *ir.Func) *abi.ABIConfig { return abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1).Copy() // No idea what races will result, be safe } +// TODO (NLT 2021-04-15) This must be changed to a name that cannot match; it may be helpful to other register ABI work to keep the trigger-logic +const magicNameDotSuffix = ".MagicMethodNameForTestingRegisterABI" +const magicLastTypeName = "MagicLastTypeNameForTestingRegisterABI" + // abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. // Passing a nil function returns ABIInternal. func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { @@ -224,16 +228,38 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { if !regabiEnabledForAllCompilation() { a = abi0 } - if fn != nil && fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + + if fn != nil { name := ir.FuncName(fn) - if strings.Contains(name, ".") { - base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) + magicName := strings.HasSuffix(name, magicNameDotSuffix) + if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working + if strings.Contains(name, ".") { + if !magicName { + base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) + } + } + a = abi1 + } else if magicName { + if base.FmtPos(fn.Pos()) == ":1" { + // no way to put a pragma here, and it will error out in the real source code if they did not do it there. + a = abi1 + } else { + base.ErrorfAt(fn.Pos(), "Methods with magic name %s (method %s) must also specify //go:registerparams", magicNameDotSuffix[1:], name) + } + } + if regAbiForFuncType(fn.Type().FuncType()) { + // fmt.Printf("Saw magic last type name for function %s\n", name) + a = abi1 } - a = abi1 } return a } +func regAbiForFuncType(ft *types.Func) bool { + np := ft.Params.NumFields() + return np > 0 && strings.Contains(ft.Params.FieldType(np-1).String(), magicLastTypeName) +} + func regabiEnabledForAllCompilation() bool { // TODO compiler does not yet change behavior for GOEXPERIMENT=regabi return false && objabi.Regabi_enabled != 0 @@ -4863,6 +4889,22 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val var callArgs []*ssa.Value // For late-expansion, the args themselves (not stored, args to the call instead). inRegisters := false + var magicFnNameSym *types.Sym + if fn.Name() != nil { + magicFnNameSym = fn.Name().Sym() + ss := magicFnNameSym.Name + if strings.HasSuffix(ss, magicNameDotSuffix) { + inRegisters = true + } + } + if magicFnNameSym == nil && n.Op() == ir.OCALLINTER { + magicFnNameSym = fn.(*ir.SelectorExpr).Sym() + ss := magicFnNameSym.Name + if strings.HasSuffix(ss, magicNameDotSuffix[1:]) { + inRegisters = true + } + } + switch n.Op() { case ir.OCALLFUNC: if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC { @@ -4871,7 +4913,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // TODO(register args) remove after register abi is working inRegistersImported := fn.Pragma()&ir.RegisterParams != 0 inRegistersSamePackage := fn.Func != nil && fn.Func.Pragma&ir.RegisterParams != 0 - inRegisters = inRegistersImported || inRegistersSamePackage + inRegisters = inRegisters || inRegistersImported || inRegistersSamePackage break } closure = s.expr(fn) @@ -4898,6 +4940,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val types.CalcSize(fn.Type()) stksize := fn.Type().ArgWidth() // includes receiver, args, and results + if regAbiForFuncType(n.X.Type().FuncType()) { + // fmt.Printf("Saw magic last type in call %v\n", n) + inRegisters = true + } + callABI := s.f.ABI1 if !inRegisters { callABI = s.f.ABI0 @@ -5047,11 +5094,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val // critical that we not clobber any arguments already // stored onto the stack. codeptr = s.rawLoad(types.Types[types.TUINTPTR], closure) - aux := ssa.ClosureAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) + aux := ssa.ClosureAuxCall(ACArgs, ACResults, callABI.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure) case codeptr != nil: // Note that the "receiver" parameter is nil because the actual receiver is the first input parameter. - aux := ssa.InterfaceAuxCall(ACArgs, ACResults, s.f.ABIDefault.ABIAnalyzeTypes(nil, ssa.ACParamsToTypes(ACArgs), ssa.ACParamsToTypes(ACResults))) + aux := ssa.InterfaceAuxCall(ACArgs, ACResults, params) call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr) case callee != nil: aux := ssa.StaticAuxCall(callTargetLSym(callee, s.curfn.LSym), ACArgs, ACResults, params) diff --git a/test/abi/fibish2.go b/test/abi/fibish2.go new file mode 100644 index 0000000000..14f3f9ada7 --- /dev/null +++ b/test/abi/fibish2.go @@ -0,0 +1,40 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 "fmt" + +// Test that register results are correctly returned (and passed) + +type MagicLastTypeNameForTestingRegisterABI func(int,MagicLastTypeNameForTestingRegisterABI) int + +//go:registerparams +//go:noinline +func minus(decrement int) MagicLastTypeNameForTestingRegisterABI { + return MagicLastTypeNameForTestingRegisterABI( func(x int, _ MagicLastTypeNameForTestingRegisterABI) int { return x-decrement} ) +} + +//go:noinline +func f(x int, sub1 MagicLastTypeNameForTestingRegisterABI) (int, int) { + + if x < 3 { + return 0, x + } + + a, b := f(sub1(sub1(x, sub1), sub1), sub1) + c, d := f(sub1(x, sub1), sub1) + return a + d, b + c +} + +func main() { + x := 40 + a, b := f(x, minus(1)) + fmt.Printf("f(%d)=%d,%d\n", x, a, b) +} diff --git a/test/abi/fibish2.out b/test/abi/fibish2.out new file mode 100644 index 0000000000..9bd80c32c9 --- /dev/null +++ b/test/abi/fibish2.out @@ -0,0 +1 @@ +f(40)=39088169,126491972 diff --git a/test/abi/fibish_closure.go b/test/abi/fibish_closure.go new file mode 100644 index 0000000000..988001ebac --- /dev/null +++ b/test/abi/fibish_closure.go @@ -0,0 +1,34 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 "fmt" + +// Test that register results are correctly returned (and passed) + +type MagicLastTypeNameForTestingRegisterABI func(int, MagicLastTypeNameForTestingRegisterABI) (int, int) + +//go:noinline +func f(x int, unused MagicLastTypeNameForTestingRegisterABI) (int, int) { + + if x < 3 { + return 0, x + } + + a, b := f(x-2, unused) + c, d := f(x-1, unused) + return a + d, b + c +} + +func main() { + x := 40 + a, b := f(x, f) + fmt.Printf("f(%d)=%d,%d\n", x, a, b) +} diff --git a/test/abi/fibish_closure.out b/test/abi/fibish_closure.out new file mode 100644 index 0000000000..9bd80c32c9 --- /dev/null +++ b/test/abi/fibish_closure.out @@ -0,0 +1 @@ +f(40)=39088169,126491972 diff --git a/test/abi/methods.go b/test/abi/methods.go new file mode 100644 index 0000000000..9ecae9833e --- /dev/null +++ b/test/abi/methods.go @@ -0,0 +1,51 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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 ( + "fmt" +) + +type toobig struct { + a,b,c string +} + +//go:registerparams +//go:noinline +func (x *toobig) MagicMethodNameForTestingRegisterABI(y toobig, z toobig) toobig { + return toobig{x.a, y.b, z.c} +} + +type AnInterface interface { + MagicMethodNameForTestingRegisterABI(y toobig, z toobig) toobig +} + +//go:registerparams +//go:noinline +func I(a,b,c string) toobig { + return toobig{a,b,c} +} + +// AnIid prevents the compiler from figuring out what the interface really is. +//go:noinline +func AnIid(x AnInterface) AnInterface { + return x +} + +var tmp toobig +func main() { + x := I("Ahoy", "1,", "2") + y := I("3", "there,", "4") + z := I("5", "6,", "Matey") + tmp = x.MagicMethodNameForTestingRegisterABI(y,z) + fmt.Println(tmp.a, tmp.b, tmp.c) + tmp = AnIid(&x).MagicMethodNameForTestingRegisterABI(y,z) + fmt.Println(tmp.a, tmp.b, tmp.c) +} diff --git a/test/abi/methods.out b/test/abi/methods.out new file mode 100644 index 0000000000..5a72b0edf7 --- /dev/null +++ b/test/abi/methods.out @@ -0,0 +1,2 @@ +Ahoy there, Matey +Ahoy there, Matey -- GitLab From 78052f4c4eac5a964a0037f6e18d1a2d31b65189 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 12 Mar 2021 10:56:08 -0500 Subject: [PATCH 0315/1298] cmd/compile: minor cleanup -- remove dead code conditional on test It would fail now if it were turned on. Updsates #44816. Change-Id: I19d94f0cb2dd84271f5304c796d7c81e1e64af25 Reviewed-on: https://go-review.googlesource.com/c/go/+/301270 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssagen/ssa.go | 71 +++++++++----------------- 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 7e461f4fe8..0029558963 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1930,7 +1930,6 @@ const shareDeferExits = false // It returns a BlockRet block that ends the control flow. Its control value // will be set to the final memory state. func (s *state) exit() *ssa.Block { - lateResultLowering := s.f.DebugTest if s.hasdefer { if s.hasOpenDefers { if shareDeferExits && s.lastDeferExit != nil && len(s.openDefers) == s.lastDeferCount { @@ -1951,56 +1950,34 @@ func (s *state) exit() *ssa.Block { var m *ssa.Value // Do actual return. // These currently turn into self-copies (in many cases). - if lateResultLowering { - resultFields := s.curfn.Type().Results().FieldSlice() - results := make([]*ssa.Value, len(resultFields)+1, len(resultFields)+1) - m = s.newValue0(ssa.OpMakeResult, s.f.OwnAux.LateExpansionResultType()) - // Store SSAable and heap-escaped PPARAMOUT variables back to stack locations. - for i, f := range resultFields { - n := f.Nname.(*ir.Name) - s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem()) - if s.canSSA(n) { // result is in some SSA variable - results[i] = s.variable(n, n.Type()) - } else if !n.OnStack() { // result is actually heap allocated - ha := s.expr(n.Heapaddr) - s.instrumentFields(n.Type(), ha, instrumentRead) - results[i] = s.newValue2(ssa.OpDereference, n.Type(), ha, s.mem()) - } else { // result is not SSA-able; not escaped, so not on heap, but too large for SSA. - // Before register ABI this ought to be a self-move, home=dest, - // With register ABI, it's still a self-move if parameter is on stack (i.e., too big or overflowed) - results[i] = s.newValue2(ssa.OpDereference, n.Type(), s.addr(n), s.mem()) - } + resultFields := s.curfn.Type().Results().FieldSlice() + results := make([]*ssa.Value, len(resultFields)+1, len(resultFields)+1) + m = s.newValue0(ssa.OpMakeResult, s.f.OwnAux.LateExpansionResultType()) + // Store SSAable and heap-escaped PPARAMOUT variables back to stack locations. + for i, f := range resultFields { + n := f.Nname.(*ir.Name) + s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem()) + if s.canSSA(n) { // result is in some SSA variable + results[i] = s.variable(n, n.Type()) + } else if !n.OnStack() { // result is actually heap allocated + ha := s.expr(n.Heapaddr) + s.instrumentFields(n.Type(), ha, instrumentRead) + results[i] = s.newValue2(ssa.OpDereference, n.Type(), ha, s.mem()) + } else { // result is not SSA-able; not escaped, so not on heap, but too large for SSA. + // Before register ABI this ought to be a self-move, home=dest, + // With register ABI, it's still a self-move if parameter is on stack (i.e., too big or overflowed) + results[i] = s.newValue2(ssa.OpDereference, n.Type(), s.addr(n), s.mem()) } + } - // Run exit code. Today, this is just racefuncexit, in -race mode. - // TODO(register args) this seems risky here with a register-ABI, but not clear it is right to do it earlier either. - // Spills in register allocation might just fix it. - s.stmtList(s.curfn.Exit) - - results[len(results)-1] = s.mem() - m.AddArgs(results...) - } else { - // Store SSAable and heap-escaped PPARAMOUT variables back to stack locations. - for _, f := range s.curfn.Type().Results().FieldSlice() { - n := f.Nname.(*ir.Name) - if s.canSSA(n) { - val := s.variable(n, n.Type()) - s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem()) - s.store(n.Type(), s.decladdrs[n], val) - } else if !n.OnStack() { - s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem()) - s.move(n.Type(), s.decladdrs[n], s.expr(n.Heapaddr)) - } // else, on stack but too large to SSA, the result is already in its destination by construction, so no store needed. - - // TODO: if (SSA) val is ever spilled, we'd like to use the PPARAMOUT slot for spilling it. That won't happen currently. - } + // Run exit code. Today, this is just racefuncexit, in -race mode. + // TODO(register args) this seems risky here with a register-ABI, but not clear it is right to do it earlier either. + // Spills in register allocation might just fix it. + s.stmtList(s.curfn.Exit) - // Run exit code. Today, this is just racefuncexit, in -race mode. - s.stmtList(s.curfn.Exit) + results[len(results)-1] = s.mem() + m.AddArgs(results...) - // Do actual return. - m = s.mem() - } b = s.endBlock() b.Kind = ssa.BlockRet b.SetControl(m) -- GitLab From 86bbf4beee276b9a7f9a427a9d1a9277bd904709 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Fri, 12 Mar 2021 13:48:32 -0500 Subject: [PATCH 0316/1298] cmd/go: fix godoc formatting for text from 'go help install' Fixes #44846 Change-Id: I5a12c6437a91ce59307483ffcc70e084edc32197 Reviewed-on: https://go-review.googlesource.com/c/go/+/301329 Trust: Jay Conrod Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills Reviewed-by: Dmitri Shuralyov TryBot-Result: Go Bot --- src/cmd/go/alldocs.go | 20 ++++++++++++-------- src/cmd/go/internal/work/build.go | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index a125e94cea..9aac344a3f 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -684,18 +684,22 @@ // arguments must satisfy the following constraints: // // - Arguments must be package paths or package patterns (with "..." wildcards). -// They must not be standard packages (like fmt), meta-patterns (std, cmd, -// all), or relative or absolute file paths. +// They must not be standard packages (like fmt), meta-patterns (std, cmd, +// all), or relative or absolute file paths. +// // - All arguments must have the same version suffix. Different queries are not -// allowed, even if they refer to the same version. +// allowed, even if they refer to the same version. +// // - All arguments must refer to packages in the same module at the same version. +// // - No module is considered the "main" module. If the module containing -// packages named on the command line has a go.mod file, it must not contain -// directives (replace and exclude) that would cause it to be interpreted -// differently than if it were the main module. The module must not require -// a higher version of itself. +// packages named on the command line has a go.mod file, it must not contain +// directives (replace and exclude) that would cause it to be interpreted +// differently than if it were the main module. The module must not require +// a higher version of itself. +// // - Package path arguments must refer to main packages. Pattern arguments -// will only match main packages. +// will only match main packages. // // If the arguments don't have version suffixes, "go install" may run in // module-aware mode or GOPATH mode, depending on the GO111MODULE environment diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index a80eb27798..ad3a118510 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -482,18 +482,22 @@ To eliminate ambiguity about which module versions are used in the build, the arguments must satisfy the following constraints: - Arguments must be package paths or package patterns (with "..." wildcards). - They must not be standard packages (like fmt), meta-patterns (std, cmd, - all), or relative or absolute file paths. +They must not be standard packages (like fmt), meta-patterns (std, cmd, +all), or relative or absolute file paths. + - All arguments must have the same version suffix. Different queries are not - allowed, even if they refer to the same version. +allowed, even if they refer to the same version. + - All arguments must refer to packages in the same module at the same version. + - No module is considered the "main" module. If the module containing - packages named on the command line has a go.mod file, it must not contain - directives (replace and exclude) that would cause it to be interpreted - differently than if it were the main module. The module must not require - a higher version of itself. +packages named on the command line has a go.mod file, it must not contain +directives (replace and exclude) that would cause it to be interpreted +differently than if it were the main module. The module must not require +a higher version of itself. + - Package path arguments must refer to main packages. Pattern arguments - will only match main packages. +will only match main packages. If the arguments don't have version suffixes, "go install" may run in module-aware mode or GOPATH mode, depending on the GO111MODULE environment -- GitLab From 3eebc26700c8e9ccb7d9962ce1c7a02d605aba66 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 9 Mar 2021 23:27:11 -0500 Subject: [PATCH 0317/1298] delete favicon.ico and robots.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The favicon.ico and robots.txt files have been with us in the root directory since 2009 and 2011 respectively. Back then, the Go repo had content for the golang.org website, which could be run locally. Since these files were at the root of the website, they were added to the corresponding location in the GOROOT tree—at the root. In 2018, work started on factoring out golang.org website content and code into a new golang.org/x/website repository (issue 29206). The favicon.ico and robots.txt files were copied to x/website repo, but some more work needed to be done before they would be picked up and served when golangorg was executed in module mode. That work is done by now (CL 293413 and CL 293414). The scope of the godoc tool has also been reduced to just serving Go package documentation and not the website (issue 32011), so it can provide its own favicon.ico as needed (CL 300394). This means these two files have no more use and can be deleted. So long and goodbye! Change-Id: Id71bdab6317c1dc481c9d85beaaac4b4eb92d379 Reviewed-on: https://go-review.googlesource.com/c/go/+/300549 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Russ Cox --- favicon.ico | Bin 5686 -> 0 bytes robots.txt | 2 -- 2 files changed, 2 deletions(-) delete mode 100644 favicon.ico delete mode 100644 robots.txt diff --git a/favicon.ico b/favicon.ico deleted file mode 100644 index 8d225846dbcda496ba803b828c4786b21cc84d01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5686 zcmZQzU}RuoP*4ET3Jfa*7#P$T7#IWuKzt5{3|0n)a{>$u8Vn2!3JeSk4h$f15Q_mX z2=TM{55oT*mi?zC2H63^=#Bx2fiNxY2AK`A1B6HIM-2f`n1C=SjA)5Lc7QOd?FhWfAX9S|EEo^ z`oCd*Ji%}P*$u+v*#F~B<^QtY1OH2U4r9eN{oAQ)|D)>v|K4r<|Nr~V|NnnJ{{R2$ z`Tq-6ZUx&NoYeZ?*wXXAsg2M7$gBxqu?<@`{r~^z@c;jxPyYY+ZvFp%kLxkq1M)iv z6ZHR+mjC~Mz4(s~{{8>||IDeq|K$~w;aFWm>;K(**U^>!|Nr;P|9>xLptu2KHwY85 z|NoDBnC2mgESO&Q-^bnLf1tPN|IKS>A<3XI|9=1f?@24%4IsNg7>oU%LE=B|l>Gnq zVk(*;|Nnpc_U(UsV)B0tExrHMwe|o1{eJ)d-^23%|DI38PXU%>HlQ zvi1M}j|ai_gUklm5#nd@8H@e5Kyt4ys_$@uP)?++ql7g7B|uD5A`=+53>K%*5v>H-fuxO@&Es6(`LZU z1i9nDfrJ15J#EKozkfh5T&o^I(mlxH*5gq zi9=xfZyd<@UyI`hf6H``8$x_6ox=kx|6SUh_W$jrg8zT+m;L|ypzQzu9}h6h zMHT?X5v-g8=TBrwWcJ@5ka&XjE56?@{=aBq2*?fpL;WqnL;WmvHf- z|8x6-{(rkw{QvJ`Q2u*`Y!ZU~zXxUiukB0!Kch47 z|Hk=||G(ZWhS=|CaUsOt;z4$j!~b9RO8)=6TM7;*P&`d)_WS?!b|oY&e82nu|IerY z|9`#o|KFtEu0wg|K<6-{~*7E!ua;# zOtAeSeimOt{mc)7(p_DV`~OV~qW|~Q`NHJ>XT;n8Kd>hL|4&e!g!z?78kE;Sdeh_W z!REz=TK``>DfIuUnc@FaW9`6V!M+yPK=B{qXYmK*1{CaX@fgOB54Zk5sm1^QmW9#( zuk20#|NLz3|Bu%S!C?jpHxL^n29g7*0jUM)f$0zRv%CXiBhmjr@efXe{${oz{+2sK z{4DN;`dOR`^|Q!iU|?Vh_O*-*_OrN;qzCM7V)?;-7I%VuEy6%u;1EBH=ny}P!%*`M zg!o!`g6t-QLqkKEgZ#`LL;Ni!h4@?S0l6{6&*B{v!`$-`%6|+|W8NR)Z)V%jz`#Vv z{DGD~z`(#vE8GAYdcfjAkobQF25^1`jZ+9f$0`^ZIIyUO2nh;{Gsr6_GwA84GlcsY zg8GXLrK#o&6&WTB)x~}ct0s9cES(g>P||al;ly%3hQ6807?v&WWH_<8h~dztDu(mB zD;ZAh?`Jr3a2mtst0fHo@0K(CzYoF{4F4aNGW>r~$?)%C8N>63ml(c&`_1tE*MElJ zfBrN4{`Vi`P>3T&$;=d>q^?3M}j#+}t292?=ttvnYT7J3BKA3o|=Ah>eaL7#SFd#jpqhssF$aDrgxP E0E9iN`2YX_ diff --git a/robots.txt b/robots.txt deleted file mode 100644 index 1f53798bb4..0000000000 --- a/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / -- GitLab From 7b47f9a5f2092dcbc1546304f1f1b739883fa4c4 Mon Sep 17 00:00:00 2001 From: Michael Schaller Date: Fri, 12 Mar 2021 12:12:48 +0000 Subject: [PATCH 0318/1298] cmd/compile: mention that -m can be increased or given multiple times -m can be increased or it can be given up to 4 times to increase the verbosity of the printed optimization decisions: https://github.com/golang/go/search?q=LowerM Change-Id: I0cc304385be052664fad455ff075846a3a63f298 GitHub-Last-Rev: 140f08529024dd17c5ca1cbad52dd1d17c6126c0 GitHub-Pull-Request: golang/go#44857 Reviewed-on: https://go-review.googlesource.com/c/go/+/299709 Reviewed-by: Keith Randall Reviewed-by: Robert Griesemer --- src/cmd/compile/doc.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index 46d4722086..b68ef274f3 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -83,7 +83,8 @@ Flags: Without this flag, the -o output is a combination of both linker and compiler input. -m - Print optimization decisions. + Print optimization decisions. Higher values or repetition + produce more detail. -memprofile file Write memory profile for the compilation to file. -memprofilerate rate -- GitLab From 16ad1ea8417bb842204bf7c982e3f19969b67458 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 11 Mar 2021 16:34:01 -0800 Subject: [PATCH 0319/1298] cmd/compile/internal/types2: simplify error reporting API (cleanup) - Remove specialized errorf functions for invalid AST/argument/operation. Instead use prefix constants with the error message. - Replace several calls to Checker.errorf with calls to Checker.error if there are no arguments to format. - Replace a handful of %s format verbs with %v to satisfy vet check. - Add a basic test that checks that we're not using Checker.errorf when we should be using Checker.error. Change-Id: I7bc7c14f3cf774689ec8cd5782ea31b6e30dbcd6 Reviewed-on: https://go-review.googlesource.com/c/go/+/300995 Trust: Robert Griesemer Reviewed-by: Robert Findley --- .../compile/internal/types2/assignments.go | 2 +- src/cmd/compile/internal/types2/builtins.go | 44 ++++++------ src/cmd/compile/internal/types2/call.go | 4 +- src/cmd/compile/internal/types2/check.go | 2 +- src/cmd/compile/internal/types2/decl.go | 6 +- .../internal/types2/errorcalls_test.go | 49 +++++++++++++ src/cmd/compile/internal/types2/errors.go | 28 ++++---- src/cmd/compile/internal/types2/expr.go | 68 +++++++++---------- src/cmd/compile/internal/types2/labels.go | 2 +- src/cmd/compile/internal/types2/resolver.go | 16 ++--- src/cmd/compile/internal/types2/stmt.go | 16 ++--- src/cmd/compile/internal/types2/typexpr.go | 34 +++++----- src/cmd/compile/internal/types2/version.go | 8 +-- 13 files changed, 162 insertions(+), 117 deletions(-) create mode 100644 src/cmd/compile/internal/types2/errorcalls_test.go diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index 00495f3976..18ae0ddf62 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -194,7 +194,7 @@ func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type { case variable, mapindex: // ok case nilvalue: - check.errorf(&z, "cannot assign to nil") // default would print "untyped nil" + check.error(&z, "cannot assign to nil") // default would print "untyped nil" return nil default: if sel, ok := z.expr.(*syntax.SelectorExpr); ok { diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index a6a9b51dd1..55a9d69b30 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -21,8 +21,8 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // append is the only built-in that permits the use of ... for the last argument bin := predeclaredFuncs[id] if call.HasDots && id != _Append { - //check.invalidOpf(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) - check.invalidOpf(call, "invalid use of ... with built-in %s", bin.name) + //check.errorf(call.Ellipsis, invalidOp + "invalid use of ... with built-in %s", bin.name) + check.errorf(call, invalidOp+"invalid use of ... with built-in %s", bin.name) check.use(call.ArgList...) return } @@ -68,7 +68,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( msg = "too many" } if msg != "" { - check.invalidOpf(call, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs) + check.errorf(call, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs) return } } @@ -85,7 +85,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( if s := asSlice(S); s != nil { T = s.elem } else { - check.invalidArgf(x, "%s is not a slice", x) + check.errorf(x, invalidArg+"%s is not a slice", x) return } @@ -197,7 +197,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } if mode == invalid && typ != Typ[Invalid] { - check.invalidArgf(x, "%s for %s", x, bin.name) + check.errorf(x, invalidArg+"%s for %s", x, bin.name) return } @@ -212,11 +212,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // close(c) c := asChan(x.typ) if c == nil { - check.invalidArgf(x, "%s is not a channel", x) + check.errorf(x, invalidArg+"%s is not a channel", x) return } if c.dir == RecvOnly { - check.invalidArgf(x, "%s must not be a receive-only channel", x) + check.errorf(x, invalidArg+"%s must not be a receive-only channel", x) return } @@ -280,7 +280,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // both argument types must be identical if !check.identical(x.typ, y.typ) { - check.invalidOpf(x, "%s (mismatched types %s and %s)", call, x.typ, y.typ) + check.errorf(x, invalidOp+"%v (mismatched types %s and %s)", call, x.typ, y.typ) return } @@ -300,7 +300,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } resTyp := check.applyTypeFunc(f, x.typ) if resTyp == nil { - check.invalidArgf(x, "arguments have type %s, expected floating-point", x.typ) + check.errorf(x, invalidArg+"arguments have type %s, expected floating-point", x.typ) return } @@ -340,12 +340,12 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } if dst == nil || src == nil { - check.invalidArgf(x, "copy expects slice arguments; found %s and %s", x, &y) + check.errorf(x, invalidArg+"copy expects slice arguments; found %s and %s", x, &y) return } if !check.identical(dst, src) { - check.invalidArgf(x, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) + check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) return } @@ -359,7 +359,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // delete(m, k) m := asMap(x.typ) if m == nil { - check.invalidArgf(x, "%s is not a map", x) + check.errorf(x, invalidArg+"%s is not a map", x) return } arg(x, 1) // k @@ -418,7 +418,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } resTyp := check.applyTypeFunc(f, x.typ) if resTyp == nil { - check.invalidArgf(x, "argument has type %s, expected complex type", x.typ) + check.errorf(x, invalidArg+"argument has type %s, expected complex type", x.typ) return } @@ -473,7 +473,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } if !valid(T) { - check.invalidArgf(arg0, "cannot make %s; type must be slice, map, or channel", arg0) + check.errorf(arg0, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0) return } if nargs < min || max < nargs { @@ -495,7 +495,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } } if len(sizes) == 2 && sizes[0] > sizes[1] { - check.invalidArgf(call.ArgList[1], "length and capacity swapped") + check.error(call.ArgList[1], invalidArg+"length and capacity swapped") // safe to continue } x.mode = value @@ -578,7 +578,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Alignof: // unsafe.Alignof(x T) uintptr if asTypeParam(x.typ) != nil { - check.invalidOpf(call, "unsafe.Alignof undefined for %s", x) + check.errorf(call, invalidOp+"unsafe.Alignof undefined for %s", x) return } check.assignment(x, nil, "argument to unsafe.Alignof") @@ -597,7 +597,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( arg0 := call.ArgList[0] selx, _ := unparen(arg0).(*syntax.SelectorExpr) if selx == nil { - check.invalidArgf(arg0, "%s is not a selector expression", arg0) + check.errorf(arg0, invalidArg+"%s is not a selector expression", arg0) check.use(arg0) return } @@ -612,18 +612,18 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel) switch obj.(type) { case nil: - check.invalidArgf(x, "%s has no single field %s", base, sel) + check.errorf(x, invalidArg+"%s has no single field %s", base, sel) return case *Func: // TODO(gri) Using derefStructPtr may result in methods being found // that don't actually exist. An error either way, but the error // message is confusing. See: https://play.golang.org/p/al75v23kUy , // but go/types reports: "invalid argument: x.m is a method value". - check.invalidArgf(arg0, "%s is a method value", arg0) + check.errorf(arg0, invalidArg+"%s is a method value", arg0) return } if indirect { - check.invalidArgf(x, "field %s is embedded via a pointer in %s", sel, base) + check.errorf(x, invalidArg+"field %s is embedded via a pointer in %s", sel, base) return } @@ -639,7 +639,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Sizeof: // unsafe.Sizeof(x T) uintptr if asTypeParam(x.typ) != nil { - check.invalidOpf(call, "unsafe.Sizeof undefined for %s", x) + check.errorf(call, invalidOp+"unsafe.Sizeof undefined for %s", x) return } check.assignment(x, nil, "argument to unsafe.Sizeof") @@ -657,7 +657,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // The result of assert is the value of pred if there is no error. // Note: assert is only available in self-test mode. if x.mode != constant_ || !isBoolean(x.typ) { - check.invalidArgf(x, "%s is not a boolean constant", x) + check.errorf(x, invalidArg+"%s is not a boolean constant", x) return } if x.val.Kind() != constant.Bool { diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 320e12d4d6..93f4c51937 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -158,7 +158,7 @@ func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind { sig := asSignature(x.typ) if sig == nil { - check.invalidOpf(x, "cannot call non-function %s", x) + check.errorf(x, invalidOp+"cannot call non-function %s", x) x.mode = invalid x.expr = call return statement @@ -248,7 +248,7 @@ func (check *Checker) exprOrTypeList(elist []syntax.Expr) (xlist []*operand, ok } } if 0 < ntypes && ntypes < len(xlist) { - check.errorf(xlist[0], "mix of value and type expressions") + check.error(xlist[0], "mix of value and type expressions") ok = false } } diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index c853925a2a..7c1d4eae56 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -214,7 +214,7 @@ func (check *Checker) initFiles(files []*syntax.File) { if name != "_" { pkg.name = name } else { - check.errorf(file.PkgName, "invalid package name _") + check.error(file.PkgName, "invalid package name _") } fallthrough diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 3528669bf9..07a22e8aad 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -629,14 +629,14 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named if alias && tdecl.TParamList != nil { // The parser will ensure this but we may still get an invalid AST. // Complain and continue as regular type definition. - check.errorf(tdecl, "generic type cannot be alias") + check.error(tdecl, "generic type cannot be alias") alias = false } if alias { // type alias declaration if !check.allowVersion(obj.pkg, 1, 9) { - check.errorf(tdecl, "type aliases requires go1.9 or later") + check.error(tdecl, "type aliases requires go1.9 or later") } obj.typ = Typ[Invalid] @@ -978,7 +978,7 @@ func (check *Checker) declStmt(list []syntax.Decl) { check.pop().setColor(black) default: - check.invalidASTf(s, "unknown syntax.Decl node %T", s) + check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s) } } } diff --git a/src/cmd/compile/internal/types2/errorcalls_test.go b/src/cmd/compile/internal/types2/errorcalls_test.go new file mode 100644 index 0000000000..28bb33aaff --- /dev/null +++ b/src/cmd/compile/internal/types2/errorcalls_test.go @@ -0,0 +1,49 @@ +// Copyright 2021 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 ast. + +package types2_test + +import ( + "cmd/compile/internal/syntax" + "testing" +) + +// TestErrorCalls makes sure that check.errorf calls have at +// least 3 arguments (otherwise we should be using check.error). +func TestErrorCalls(t *testing.T) { + files, err := pkgFiles(".") + if err != nil { + t.Fatal(err) + } + + for _, file := range files { + syntax.Walk(file, func(n syntax.Node) bool { + call, _ := n.(*syntax.CallExpr) + if call == nil { + return false + } + selx, _ := call.Fun.(*syntax.SelectorExpr) + if selx == nil { + return false + } + if !(isName(selx.X, "check") && isName(selx.Sel, "errorf")) { + return false + } + // check.errorf calls should have more than 2 arguments: + // position, format string, and arguments to format + if n := len(call.ArgList); n <= 2 { + t.Errorf("%s: got %d arguments, want > 2", call.Pos(), n) + return true + } + return false + }) + } +} + +func isName(n syntax.Node, name string) bool { + if n, ok := n.(*syntax.Name); ok { + return n.Value == name + } + return false +} diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go index 01df50c8e3..79fedc91e1 100644 --- a/src/cmd/compile/internal/types2/errors.go +++ b/src/cmd/compile/internal/types2/errors.go @@ -142,7 +142,7 @@ func (check *Checker) dump(format string, args ...interface{}) { fmt.Println(check.sprintf(format, args...)) } -func (check *Checker) err(pos syntax.Pos, msg string, soft bool) { +func (check *Checker) err(at poser, msg string, soft bool) { // Cheap trick: Don't report errors with messages containing // "invalid operand" or "invalid type" as those tend to be // follow-on errors which don't add useful information. Only @@ -152,6 +152,8 @@ func (check *Checker) err(pos syntax.Pos, msg string, soft bool) { return } + pos := posFor(at) + // If we are encountering an error while evaluating an inherited // constant initialization expression, pos is the position of in // the original expression, and not of the currently declared @@ -179,32 +181,26 @@ func (check *Checker) err(pos syntax.Pos, msg string, soft bool) { f(err) } +const ( + invalidAST = "invalid AST: " + invalidArg = "invalid argument: " + invalidOp = "invalid operation: " +) + type poser interface { Pos() syntax.Pos } func (check *Checker) error(at poser, msg string) { - check.err(posFor(at), msg, false) + check.err(at, msg, false) } func (check *Checker) errorf(at poser, format string, args ...interface{}) { - check.err(posFor(at), check.sprintf(format, args...), false) + check.err(at, check.sprintf(format, args...), false) } func (check *Checker) softErrorf(at poser, format string, args ...interface{}) { - check.err(posFor(at), check.sprintf(format, args...), true) -} - -func (check *Checker) invalidASTf(at poser, format string, args ...interface{}) { - check.errorf(at, "invalid AST: "+format, args...) -} - -func (check *Checker) invalidArgf(at poser, format string, args ...interface{}) { - check.errorf(at, "invalid argument: "+format, args...) -} - -func (check *Checker) invalidOpf(at poser, format string, args ...interface{}) { - check.errorf(at, "invalid operation: "+format, args...) + check.err(at, check.sprintf(format, args...), true) } // posFor reports the left (= start) position of at. diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 584b8ee6a0..b89eb199eb 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -75,14 +75,14 @@ func (check *Checker) op(m opPredicates, x *operand, op syntax.Operator) bool { if pred := m[op]; pred != nil { if !pred(x.typ) { if check.conf.CompilerErrorMessages { - check.invalidOpf(x, "operator %s not defined on %s", op, x) + check.errorf(x, invalidOp+"operator %s not defined on %s", op, x) } else { - check.invalidOpf(x, "operator %s not defined for %s", op, x) + check.errorf(x, invalidOp+"operator %s not defined for %s", op, x) } return false } } else { - check.invalidASTf(x, "unknown operator %s", op) + check.errorf(x, invalidAST+"unknown operator %s", op) return false } return true @@ -108,7 +108,7 @@ func (check *Checker) overflow(x *operand) { // TODO(gri) We should report exactly what went wrong. At the // moment we don't have the (go/constant) API for that. // See also TODO in go/constant/value.go. - check.errorf(pos, "constant result is not representable") + check.error(pos, "constant result is not representable") return } @@ -169,7 +169,7 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) { // spec: "As an exception to the addressability // requirement x may also be a composite literal." if _, ok := unparen(e.X).(*syntax.CompositeLit); !ok && x.mode != variable { - check.invalidOpf(x, "cannot take address of %s", x) + check.errorf(x, invalidOp+"cannot take address of %s", x) x.mode = invalid return } @@ -180,12 +180,12 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) { case syntax.Recv: typ := asChan(x.typ) if typ == nil { - check.invalidOpf(x, "cannot receive from non-channel %s", x) + check.errorf(x, invalidOp+"cannot receive from non-channel %s", x) x.mode = invalid return } if typ.dir == SendOnly { - check.invalidOpf(x, "cannot receive from send-only channel %s", x) + check.errorf(x, invalidOp+"cannot receive from send-only channel %s", x) x.mode = invalid return } @@ -562,7 +562,7 @@ func (check *Checker) updateExprType(x syntax.Expr, typ Type, final bool) { // We already know from the shift check that it is representable // as an integer if it is a constant. if !isInteger(typ) { - check.invalidOpf(x, "shifted operand %s (type %s) must be integer", x, typ) + check.errorf(x, invalidOp+"shifted operand %s (type %s) must be integer", x, typ) return } // Even if we have an integer, if the value is a constant we @@ -753,7 +753,7 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) { if err != "" { // TODO(gri) better error message for cases where one can only compare against nil - check.invalidOpf(x, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err) + check.errorf(x, invalidOp+"cannot compare %s %s %s (%s)", x.expr, op, y.expr, err) x.mode = invalid return } @@ -791,7 +791,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { // as an integer. Nothing to do. } else { // shift has no chance - check.invalidOpf(x, "shifted operand %s must be integer", x) + check.errorf(x, invalidOp+"shifted operand %s must be integer", x) x.mode = invalid return } @@ -803,7 +803,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { if y.mode == constant_ { yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1 if yval.Kind() == constant.Int && constant.Sign(yval) < 0 { - check.invalidOpf(y, "negative shift count %s", y) + check.errorf(y, invalidOp+"negative shift count %s", y) x.mode = invalid return } @@ -818,11 +818,11 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { return } } else if !isInteger(y.typ) { - check.invalidOpf(y, "shift count %s must be integer", y) + check.errorf(y, invalidOp+"shift count %s must be integer", y) x.mode = invalid return } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) { - check.invalidOpf(y, "signed shift count %s requires go1.13 or later", y) + check.errorf(y, invalidOp+"signed shift count %s requires go1.13 or later", y) x.mode = invalid return } @@ -842,7 +842,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64 (see issue #44057) s, ok := constant.Uint64Val(y.val) if !ok || s > shiftBound { - check.invalidOpf(y, "invalid shift count %s", y) + check.errorf(y, invalidOp+"invalid shift count %s", y) x.mode = invalid return } @@ -893,7 +893,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { // non-constant shift - lhs must be an integer if !isInteger(x.typ) { - check.invalidOpf(x, "shifted operand %s must be integer", x) + check.errorf(x, invalidOp+"shifted operand %s must be integer", x) x.mode = invalid return } @@ -963,7 +963,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op // only report an error if we have valid types // (otherwise we had an error reported elsewhere already) if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] { - check.invalidOpf(x, "mismatched types %s and %s", x.typ, y.typ) + check.errorf(x, invalidOp+"mismatched types %s and %s", x.typ, y.typ) } x.mode = invalid return @@ -977,7 +977,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op if op == syntax.Div || op == syntax.Rem { // check for zero divisor if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 { - check.invalidOpf(&y, "division by zero") + check.error(&y, invalidOp+"division by zero") x.mode = invalid return } @@ -987,7 +987,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op re, im := constant.Real(y.val), constant.Imag(y.val) re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im) if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 { - check.invalidOpf(&y, "division by zero") + check.error(&y, invalidOp+"division by zero") x.mode = invalid return } @@ -1038,7 +1038,7 @@ func (check *Checker) index(index syntax.Expr, max int64) (typ Type, val int64) // the index must be of integer type if !isInteger(x.typ) { - check.invalidArgf(&x, "index %s must be integer", &x) + check.errorf(&x, invalidArg+"index %s must be integer", &x) return } @@ -1048,7 +1048,7 @@ func (check *Checker) index(index syntax.Expr, max int64) (typ Type, val int64) // a constant index i must be in bounds if constant.Sign(x.val) < 0 { - check.invalidArgf(&x, "index %s must not be negative", &x) + check.errorf(&x, invalidArg+"index %s must not be negative", &x) return } @@ -1242,7 +1242,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin x.mode = value x.typ = sig } else { - check.invalidASTf(e, "invalid function literal %s", e) + check.errorf(e, invalidAST+"invalid function literal %v", e) goto Error } @@ -1608,23 +1608,23 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin } if !valid { - check.invalidOpf(x, "cannot index %s", x) + check.errorf(x, invalidOp+"cannot index %s", x) goto Error } if e.Index == nil { - check.invalidASTf(e, "missing index for %s", x) + check.errorf(e, invalidAST+"missing index for %s", x) goto Error } index := e.Index if l, _ := index.(*syntax.ListExpr); l != nil { if n := len(l.ElemList); n <= 1 { - check.invalidASTf(e, "invalid use of ListExpr for index expression %s with %d indices", e, n) + check.errorf(e, invalidAST+"invalid use of ListExpr for index expression %v with %d indices", e, n) goto Error } // len(l.ElemList) > 1 - check.invalidOpf(l.ElemList[1], "more than one index") + check.error(l.ElemList[1], invalidOp+"more than one index") index = l.ElemList[0] // continue with first index } @@ -1651,7 +1651,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case *Basic: if isString(typ) { if e.Full { - check.invalidOpf(x, "3-index slice of string") + check.error(x, invalidOp+"3-index slice of string") goto Error } valid = true @@ -1669,7 +1669,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin valid = true length = typ.len if x.mode != variable { - check.invalidOpf(x, "%s (slice of unaddressable value)", x) + check.errorf(x, invalidOp+"%s (slice of unaddressable value)", x) goto Error } x.typ = &Slice{elem: typ.elem} @@ -1686,12 +1686,12 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin // x.typ doesn't change case *Sum, *TypeParam: - check.errorf(x, "generic slice expressions not yet implemented") + check.error(x, "generic slice expressions not yet implemented") goto Error } if !valid { - check.invalidOpf(x, "cannot slice %s", x) + check.errorf(x, invalidOp+"cannot slice %s", x) goto Error } @@ -1699,7 +1699,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin // spec: "Only the first index may be omitted; it defaults to 0." if e.Full && (e.Index[1] == nil || e.Index[2] == nil) { - check.invalidASTf(e, "2nd and 3rd index required in 3-index slice") + check.error(e, invalidAST+"2nd and 3rd index required in 3-index slice") goto Error } @@ -1756,7 +1756,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin check.ordinaryType(x.Pos(), xtyp) // x.(type) expressions are encoded via TypeSwitchGuards if e.Type == nil { - check.invalidASTf(e, "invalid use of AssertExpr") + check.error(e, invalidAST+"invalid use of AssertExpr") goto Error } T := check.varType(e.Type) @@ -1769,7 +1769,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case *syntax.TypeSwitchGuard: // x.(type) expressions are handled explicitly in type switches - check.invalidASTf(e, "use of .(type) outside type switch") + check.error(e, invalidAST+"use of .(type) outside type switch") goto Error case *syntax.CallExpr: @@ -1811,7 +1811,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin x.mode = variable x.typ = typ.base } else { - check.invalidOpf(x, "cannot indirect %s", x) + check.errorf(x, invalidOp+"cannot indirect %s", x) goto Error } } @@ -1837,7 +1837,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case *syntax.KeyValueExpr: // key:value expressions are handled in composite literals - check.invalidASTf(e, "no key:value expected") + check.error(e, invalidAST+"no key:value expected") goto Error case *syntax.ArrayType, *syntax.SliceType, *syntax.StructType, *syntax.FuncType, diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go index cbbd65aa9a..d5878692f5 100644 --- a/src/cmd/compile/internal/types2/labels.go +++ b/src/cmd/compile/internal/types2/labels.go @@ -212,7 +212,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab } default: - check.invalidASTf(s, "branch statement: %s %s", s.Tok, name) + check.errorf(s, invalidAST+"branch statement: %s %s", s.Tok, name) return } diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index fe551525c6..79938964c1 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -92,14 +92,14 @@ func (check *Checker) declarePkgObj(ident *syntax.Name, obj Object, d *declInfo) // spec: "A package-scope or file-scope identifier with name init // may only be declared to be a function with this (func()) signature." if ident.Value == "init" { - check.errorf(ident, "cannot declare init - must be func") + check.error(ident, "cannot declare init - must be func") return } // spec: "The main package must have package name main and declare // a function main that takes no arguments and returns no value." if ident.Value == "main" && check.pkg.name == "main" { - check.errorf(ident, "cannot declare main - must be func") + check.error(ident, "cannot declare main - must be func") return } @@ -256,13 +256,13 @@ func (check *Checker) collectObjects() { name = s.LocalPkgName.Value if path == "C" { // match cmd/compile (not prescribed by spec) - check.errorf(s.LocalPkgName, `cannot rename import "C"`) + check.error(s.LocalPkgName, `cannot rename import "C"`) continue } } if name == "init" { - check.errorf(s.LocalPkgName, "cannot import package as init - init must be a func") + check.error(s.LocalPkgName, "cannot import package as init - init must be a func") continue } @@ -428,8 +428,8 @@ func (check *Checker) collectObjects() { // method // d.Recv != nil if !methodTypeParamsOk && len(d.TParamList) != 0 { - //check.invalidASTf(d.TParamList.Pos(), "method must have no type parameters") - check.invalidASTf(d, "method must have no type parameters") + //check.error(d.TParamList.Pos(), invalidAST + "method must have no type parameters") + check.error(d, invalidAST+"method must have no type parameters") } ptr, recv, _ := check.unpackRecv(d.Recv.Type, false) // (Methods with invalid receiver cannot be associated to a type, and @@ -449,7 +449,7 @@ func (check *Checker) collectObjects() { obj.setOrder(uint32(len(check.objMap))) default: - check.invalidASTf(s, "unknown syntax.Decl node %T", s) + check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s) } } } @@ -530,7 +530,7 @@ L: // unpack receiver type case *syntax.BadExpr: // ignore - error already reported by parser case nil: - check.invalidASTf(ptyp, "parameterized receiver contains nil parameters") + check.error(ptyp, invalidAST+"parameterized receiver contains nil parameters") default: check.errorf(arg, "receiver type parameter %s must be an identifier", arg) } diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 21244f6065..bf3c9dfa5f 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -357,12 +357,12 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { tch := asChan(ch.typ) if tch == nil { - check.invalidOpf(s, "cannot send to non-chan type %s", ch.typ) + check.errorf(s, invalidOp+"cannot send to non-chan type %s", ch.typ) return } if tch.dir == RecvOnly { - check.invalidOpf(s, "cannot send to receive-only type %s", tch) + check.errorf(s, invalidOp+"cannot send to receive-only type %s", tch) return } @@ -373,7 +373,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { if s.Rhs == nil { // x++ or x-- if len(lhs) != 1 { - check.invalidASTf(s, "%s%s requires one operand", s.Op, s.Op) + check.errorf(s, invalidAST+"%s%s requires one operand", s.Op, s.Op) return } var x operand @@ -382,7 +382,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { return } if !isNumeric(x.typ) { - check.invalidOpf(lhs[0], "%s%s%s (non-numeric type %s)", lhs[0], s.Op, s.Op, x.typ) + check.errorf(lhs[0], invalidOp+"%s%s%s (non-numeric type %s)", lhs[0], s.Op, s.Op, x.typ) return } check.assignVar(lhs[0], &x) @@ -484,7 +484,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // goto's must have labels, should have been caught above fallthrough default: - check.invalidASTf(s, "branch statement: %s", s.Tok) + check.errorf(s, invalidAST+"branch statement: %s", s.Tok) } case *syntax.BlockStmt: @@ -642,7 +642,7 @@ func (check *Checker) switchStmt(inner stmtContext, s *syntax.SwitchStmt) { seen := make(valueMap) // map of seen case values to positions and types for i, clause := range s.Body { if clause == nil { - check.invalidASTf(clause, "incorrect expression switch case") + check.error(clause, invalidAST+"incorrect expression switch case") continue } end := s.Rbrace @@ -699,7 +699,7 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu seen := make(map[Type]syntax.Pos) // map of seen types to positions for i, clause := range s.Body { if clause == nil { - check.invalidASTf(s, "incorrect type switch case") + check.error(s, invalidAST+"incorrect type switch case") continue } end := s.Rbrace @@ -765,7 +765,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s var sValue syntax.Expr if p, _ := sKey.(*syntax.ListExpr); p != nil { if len(p.ElemList) != 2 { - check.invalidASTf(s, "invalid lhs in range clause") + check.error(s, invalidAST+"invalid lhs in range clause") return } sKey = p.ElemList[0] diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 14bc91785e..7675ce6376 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -29,7 +29,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo scope, obj := check.scope.LookupParent(e.Value, check.pos) if obj == nil { if e.Value == "_" { - check.errorf(e, "cannot use _ as value or type") + check.error(e, "cannot use _ as value or type") } else { if check.conf.CompilerErrorMessages { check.errorf(e, "undefined: %s", e.Value) @@ -76,7 +76,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo } if obj == universeIota { if check.iota == nil { - check.errorf(e, "cannot use iota outside constant declaration") + check.error(e, "cannot use iota outside constant declaration") return } x.val = check.iota @@ -337,7 +337,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // (A separate check is needed when type-checking interface method signatures because // they don't have a receiver specification.) if recvPar != nil && !check.conf.AcceptMethodTypeParams { - check.errorf(ftyp, "methods cannot have type parameters") + check.error(ftyp, "methods cannot have type parameters") } } @@ -511,7 +511,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { typ.len = check.arrayLength(e.Len) } else { // [...]array - check.errorf(e, "invalid use of [...] array (outside a composite literal)") + check.error(e, "invalid use of [...] array (outside a composite literal)") typ.len = -1 } typ.elem = check.varType(e.Elem) @@ -599,7 +599,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { case syntax.RecvOnly: dir = RecvOnly default: - check.invalidASTf(e, "unknown channel direction %d", e.Dir) + check.errorf(e, invalidAST+"unknown channel direction %d", e.Dir) // ok to continue } @@ -763,7 +763,7 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy // named parameter name := field.Name.Value if name == "" { - check.invalidASTf(field.Name, "anonymous parameter") + check.error(field.Name, invalidAST+"anonymous parameter") // ok to continue } par := NewParam(field.Name.Pos(), check.pkg, name, typ) @@ -780,7 +780,7 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy } if named && anonymous { - check.invalidASTf(list[0], "list contains both named and anonymous parameters") + check.error(list[0], invalidAST+"list contains both named and anonymous parameters") // ok to continue } @@ -817,9 +817,9 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType name := f.Name.Value if name == "_" { if check.conf.CompilerErrorMessages { - check.errorf(f.Name, "methods must have a unique non-blank name") + check.error(f.Name, "methods must have a unique non-blank name") } else { - check.errorf(f.Name, "invalid method name _") + check.error(f.Name, "invalid method name _") } continue // ignore } @@ -830,7 +830,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // the author intended to include all types. types = append(types, f.Type) if tname != nil && tname != f.Name { - check.errorf(f.Name, "cannot have multiple type lists in an interface") + check.error(f.Name, "cannot have multiple type lists in an interface") } tname = f.Name continue @@ -840,7 +840,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType sig, _ := typ.(*Signature) if sig == nil { if typ != Typ[Invalid] { - check.invalidASTf(f.Type, "%s is not a method signature", typ) + check.errorf(f.Type, invalidAST+"%s is not a method signature", typ) } continue // ignore } @@ -849,7 +849,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // (This extra check is needed here because interface method signatures don't have // a receiver specification.) if sig.tparams != nil && !check.conf.AcceptMethodTypeParams { - check.errorf(f.Type, "methods cannot have type parameters") + check.error(f.Type, "methods cannot have type parameters") } // use named receiver type if available (for better error messages) @@ -1087,7 +1087,7 @@ func (check *Checker) tag(t *syntax.BasicLit) string { return val } } - check.invalidASTf(t, "incorrect tag syntax: %q", t.Value) + check.errorf(t, invalidAST+"incorrect tag syntax: %q", t.Value) } return "" } @@ -1180,13 +1180,13 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) { } // unsafe.Pointer is treated like a regular pointer if t.kind == UnsafePointer { - check.errorf(embeddedPos, "embedded field type cannot be unsafe.Pointer") + check.error(embeddedPos, "embedded field type cannot be unsafe.Pointer") } case *Pointer: - check.errorf(embeddedPos, "embedded field type cannot be a pointer") + check.error(embeddedPos, "embedded field type cannot be a pointer") case *Interface: if isPtr { - check.errorf(embeddedPos, "embedded field type cannot be a pointer to an interface") + check.error(embeddedPos, "embedded field type cannot be a pointer to an interface") } } }) @@ -1220,7 +1220,7 @@ func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr list := make([]Type, 0, len(types)) // assume all types are correct for _, texpr := range types { if texpr == nil { - check.invalidASTf(pos, "missing type constraint") + check.error(pos, invalidAST+"missing type constraint") continue } list = append(list, check.varType(texpr)) diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go index cb497f048e..d9d18b6f7a 100644 --- a/src/cmd/compile/internal/types2/version.go +++ b/src/cmd/compile/internal/types2/version.go @@ -21,7 +21,7 @@ func (check *Checker) langCompat(lit *syntax.BasicLit) { } // len(s) > 2 if strings.Contains(s, "_") { - check.errorf(lit, "underscores in numeric literals requires go1.13 or later") + check.error(lit, "underscores in numeric literals requires go1.13 or later") return } if s[0] != '0' { @@ -29,15 +29,15 @@ func (check *Checker) langCompat(lit *syntax.BasicLit) { } radix := s[1] if radix == 'b' || radix == 'B' { - check.errorf(lit, "binary literals requires go1.13 or later") + check.error(lit, "binary literals requires go1.13 or later") return } if radix == 'o' || radix == 'O' { - check.errorf(lit, "0o/0O-style octal literals requires go1.13 or later") + check.error(lit, "0o/0O-style octal literals requires go1.13 or later") return } if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') { - check.errorf(lit, "hexadecimal floating-point literals requires go1.13 or later") + check.error(lit, "hexadecimal floating-point literals requires go1.13 or later") } } -- GitLab From 7588ef0d9020c8e628adcd0a0046231252f0d90d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 11 Mar 2021 18:10:08 -0800 Subject: [PATCH 0320/1298] cmd/compile/internal/types2: use self_test.go from go/types This CL replaces self_test.go with the (improved) version from go/types, modified for types2. To see the differences between go/types/self_test.go and this version, compare against patch set 1. Change-Id: I7ae830a17f7a0de40cc1f5063166a7247f78ec27 Reviewed-on: https://go-review.googlesource.com/c/go/+/300997 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/self_test.go | 86 ++++++++++++-------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/src/cmd/compile/internal/types2/self_test.go b/src/cmd/compile/internal/types2/self_test.go index 6d7971e50f..4722fec988 100644 --- a/src/cmd/compile/internal/types2/self_test.go +++ b/src/cmd/compile/internal/types2/self_test.go @@ -1,4 +1,3 @@ -// UNREVIEWED // Copyright 2013 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. @@ -7,17 +6,15 @@ package types2_test import ( "cmd/compile/internal/syntax" - "flag" - "fmt" + "path" "path/filepath" + "runtime" "testing" "time" . "cmd/compile/internal/types2" ) -var benchmark = flag.Bool("b", false, "run benchmarks") - func TestSelf(t *testing.T) { files, err := pkgFiles(".") if err != nil { @@ -25,7 +22,7 @@ func TestSelf(t *testing.T) { } conf := Config{Importer: defaultImporter()} - _, err = conf.Check("go/types", files, nil) + _, err = conf.Check("cmd/compile/internal/types2", files, nil) if err != nil { // Importing go/constant doesn't work in the // build dashboard environment. Don't report an error @@ -36,46 +33,69 @@ func TestSelf(t *testing.T) { } } -func TestBenchmark(t *testing.T) { - if !*benchmark { - return - } - - // We're not using testing's benchmarking mechanism directly - // because we want custom output. - - for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} { - path := filepath.Join("..", p) - runbench(t, path, false) - runbench(t, path, true) - fmt.Println() +func BenchmarkCheck(b *testing.B) { + for _, p := range []string{ + filepath.Join("src", "net", "http"), + filepath.Join("src", "go", "parser"), + filepath.Join("src", "go", "constant"), + filepath.Join("src", "go", "internal", "gcimporter"), + } { + b.Run(path.Base(p), func(b *testing.B) { + path := filepath.Join(runtime.GOROOT(), p) + for _, ignoreFuncBodies := range []bool{false, true} { + name := "funcbodies" + if ignoreFuncBodies { + name = "nofuncbodies" + } + b.Run(name, func(b *testing.B) { + b.Run("info", func(b *testing.B) { + runbench(b, path, ignoreFuncBodies, true) + }) + b.Run("noinfo", func(b *testing.B) { + runbench(b, path, ignoreFuncBodies, false) + }) + }) + } + }) } } -func runbench(t *testing.T, path string, ignoreFuncBodies bool) { +func runbench(b *testing.B, path string, ignoreFuncBodies, writeInfo bool) { files, err := pkgFiles(path) if err != nil { - t.Fatal(err) + b.Fatal(err) } - b := testing.Benchmark(func(b *testing.B) { - for i := 0; i < b.N; i++ { - conf := Config{IgnoreFuncBodies: ignoreFuncBodies} - conf.Check(path, files, nil) - } - }) - // determine line count var lines uint for _, f := range files { lines += f.EOF.Line() } - d := time.Duration(b.NsPerOp()) - fmt.Printf( - "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n", - filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies, - ) + b.ResetTimer() + start := time.Now() + for i := 0; i < b.N; i++ { + conf := Config{ + IgnoreFuncBodies: ignoreFuncBodies, + Importer: defaultImporter(), + } + var info *Info + if writeInfo { + info = &Info{ + Types: make(map[syntax.Expr]TypeAndValue), + Defs: make(map[*syntax.Name]Object), + Uses: make(map[*syntax.Name]Object), + Implicits: make(map[syntax.Node]Object), + Selections: make(map[*syntax.SelectorExpr]*Selection), + Scopes: make(map[syntax.Node]*Scope), + } + } + if _, err := conf.Check(path, files, info); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + b.ReportMetric(float64(lines)*float64(b.N)/time.Since(start).Seconds(), "lines/s") } func pkgFiles(path string) ([]*syntax.File, error) { -- GitLab From 73eb27bd3bdf727347a5e4d7d369d92f712f5ab5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 11 Mar 2021 15:09:47 -0800 Subject: [PATCH 0321/1298] misc/cgo/testcarchive: don't use == for string equality in C code For https://gcc.gnu.org/PR99553 Change-Id: I29a7fbfd89963d4139bc19af99330d70567938ea Reviewed-on: https://go-review.googlesource.com/c/go/+/300993 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- misc/cgo/testcarchive/testdata/main_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/cgo/testcarchive/testdata/main_unix.c b/misc/cgo/testcarchive/testdata/main_unix.c index b23ac1c242..bd00f9d233 100644 --- a/misc/cgo/testcarchive/testdata/main_unix.c +++ b/misc/cgo/testcarchive/testdata/main_unix.c @@ -36,7 +36,7 @@ int install_handler() { return 2; } // gccgo does not set SA_ONSTACK for SIGSEGV. - if (getenv("GCCGO") == "" && (osa.sa_flags&SA_ONSTACK) == 0) { + if (getenv("GCCGO") == NULL && (osa.sa_flags&SA_ONSTACK) == 0) { fprintf(stderr, "Go runtime did not install signal handler\n"); return 2; } -- GitLab From 8e725f8452ac0ece548837a95d125bc67b9d8828 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Fri, 5 Mar 2021 01:53:00 +0000 Subject: [PATCH 0322/1298] all: use HTML5 br tags In HTML5 br tags don't need a closing slash Change-Id: Ic53c43faee08c5b1267daa9a02cc186b1c255ca1 GitHub-Last-Rev: 652208116944d01b23b8af8f1af485da5e916d32 GitHub-Pull-Request: golang/go#44283 Reviewed-on: https://go-review.googlesource.com/c/go/+/292370 Reviewed-by: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Trust: Emmanuel Odeke --- misc/trace/trace_viewer_full.html | 16 ++++++++-------- src/cmd/compile/internal/ssa/html.go | 2 +- src/cmd/trace/mmu.go | 22 +++++++++++----------- src/encoding/xml/xml.go | 2 +- src/encoding/xml/xml_test.go | 2 +- src/net/http/pprof/pprof.go | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/misc/trace/trace_viewer_full.html b/misc/trace/trace_viewer_full.html index ef2e0ea573..ae6e35fca2 100644 --- a/misc/trace/trace_viewer_full.html +++ b/misc/trace/trace_viewer_full.html @@ -993,13 +993,13 @@
    - X no feedback
    - 0 uninitialized
    - . premonomorphic
    - 1 monomorphic
    - ^ recompute handler
    - P polymorphic
    - N megamorphic
    + X no feedback
    + 0 uninitialized
    + . premonomorphic
    + 1 monomorphic
    + ^ recompute handler
    + P polymorphic
    + N megamorphic
    G generic
    @@ -3596,7 +3596,7 @@
    Graphics Pipeline and Raster Tasks
    - When raster tasks are completed in comparison to the rest of the graphics pipeline.
    + When raster tasks are completed in comparison to the rest of the graphics pipeline.
    Only pages where raster tasks are completed after beginFrame is issued are included.
    diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index c06b5808e1..4d191199fb 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -1064,7 +1064,7 @@ func (f *Func) HTML(phase string, dot *dotWriter) string { p := htmlFuncPrinter{w: buf} fprintFunc(p, f) - // fprintFunc(&buf, f) // TODO: HTML, not text,
    for line breaks, etc. + // fprintFunc(&buf, f) // TODO: HTML, not text,
    for line breaks, etc. fmt.Fprint(buf, "") return buf.String() } diff --git a/src/cmd/trace/mmu.go b/src/cmd/trace/mmu.go index b92fac652c..1d1fd2ea94 100644 --- a/src/cmd/trace/mmu.go +++ b/src/cmd/trace/mmu.go @@ -283,7 +283,7 @@ var templMMU = ` .done(function(worst) { details.text('Lowest mutator utilization in ' + niceDuration(windowNS) + ' windows:'); for (var i = 0; i < worst.length; i++) { - details.append($('
    ')); + details.append($('
    ')); var text = worst[i].MutatorUtil.toFixed(3) + ' at time ' + niceDuration(worst[i].Time); details.append($('').text(text).attr('href', worst[i].URL)); } @@ -328,27 +328,27 @@ var templMMU = `
    Loading plot...

    - View
    + View
    - ?Consider whole system utilization. For example, if one of four procs is available to the mutator, mutator utilization will be 0.25. This is the standard definition of an MMU.
    + ?Consider whole system utilization. For example, if one of four procs is available to the mutator, mutator utilization will be 0.25. This is the standard definition of an MMU.
    - ?Consider per-goroutine utilization. When even one goroutine is interrupted by GC, mutator utilization is 0.
    + ?Consider per-goroutine utilization. When even one goroutine is interrupted by GC, mutator utilization is 0.

    - Include
    + Include
    - ?Stop-the-world stops all goroutines simultaneously.
    + ?Stop-the-world stops all goroutines simultaneously.
    - ?Background workers are GC-specific goroutines. 25% of the CPU is dedicated to background workers during GC.
    + ?Background workers are GC-specific goroutines. 25% of the CPU is dedicated to background workers during GC.
    - ?Mark assists are performed by allocation to prevent the mutator from outpacing GC.
    + ?Mark assists are performed by allocation to prevent the mutator from outpacing GC.
    - ?Sweep reclaims unused memory between GCs. (Enabling this may be very slow.).
    + ?Sweep reclaims unused memory between GCs. (Enabling this may be very slow.).

    - Display
    + Display
    - ?Display percentile mutator utilization in addition to minimum. E.g., p99 MU drops the worst 1% of windows.
    + ?Display percentile mutator utilization in addition to minimum. E.g., p99 MU drops the worst 1% of windows.

    diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 6f9594d7ba..384d6ad4b8 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -261,7 +261,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { // call to Token. To acquire a copy of the bytes, call CopyToken // or the token's Copy method. // -// Token expands self-closing elements such as
    +// Token expands self-closing elements such as
    // into separate start and end elements returned by successive calls. // // Token guarantees that the StartElement and EndElement diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go index 5672ebb375..5a10f5309d 100644 --- a/src/encoding/xml/xml_test.go +++ b/src/encoding/xml/xml_test.go @@ -940,7 +940,7 @@ func (m mapper) Token() (Token, error) { } func TestNewTokenDecoderIdempotent(t *testing.T) { - d := NewDecoder(strings.NewReader(`
    `)) + d := NewDecoder(strings.NewReader(`
    `)) d2 := NewTokenDecoder(d) if d != d2 { t.Error("NewTokenDecoder did not detect underlying Decoder") diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go index 5389a388c1..a854fef5d3 100644 --- a/src/net/http/pprof/pprof.go +++ b/src/net/http/pprof/pprof.go @@ -431,7 +431,7 @@ Types of profiles available: b.WriteString(`
    full goroutine stack dump -
    +

    Profile Descriptions:

      -- GitLab From a8a85281caf21831ee51ea8c879cbba94bcce256 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 12 Mar 2021 16:58:10 -0800 Subject: [PATCH 0323/1298] runtime: fix documented alignment of 32KiB and 64KiB size classes As Cherry pointed out on golang.org/cl/299909, the page allocator doesn't guarantee any alignment for multi-page allocations, so object alignments are thus implicitly capped at page alignment. Change-Id: I6f5df27f269b095cde54056f876fe4240f69c5c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/301292 Reviewed-by: Cherry Zhang Trust: Matthew Dempsky --- src/runtime/mksizeclasses.go | 6 +++++- src/runtime/sizeclasses.go | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go index ddbf1bf7fe..b1b10e9e02 100644 --- a/src/runtime/mksizeclasses.go +++ b/src/runtime/mksizeclasses.go @@ -239,7 +239,7 @@ func computeDivMagic(c *class) { func printComment(w io.Writer, classes []class) { fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste", "min align") prevSize := 0 - var minAligns [32]int + var minAligns [pageShift + 1]int for i, c := range classes { if i == 0 { continue @@ -249,6 +249,10 @@ func printComment(w io.Writer, classes []class) { tailWaste := spanSize - c.size*(spanSize/c.size) maxWaste := float64((c.size-prevSize-1)*objects+tailWaste) / float64(spanSize) alignBits := bits.TrailingZeros(uint(c.size)) + if alignBits > pageShift { + // object alignment is capped at page alignment + alignBits = pageShift + } for i := range minAligns { if i > alignBits { minAligns[i] = 0 diff --git a/src/runtime/sizeclasses.go b/src/runtime/sizeclasses.go index 65c72cfb1a..067871eaf3 100644 --- a/src/runtime/sizeclasses.go +++ b/src/runtime/sizeclasses.go @@ -62,7 +62,7 @@ package runtime // 56 12288 24576 2 0 11.45% 4096 // 57 13568 40960 3 256 9.99% 256 // 58 14336 57344 4 0 5.35% 2048 -// 59 16384 16384 1 0 12.49% 16384 +// 59 16384 16384 1 0 12.49% 8192 // 60 18432 73728 4 0 11.11% 2048 // 61 19072 57344 3 128 3.57% 128 // 62 20480 40960 2 0 6.87% 4096 @@ -70,7 +70,7 @@ package runtime // 64 24576 24576 1 0 11.45% 8192 // 65 27264 81920 3 128 10.00% 128 // 66 28672 57344 2 0 4.91% 4096 -// 67 32768 32768 1 0 12.50% 32768 +// 67 32768 32768 1 0 12.50% 8192 // alignment bits min obj size // 8 3 8 @@ -79,7 +79,7 @@ package runtime // 64 6 512 // 128 7 768 // 4096 12 28672 -// 32768 15 32768 +// 8192 13 32768 const ( _MaxSmallSize = 32768 -- GitLab From 59e012991a31dcf65a0ec79f99b7f4234f46cf2d Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Tue, 10 Nov 2020 21:27:04 +0000 Subject: [PATCH 0324/1298] net/http: note that "HTTP/2" is invalid for ParseHTTPVersion Change-Id: Ieba05dea892ec9855a63b80e456bcf9188eef855 GitHub-Last-Rev: 5f7663ac4aaecb01a27a04309277240fd15759c9 GitHub-Pull-Request: golang/go#41806 Reviewed-on: https://go-review.googlesource.com/c/go/+/259758 Reviewed-by: Damien Neil Reviewed-by: Emmanuel Odeke Trust: Damien Neil --- src/net/http/request.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 5251ebea66..aca55b1ca7 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -779,7 +779,8 @@ func removeZone(host string) string { } // ParseHTTPVersion parses an HTTP version string. -// "HTTP/1.0" returns (1, 0, true). +// "HTTP/1.0" returns (1, 0, true). Note that strings without +// a minor version, such as "HTTP/2", are not valid. func ParseHTTPVersion(vers string) (major, minor int, ok bool) { const Big = 1000000 // arbitrary upper bound switch vers { -- GitLab From 83e79c7b1474bfd7398cc69207587547885fa96e Mon Sep 17 00:00:00 2001 From: Mostyn Bramley-Moore Date: Tue, 16 Feb 2021 16:01:39 +0000 Subject: [PATCH 0325/1298] crypto/ecdsa: fix dead reference link The previous link broke, but it's available on the internet archive. Fixes #39808 Change-Id: Ic2be74a1f0591600ca1acbe08e1bab8ba1e21abe GitHub-Last-Rev: 6d6de5d2f451c6d53a1e55b62fb5a1fab0d49f10 GitHub-Pull-Request: golang/go#40165 Reviewed-on: https://go-review.googlesource.com/c/go/+/242103 Trust: Emmanuel Odeke Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Filippo Valsorda --- src/crypto/ecdsa/ecdsa.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index ccce873859..219436935f 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -17,7 +17,7 @@ // [Coron] // https://cs.nyu.edu/~dodis/ps/merkle.pdf // [Larsson] -// https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf +// https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf package ecdsa // Further references: -- GitLab From b3235b75d109f06eec0d3603c606b2d8373b9d4c Mon Sep 17 00:00:00 2001 From: Aman Karmani Date: Tue, 2 Mar 2021 11:52:34 -0800 Subject: [PATCH 0326/1298] encoding/gob: ensure "duplicate type received" decoder errors surface up Previously re-using a decoder with a new stream resulted in a confusing "extra data in buffer" error message. Change-Id: Ia4c4c3a2d4b63c59e37e53faa61a500d5ff6e5f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/297949 Reviewed-by: Rob Pike Run-TryBot: Rob Pike TryBot-Result: Go Bot Trust: Emmanuel Odeke --- src/encoding/gob/decoder.go | 3 +++ src/encoding/gob/encoder_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index b52aabe54b..7eb3093391 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -152,6 +152,9 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { } // Type definition for (-id) follows. dec.recvType(-id) + if dec.err != nil { + break + } // When decoding an interface, after a type there may be a // DelimitedValue still in the buffer. Skip its count. // (Alternatively, the buffer is empty and the byte count diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index fe2774948a..6183646f60 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -1127,3 +1127,28 @@ func TestBadData(t *testing.T) { } } } + +func TestDecodeErrorMultipleTypes(t *testing.T) { + type Test struct { + A string + B int + } + var b bytes.Buffer + NewEncoder(&b).Encode(Test{"one", 1}) + + var result, result2 Test + dec := NewDecoder(&b) + err := dec.Decode(&result) + if err != nil { + t.Errorf("decode: unexpected error %v", err) + } + + b.Reset() + NewEncoder(&b).Encode(Test{"two", 2}) + err = dec.Decode(&result2) + if err == nil { + t.Errorf("decode: expected duplicate type error, got nil") + } else if !strings.Contains(err.Error(), "duplicate type") { + t.Errorf("decode: expected duplicate type error, got %s", err.Error()) + } +} -- GitLab From 289d34a465d46e5c5c07034f5d54afbfda06f5b9 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Sat, 13 Mar 2021 11:25:15 +0000 Subject: [PATCH 0327/1298] all: remove duplicate words Change-Id: Ib0469232a2b69a869e58d5d24990ad74ac96ea56 GitHub-Last-Rev: eb38e049ee1e773392ff3747e1eb2af20dd50dcd GitHub-Pull-Request: golang/go#44805 Reviewed-on: https://go-review.googlesource.com/c/go/+/299109 Trust: Emmanuel Odeke Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/bytes/buffer.go | 2 +- src/cmd/compile/internal/ssa/func.go | 2 +- src/cmd/compile/internal/ssa/rewrite.go | 2 +- src/cmd/compile/internal/ssagen/abi.go | 2 +- src/cmd/compile/internal/syntax/scanner_test.go | 2 +- src/cmd/compile/internal/types2/examples/methods.go2 | 2 +- src/cmd/compile/internal/types2/type.go | 2 +- src/cmd/go/internal/fsys/fsys.go | 2 +- src/cmd/go/internal/modfetch/cache.go | 2 +- src/cmd/go/internal/modfetch/sumdb.go | 2 +- src/cmd/go/internal/modload/query_test.go | 2 +- src/cmd/go/testdata/script/mod_lazy_new_import.txt | 2 +- src/cmd/go/testdata/script/test_chatty_parallel_fail.txt | 2 +- src/cmd/go/testdata/script/test_chatty_parallel_success.txt | 2 +- src/cmd/internal/obj/sym.go | 2 +- src/cmd/link/internal/ld/macho_combine_dwarf.go | 2 +- src/crypto/tls/handshake_client_test.go | 2 +- src/debug/dwarf/const.go | 2 +- src/go/types/errorcodes.go | 2 +- src/go/types/examples/methods.go2 | 2 +- src/go/types/type.go | 2 +- src/go/types/typexpr.go | 2 +- src/net/http/h2_bundle.go | 2 +- src/net/http/server.go | 2 +- src/runtime/defer_test.go | 2 +- src/runtime/memmove_ppc64x.s | 2 +- src/runtime/panic.go | 2 +- src/runtime/proc.go | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index 549b077708..01764c694e 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -387,7 +387,7 @@ var errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was // UnreadByte unreads the last byte returned by the most recent successful // read operation that read at least one byte. If a write has happened since -// the last read, if the last read returned an error, or if the read read zero +// the last read, if the last read returned an error, or if the read reads zero // bytes, UnreadByte returns an error. func (b *Buffer) UnreadByte() error { if b.lastRead == opInvalid { diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index a36529af03..ebbcea598b 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -551,7 +551,7 @@ func (b *Block) NewValue4(pos src.XPos, op Op, t *types.Type, arg0, arg1, arg2, return v } -// NewValue4I returns a new value in the block with four arguments and and auxint value. +// NewValue4I returns a new value in the block with four arguments and auxint value. func (b *Block) NewValue4I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1, arg2, arg3 *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = auxint diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 5c56b2b346..3c222f80bf 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -1414,7 +1414,7 @@ func isPPC64WordRotateMask(v64 int64) bool { return (v&vp == 0 || vn&vpn == 0) && v != 0 } -// Compress mask and and shift into single value of the form +// Compress mask and shift into single value of the form // me | mb<<8 | rotate<<16 | nbits<<24 where me and mb can // be used to regenerate the input mask. func encodePPC64RotateMask(rotate, mask, nbits int64) int64 { diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go index 7180b3816c..e3f3ac637b 100644 --- a/src/cmd/compile/internal/ssagen/abi.go +++ b/src/cmd/compile/internal/ssagen/abi.go @@ -279,7 +279,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) { // things in registers and pushing them onto the stack prior to // the ABI0 call, meaning that they will always need to allocate // stack space. If the compiler marks them as NOSPLIT this seems - // as though it could lead to situations where the the linker's + // as though it could lead to situations where the linker's // nosplit-overflow analysis would trigger a link failure. On the // other hand if they not tagged NOSPLIT then this could cause // problems when building the runtime (since there may be calls to diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go index 04338629d4..fbe7b71163 100644 --- a/src/cmd/compile/internal/syntax/scanner_test.go +++ b/src/cmd/compile/internal/syntax/scanner_test.go @@ -547,7 +547,7 @@ func TestNumbers(t *testing.T) { t.Errorf("%q: got error but bad not set", test.src) } - // compute lit where where s.lit is not defined + // compute lit where s.lit is not defined var lit string switch s.tok { case _Name, _Literal: diff --git a/src/cmd/compile/internal/types2/examples/methods.go2 b/src/cmd/compile/internal/types2/examples/methods.go2 index 52f835f80e..7b6b13ddaa 100644 --- a/src/cmd/compile/internal/types2/examples/methods.go2 +++ b/src/cmd/compile/internal/types2/examples/methods.go2 @@ -43,7 +43,7 @@ func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ } // The names of the type parameters used in a parameterized receiver -// type don't have to match the type parameter names in the the declaration +// type don't have to match the type parameter names in the declaration // of the type used for the receiver. In our example, even though T1 is // declared with type parameter named A, methods using that receiver type // are free to use their own name for that type parameter. That is, the diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index ae6642a059..e4d6d0432d 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -522,7 +522,7 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b } // isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. -// If the the type list is empty (absent), typ trivially satisfies the interface. +// If the type list is empty (absent), typ trivially satisfies the interface. // TODO(gri) This is not a great name. Eventually, we should have a more comprehensive // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { diff --git a/src/cmd/go/internal/fsys/fsys.go b/src/cmd/go/internal/fsys/fsys.go index 7b06c3c7f3..ae10946fb1 100644 --- a/src/cmd/go/internal/fsys/fsys.go +++ b/src/cmd/go/internal/fsys/fsys.go @@ -100,7 +100,7 @@ func Init(wd string) error { } func initFromJSON(overlayJSON OverlayJSON) error { - // Canonicalize the paths in in the overlay map. + // Canonicalize the paths in the overlay map. // Use reverseCanonicalized to check for collisions: // no two 'from' paths should canonicalize to the same path. overlay = make(map[string]*node) diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 50a2898f24..d6774e1ce1 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -144,7 +144,7 @@ func lockVersion(mod module.Version) (unlock func(), err error) { return lockedfile.MutexAt(path).Lock() } -// SideLock locks a file within the module cache that that previously guarded +// SideLock locks a file within the module cache that previously guarded // edits to files outside the cache, such as go.sum and go.mod files in the // user's working directory. // If err is nil, the caller MUST eventually call the unlock function. diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index 118bb3d2d0..f233cba6df 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -185,7 +185,7 @@ func (c *dbClient) initBase() { } }) if errors.Is(err, fs.ErrNotExist) { - // No proxies, or all proxies failed (with 404, 410, or were were allowed + // No proxies, or all proxies failed (with 404, 410, or were allowed // to fall back), or we reached an explicit "direct" or "off". c.base = c.direct } else if err != nil { diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go index 6e39df45a7..a3f2f84505 100644 --- a/src/cmd/go/internal/modload/query_test.go +++ b/src/cmd/go/internal/modload/query_test.go @@ -106,7 +106,7 @@ var queryTests = []struct { {path: queryRepo, query: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, {path: queryRepo, query: "ed5ffdaa", vers: "v1.9.10-pre2.0.20191220134614-ed5ffdaa1f5e"}, - // golang.org/issue/29262: The major version for for a module without a suffix + // golang.org/issue/29262: The major version for a module without a suffix // should be based on the most recent tag (v1 as appropriate, not v0 // unconditionally). {path: queryRepo, query: "42abcb6df8ee", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt index 02935bf236..1be61a1561 100644 --- a/src/cmd/go/testdata/script/mod_lazy_new_import.txt +++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt @@ -32,7 +32,7 @@ cmp go.mod go.mod.old cp lazy.go.new lazy.go go list all go list -m all -stdout '^example.com/c v0.1.0' # not v0.2.0 as would be be resolved by 'latest' +stdout '^example.com/c v0.1.0' # not v0.2.0 as would be resolved by 'latest' cmp go.mod go.mod.old # TODO(#36460): diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt index 3b2791cb89..f8faa93663 100644 --- a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt +++ b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt @@ -22,7 +22,7 @@ import ( "flag" ) -// This test ensures the the order of CONT lines in parallel chatty tests. +// This test ensures the order of CONT lines in parallel chatty tests. func TestChattyParallel(t *testing.T) { t.Parallel() diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt index 58b5ab7267..63034fa3b5 100644 --- a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt @@ -21,7 +21,7 @@ import ( "flag" ) -// This test ensures the the order of CONT lines in parallel chatty tests. +// This test ensures the order of CONT lines in parallel chatty tests. func TestChattyParallel(t *testing.T) { t.Parallel() diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index 4515bdd0d3..98c7364e2a 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -57,7 +57,7 @@ func Linknew(arch *LinkArch) *Link { return ctxt } -// LookupDerived looks up or creates the symbol with name name derived from symbol s. +// LookupDerived looks up or creates the symbol with name derived from symbol s. // The resulting symbol will be static iff s is. func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym { if s.Static() { diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go index 77ee8a4d62..ae873ca6fa 100644 --- a/src/cmd/link/internal/ld/macho_combine_dwarf.go +++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go @@ -394,7 +394,7 @@ func machoUpdateDwarfHeader(r *loadCmdReader, compressedSects []*macho.Section, // We want the DWARF segment to be considered non-loadable, so // force vmaddr and vmsize to zero. In addition, set the initial // protection to zero so as to make the dynamic loader happy, - // since otherwise it may complain that that the vm size and file + // since otherwise it may complain that the vm size and file // size don't match for the segment. See issues 21647 and 32673 // for more context. Also useful to refer to the Apple dynamic // loader source, specifically ImageLoaderMachO::sniffLoadCommands diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 0e6c5a6370..693f9686a7 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -42,7 +42,7 @@ const ( // opensslSentinel on the connection. opensslSendSentinel - // opensslKeyUpdate causes OpenSSL to send send a key update message to the + // opensslKeyUpdate causes OpenSSL to send a key update message to the // client and request one back. opensslKeyUpdate ) diff --git a/src/debug/dwarf/const.go b/src/debug/dwarf/const.go index c60709199b..c0a74b08bb 100644 --- a/src/debug/dwarf/const.go +++ b/src/debug/dwarf/const.go @@ -427,7 +427,7 @@ const ( lneSetDiscriminator = 4 ) -// Line table directory directory and file name entry formats. +// Line table directory and file name entry formats. // These are new in DWARF 5. const ( lnctPath = 0x01 diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go index 1e39aed07d..4d9db18f9c 100644 --- a/src/go/types/errorcodes.go +++ b/src/go/types/errorcodes.go @@ -162,7 +162,7 @@ const ( _UntypedNil // _WrongAssignCount occurs when the number of values on the right-hand side - // of an assignment or or initialization expression does not match the number + // of an assignment or initialization expression does not match the number // of variables on the left-hand side. // // Example: diff --git a/src/go/types/examples/methods.go2 b/src/go/types/examples/methods.go2 index c294627837..76c6539e1b 100644 --- a/src/go/types/examples/methods.go2 +++ b/src/go/types/examples/methods.go2 @@ -42,7 +42,7 @@ func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot use 42 .* as int */ } // The names of the type parameters used in a parameterized receiver -// type don't have to match the type parameter names in the the declaration +// type don't have to match the type parameter names in the declaration // of the type used for the receiver. In our example, even though T1 is // declared with type parameter named A, methods using that receiver type // are free to use their own name for that type parameter. That is, the diff --git a/src/go/types/type.go b/src/go/types/type.go index 201da95a58..21d49de3aa 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -519,7 +519,7 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b } // isSatisfiedBy reports whether interface t's type list is satisfied by the type typ. -// If the the type list is empty (absent), typ trivially satisfies the interface. +// If the type list is empty (absent), typ trivially satisfies the interface. // TODO(gri) This is not a great name. Eventually, we should have a more comprehensive // "implements" predicate. func (t *Interface) isSatisfiedBy(typ Type) bool { diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 63e37de4b7..60a42b0426 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -690,7 +690,7 @@ func (check *Checker) typeList(list []ast.Expr) []Type { } // collectParams declares the parameters of list in scope and returns the corresponding -// variable list. If type0 != nil, it is used instead of the the first type in list. +// variable list. If type0 != nil, it is used instead of the first type in list. func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) { if list == nil { return diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 0379848e70..feecc8ce9c 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -7297,7 +7297,7 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool { return st.canTakeNewRequest } -// tooIdleLocked reports whether this connection has been been sitting idle +// tooIdleLocked reports whether this connection has been sitting idle // for too much wall time. func (cc *http2ClientConn) tooIdleLocked() bool { // The Round(0) strips the monontonic clock reading so the diff --git a/src/net/http/server.go b/src/net/http/server.go index ad99741177..ea3486289a 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2638,7 +2638,7 @@ type Server struct { // value. ConnContext func(ctx context.Context, c net.Conn) context.Context - inShutdown atomicBool // true when when server is in shutdown + inShutdown atomicBool // true when server is in shutdown disableKeepAlives int32 // accessed atomically. nextProtoOnce sync.Once // guards setupHTTP2_* init diff --git a/src/runtime/defer_test.go b/src/runtime/defer_test.go index 9a40ea1984..fc96144597 100644 --- a/src/runtime/defer_test.go +++ b/src/runtime/defer_test.go @@ -370,7 +370,7 @@ func g2() { defer ap.method2() defer ap.method1() ff1(ap, 1, 2, 3, 4, 5, 6, 7, 8, 9) - // Try to get the stack to be be moved by growing it too large, so + // Try to get the stack to be moved by growing it too large, so // existing stack-allocated defer becomes invalid. rec1(2000) } diff --git a/src/runtime/memmove_ppc64x.s b/src/runtime/memmove_ppc64x.s index edc6452bba..dbd835506f 100644 --- a/src/runtime/memmove_ppc64x.s +++ b/src/runtime/memmove_ppc64x.s @@ -157,7 +157,7 @@ backwardlargeloop: backward32setup: MOVD QWORDS, CTR // set up loop ctr - MOVD $16, IDX16 // 32 bytes at at time + MOVD $16, IDX16 // 32 bytes at a time backward32loop: SUB $32, TGT diff --git a/src/runtime/panic.go b/src/runtime/panic.go index e320eaa596..b5133fa5b4 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -699,7 +699,7 @@ func printpanics(p *_panic) { // specified by sp. If sp is nil, it uses the sp from the current defer record // (which has just been finished). Hence, it continues the stack scan from the // frame of the defer that just finished. It skips any frame that already has an -// open-coded _defer record, which would have been been created from a previous +// open-coded _defer record, which would have been created from a previous // (unrecovered) panic. // // Note: All entries of the defer chain (including this new open-coded entry) have diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 8db3b767d1..9ebfe70883 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1318,7 +1318,7 @@ func mstart1() { throw("bad runtime·mstart") } - // Set up m.g0.sched as a label returning returning to just + // Set up m.g0.sched as a label returning to just // after the mstart1 call in mstart0 above, for use by goexit0 and mcall. // We're never coming back to mstart1 after we call schedule, // so other calls can reuse the current frame. -- GitLab From fedb49487831e1168ebad7d313e23a8494bee6a2 Mon Sep 17 00:00:00 2001 From: Vitaly Zdanevich Date: Mon, 8 Mar 2021 03:15:25 +0000 Subject: [PATCH 0328/1298] errors/wrap: do not call Elem() twice Change-Id: I2fe6037c45a0dfe25f946a92ff97b5e3fbd69bc0 GitHub-Last-Rev: 644d479a27c0eccfc0b37e1a560ca09e47b5a972 GitHub-Pull-Request: golang/go#44851 Reviewed-on: https://go-review.googlesource.com/c/go/+/299629 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Tobias Klauser --- src/errors/wrap.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/errors/wrap.go b/src/errors/wrap.go index 7928fe673e..4eb4f9ae37 100644 --- a/src/errors/wrap.go +++ b/src/errors/wrap.go @@ -83,10 +83,10 @@ func As(err error, target interface{}) bool { if typ.Kind() != reflectlite.Ptr || val.IsNil() { panic("errors: target must be a non-nil pointer") } - if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) { + targetType := typ.Elem() + if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) { panic("errors: *target must be interface or implement error") } - targetType := typ.Elem() for err != nil { if reflectlite.TypeOf(err).AssignableTo(targetType) { val.Elem().Set(reflectlite.ValueOf(err)) -- GitLab From 3224990dad27d5a06961a168c3760b13a6d140c1 Mon Sep 17 00:00:00 2001 From: zfCode Date: Sat, 13 Mar 2021 18:00:30 +0000 Subject: [PATCH 0329/1298] =?UTF-8?q?fmt:=20use=20=E2=80=9CtruncateString?= =?UTF-8?q?=E2=80=9D=20not=20=E2=80=9Ctruncate=E2=80=9D=20in=20method=20do?= =?UTF-8?q?c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If1acb6a8533a782f80c7d1f0ad5155e98e1134dd GitHub-Last-Rev: 03384a3d99dd89d802635f7ef48ce4456ec338b0 GitHub-Pull-Request: golang/go#44375 Reviewed-on: https://go-review.googlesource.com/c/go/+/293629 Reviewed-by: Emmanuel Odeke Reviewed-by: Rob Pike Trust: Rob Pike --- src/fmt/format.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt/format.go b/src/fmt/format.go index 4d12f82f7d..bd00e5a5e0 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -320,7 +320,7 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits st f.zero = oldZero } -// truncate truncates the string s to the specified precision, if present. +// truncateString truncates the string s to the specified precision, if present. func (f *fmt) truncateString(s string) string { if f.precPresent { n := f.prec -- GitLab From 8336c311f848cb9adc76aeb8bd8172f67bda67e6 Mon Sep 17 00:00:00 2001 From: JulianChu Date: Sat, 13 Mar 2021 17:44:10 +0000 Subject: [PATCH 0330/1298] io: add error check to WriteString Example test Change-Id: I9ce1c79e5799f205aec3a4dc02645ed26bdc3581 GitHub-Last-Rev: 59b637db0154e55ddfdd55e54b9596dc3a0ad32d GitHub-Pull-Request: golang/go#44533 Reviewed-on: https://go-review.googlesource.com/c/go/+/295389 Reviewed-by: Emmanuel Odeke Reviewed-by: Robert Griesemer Trust: Emmanuel Odeke Trust: Robert Griesemer Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot --- src/io/example_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/io/example_test.go b/src/io/example_test.go index 6d338acd14..a18df9feff 100644 --- a/src/io/example_test.go +++ b/src/io/example_test.go @@ -103,7 +103,9 @@ func ExampleReadFull() { } func ExampleWriteString() { - io.WriteString(os.Stdout, "Hello World") + if _, err := io.WriteString(os.Stdout, "Hello World"); err != nil { + log.Fatal(err) + } // Output: Hello World } -- GitLab From 4bd4dfe96a0e7cd252ff0d53ba46618b54618d15 Mon Sep 17 00:00:00 2001 From: cui Date: Mon, 11 Jan 2021 08:44:45 +0000 Subject: [PATCH 0331/1298] cmd/compile/internal/ssa: prealloc slice Change-Id: I9943a4f931c251a69bc8244c0d7723a0a3552073 GitHub-Last-Rev: d9dd94ae4444cb0106756cdb98c1c5fa12fa5f79 GitHub-Pull-Request: golang/go#43622 Reviewed-on: https://go-review.googlesource.com/c/go/+/282992 Reviewed-by: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Trust: Emmanuel Odeke --- src/cmd/compile/internal/ssa/lca.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/lca.go b/src/cmd/compile/internal/ssa/lca.go index 5cb73911df..90daebe44f 100644 --- a/src/cmd/compile/internal/ssa/lca.go +++ b/src/cmd/compile/internal/ssa/lca.go @@ -4,6 +4,10 @@ package ssa +import ( + "math/bits" +) + // Code to compute lowest common ancestors in the dominator tree. // https://en.wikipedia.org/wiki/Lowest_common_ancestor // https://en.wikipedia.org/wiki/Range_minimum_query#Solution_using_constant_time_and_linearithmic_space @@ -79,7 +83,7 @@ func makeLCArange(f *Func) *lcaRange { } // Compute fast range-minimum query data structure - var rangeMin [][]ID + rangeMin := make([][]ID, 0, bits.Len64(uint64(len(tour)))) rangeMin = append(rangeMin, tour) // 1-size windows are just the tour itself. for logS, s := 1, 2; s < len(tour); logS, s = logS+1, s*2 { r := make([]ID, len(tour)-s+1) -- GitLab From 1767d2cc2fed70e4f195474677f72712eaf28c9e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 13 Mar 2021 18:00:17 +0100 Subject: [PATCH 0332/1298] io/fs: use testing.T.TempDir in TestWalkDir Change-Id: I805ad51332e4efe27d47f6c6e3b0af945e0d4aa0 Reviewed-on: https://go-review.googlesource.com/c/go/+/301489 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/io/fs/walk_test.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/io/fs/walk_test.go b/src/io/fs/walk_test.go index ebc4e50fb3..5e127e71cd 100644 --- a/src/io/fs/walk_test.go +++ b/src/io/fs/walk_test.go @@ -6,7 +6,6 @@ package fs_test import ( . "io/fs" - "io/ioutil" "os" pathpkg "path" "testing" @@ -96,11 +95,7 @@ func mark(entry DirEntry, err error, errors *[]error, clear bool) error { } func TestWalkDir(t *testing.T) { - tmpDir, err := ioutil.TempDir("", "TestWalk") - if err != nil { - t.Fatal("creating temp dir:", err) - } - defer os.RemoveAll(tmpDir) + tmpDir := t.TempDir() origDir, err := os.Getwd() if err != nil { -- GitLab From 7936efecc8981fab11b445d96cdb1480d9d8208b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 13 Mar 2021 19:43:12 +0100 Subject: [PATCH 0333/1298] net/http: revert change from CL 299109 breaking TestAllDependencies This code is generated from golang.org/x/net/http2 and thus any changes first have to occur there. Otherwise TestAllDependencies fails on the longtest builders. Change-Id: I918afdd9388dd28bb3c8e55438be764c4f32c7c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/301491 Trust: Tobias Klauser Run-TryBot: Tobias Klauser Reviewed-by: Emmanuel Odeke TryBot-Result: Go Bot --- src/net/http/h2_bundle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index feecc8ce9c..0379848e70 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -7297,7 +7297,7 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool { return st.canTakeNewRequest } -// tooIdleLocked reports whether this connection has been sitting idle +// tooIdleLocked reports whether this connection has been been sitting idle // for too much wall time. func (cc *http2ClientConn) tooIdleLocked() bool { // The Round(0) strips the monontonic clock reading so the -- GitLab From 88b8a1608987d494f3f29618e7524e61712c31ba Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Fri, 21 Aug 2020 21:23:18 +0900 Subject: [PATCH 0334/1298] cmd/cover: replace code using optimized golang.org/x/tools/cover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After CL 179377, this change deletes all the prior cmd/cover code and instead vendors and type aliases code using the significantly optimized golang.org/x/tools/cover, which sped up ParseProfiles by manually parsing profiles instead of a regex. The speed up was: name old time/op new time/op delta ParseLine-12 2.43µs ± 2% 0.05µs ± 8% -97.98% (p=0.000 n=10+9) name old speed new speed delta ParseLine-12 42.5MB/s ± 2% 2103.2MB/s ± 7% +4853.14% (p=0.000 n=10+9) Fixes #32211. Change-Id: Ie4e8be7502f25eb95fae7a9d8334fc97b045d53f Reviewed-on: https://go-review.googlesource.com/c/go/+/249759 Reviewed-by: Emmanuel Odeke Reviewed-by: Bryan C. Mills Trust: Emmanuel Odeke Trust: Bryan C. Mills Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot --- src/cmd/cover/profile.go | 202 +------------- .../golang.org/x/tools/cover/profile.go | 261 ++++++++++++++++++ src/cmd/vendor/modules.txt | 1 + 3 files changed, 268 insertions(+), 196 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/tools/cover/profile.go diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go index 656c862740..839444edb7 100644 --- a/src/cmd/cover/profile.go +++ b/src/cmd/cover/profile.go @@ -4,217 +4,27 @@ // This file provides support for parsing coverage profiles // generated by "go test -coverprofile=cover.out". -// It is a copy of golang.org/x/tools/cover/profile.go. +// It is a alias of golang.org/x/tools/cover/profile.go. package main import ( - "bufio" - "fmt" - "math" - "os" - "regexp" - "sort" - "strconv" - "strings" + "golang.org/x/tools/cover" ) // Profile represents the profiling data for a specific file. -type Profile struct { - FileName string - Mode string - Blocks []ProfileBlock -} +type Profile = cover.Profile // ProfileBlock represents a single block of profiling data. -type ProfileBlock struct { - StartLine, StartCol int - EndLine, EndCol int - NumStmt, Count int -} - -type byFileName []*Profile - -func (p byFileName) Len() int { return len(p) } -func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName } -func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +type ProfileBlock = cover.ProfileBlock // ParseProfiles parses profile data in the specified file and returns a // Profile for each source file described therein. func ParseProfiles(fileName string) ([]*Profile, error) { - pf, err := os.Open(fileName) - if err != nil { - return nil, err - } - defer pf.Close() - - files := make(map[string]*Profile) - buf := bufio.NewReader(pf) - // First line is "mode: foo", where foo is "set", "count", or "atomic". - // Rest of file is in the format - // encoding/base64/base64.go:34.44,37.40 3 1 - // where the fields are: name.go:line.column,line.column numberOfStatements count - s := bufio.NewScanner(buf) - mode := "" - for s.Scan() { - line := s.Text() - if mode == "" { - const p = "mode: " - if !strings.HasPrefix(line, p) || line == p { - return nil, fmt.Errorf("bad mode line: %v", line) - } - mode = line[len(p):] - continue - } - m := lineRe.FindStringSubmatch(line) - if m == nil { - return nil, fmt.Errorf("line %q doesn't match expected format: %v", m, lineRe) - } - fn := m[1] - p := files[fn] - if p == nil { - p = &Profile{ - FileName: fn, - Mode: mode, - } - files[fn] = p - } - p.Blocks = append(p.Blocks, ProfileBlock{ - StartLine: toInt(m[2]), - StartCol: toInt(m[3]), - EndLine: toInt(m[4]), - EndCol: toInt(m[5]), - NumStmt: toInt(m[6]), - Count: toInt(m[7]), - }) - } - if err := s.Err(); err != nil { - return nil, err - } - for _, p := range files { - sort.Sort(blocksByStart(p.Blocks)) - // Merge samples from the same location. - j := 1 - for i := 1; i < len(p.Blocks); i++ { - b := p.Blocks[i] - last := p.Blocks[j-1] - if b.StartLine == last.StartLine && - b.StartCol == last.StartCol && - b.EndLine == last.EndLine && - b.EndCol == last.EndCol { - if b.NumStmt != last.NumStmt { - return nil, fmt.Errorf("inconsistent NumStmt: changed from %d to %d", last.NumStmt, b.NumStmt) - } - if mode == "set" { - p.Blocks[j-1].Count |= b.Count - } else { - p.Blocks[j-1].Count += b.Count - } - continue - } - p.Blocks[j] = b - j++ - } - p.Blocks = p.Blocks[:j] - } - // Generate a sorted slice. - profiles := make([]*Profile, 0, len(files)) - for _, profile := range files { - profiles = append(profiles, profile) - } - sort.Sort(byFileName(profiles)) - return profiles, nil -} - -type blocksByStart []ProfileBlock - -func (b blocksByStart) Len() int { return len(b) } -func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] } -func (b blocksByStart) Less(i, j int) bool { - bi, bj := b[i], b[j] - return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol -} - -var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`) - -func toInt(s string) int { - i, err := strconv.Atoi(s) - if err != nil { - panic(err) - } - return i + return cover.ParseProfiles(fileName) } // Boundary represents the position in a source file of the beginning or end of a // block as reported by the coverage profile. In HTML mode, it will correspond to // the opening or closing of a tag and will be used to colorize the source -type Boundary struct { - Offset int // Location as a byte offset in the source file. - Start bool // Is this the start of a block? - Count int // Event count from the cover profile. - Norm float64 // Count normalized to [0..1]. - Index int // Order in input file. -} - -// Boundaries returns a Profile as a set of Boundary objects within the provided src. -func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { - // Find maximum count. - max := 0 - for _, b := range p.Blocks { - if b.Count > max { - max = b.Count - } - } - // Divisor for normalization. - divisor := math.Log(float64(max)) - - // boundary returns a Boundary, populating the Norm field with a normalized Count. - index := 0 - boundary := func(offset int, start bool, count int) Boundary { - b := Boundary{Offset: offset, Start: start, Count: count, Index: index} - index++ - if !start || count == 0 { - return b - } - if max <= 1 { - b.Norm = 0.8 // Profile is in "set" mode; we want a heat map. Use cov8 in the CSS. - } else if count > 0 { - b.Norm = math.Log(float64(count)) / divisor - } - return b - } - - line, col := 1, 2 // TODO: Why is this 2? - for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); { - b := p.Blocks[bi] - if b.StartLine == line && b.StartCol == col { - boundaries = append(boundaries, boundary(si, true, b.Count)) - } - if b.EndLine == line && b.EndCol == col || line > b.EndLine { - boundaries = append(boundaries, boundary(si, false, 0)) - bi++ - continue // Don't advance through src; maybe the next block starts here. - } - if src[si] == '\n' { - line++ - col = 0 - } - col++ - si++ - } - sort.Sort(boundariesByPos(boundaries)) - return -} - -type boundariesByPos []Boundary - -func (b boundariesByPos) Len() int { return len(b) } -func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } -func (b boundariesByPos) Less(i, j int) bool { - if b[i].Offset == b[j].Offset { - // Boundaries at the same offset should be ordered according to - // their original position. - return b[i].Index < b[j].Index - } - return b[i].Offset < b[j].Offset -} +type Boundary = cover.Boundary diff --git a/src/cmd/vendor/golang.org/x/tools/cover/profile.go b/src/cmd/vendor/golang.org/x/tools/cover/profile.go new file mode 100644 index 0000000000..57195774ce --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/cover/profile.go @@ -0,0 +1,261 @@ +// Copyright 2013 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 cover provides support for parsing coverage profiles +// generated by "go test -coverprofile=cover.out". +package cover // import "golang.org/x/tools/cover" + +import ( + "bufio" + "errors" + "fmt" + "math" + "os" + "sort" + "strconv" + "strings" +) + +// Profile represents the profiling data for a specific file. +type Profile struct { + FileName string + Mode string + Blocks []ProfileBlock +} + +// ProfileBlock represents a single block of profiling data. +type ProfileBlock struct { + StartLine, StartCol int + EndLine, EndCol int + NumStmt, Count int +} + +type byFileName []*Profile + +func (p byFileName) Len() int { return len(p) } +func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName } +func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// ParseProfiles parses profile data in the specified file and returns a +// Profile for each source file described therein. +func ParseProfiles(fileName string) ([]*Profile, error) { + pf, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer pf.Close() + + files := make(map[string]*Profile) + buf := bufio.NewReader(pf) + // First line is "mode: foo", where foo is "set", "count", or "atomic". + // Rest of file is in the format + // encoding/base64/base64.go:34.44,37.40 3 1 + // where the fields are: name.go:line.column,line.column numberOfStatements count + s := bufio.NewScanner(buf) + mode := "" + for s.Scan() { + line := s.Text() + if mode == "" { + const p = "mode: " + if !strings.HasPrefix(line, p) || line == p { + return nil, fmt.Errorf("bad mode line: %v", line) + } + mode = line[len(p):] + continue + } + fn, b, err := parseLine(line) + if err != nil { + return nil, fmt.Errorf("line %q doesn't match expected format: %v", line, err) + } + p := files[fn] + if p == nil { + p = &Profile{ + FileName: fn, + Mode: mode, + } + files[fn] = p + } + p.Blocks = append(p.Blocks, b) + } + if err := s.Err(); err != nil { + return nil, err + } + for _, p := range files { + sort.Sort(blocksByStart(p.Blocks)) + // Merge samples from the same location. + j := 1 + for i := 1; i < len(p.Blocks); i++ { + b := p.Blocks[i] + last := p.Blocks[j-1] + if b.StartLine == last.StartLine && + b.StartCol == last.StartCol && + b.EndLine == last.EndLine && + b.EndCol == last.EndCol { + if b.NumStmt != last.NumStmt { + return nil, fmt.Errorf("inconsistent NumStmt: changed from %d to %d", last.NumStmt, b.NumStmt) + } + if mode == "set" { + p.Blocks[j-1].Count |= b.Count + } else { + p.Blocks[j-1].Count += b.Count + } + continue + } + p.Blocks[j] = b + j++ + } + p.Blocks = p.Blocks[:j] + } + // Generate a sorted slice. + profiles := make([]*Profile, 0, len(files)) + for _, profile := range files { + profiles = append(profiles, profile) + } + sort.Sort(byFileName(profiles)) + return profiles, nil +} + +// parseLine parses a line from a coverage file. +// It is equivalent to the regex +// ^(.+):([0-9]+)\.([0-9]+),([0-9]+)\.([0-9]+) ([0-9]+) ([0-9]+)$ +// +// However, it is much faster: https://golang.org/cl/179377 +func parseLine(l string) (fileName string, block ProfileBlock, err error) { + end := len(l) + + b := ProfileBlock{} + b.Count, end, err = seekBack(l, ' ', end, "Count") + if err != nil { + return "", b, err + } + b.NumStmt, end, err = seekBack(l, ' ', end, "NumStmt") + if err != nil { + return "", b, err + } + b.EndCol, end, err = seekBack(l, '.', end, "EndCol") + if err != nil { + return "", b, err + } + b.EndLine, end, err = seekBack(l, ',', end, "EndLine") + if err != nil { + return "", b, err + } + b.StartCol, end, err = seekBack(l, '.', end, "StartCol") + if err != nil { + return "", b, err + } + b.StartLine, end, err = seekBack(l, ':', end, "StartLine") + if err != nil { + return "", b, err + } + fn := l[0:end] + if fn == "" { + return "", b, errors.New("a FileName cannot be blank") + } + return fn, b, nil +} + +// seekBack searches backwards from end to find sep in l, then returns the +// value between sep and end as an integer. +// If seekBack fails, the returned error will reference what. +func seekBack(l string, sep byte, end int, what string) (value int, nextSep int, err error) { + // Since we're seeking backwards and we know only ASCII is legal for these values, + // we can ignore the possibility of non-ASCII characters. + for start := end - 1; start >= 0; start-- { + if l[start] == sep { + i, err := strconv.Atoi(l[start+1 : end]) + if err != nil { + return 0, 0, fmt.Errorf("couldn't parse %q: %v", what, err) + } + if i < 0 { + return 0, 0, fmt.Errorf("negative values are not allowed for %s, found %d", what, i) + } + return i, start, nil + } + } + return 0, 0, fmt.Errorf("couldn't find a %s before %s", string(sep), what) +} + +type blocksByStart []ProfileBlock + +func (b blocksByStart) Len() int { return len(b) } +func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b blocksByStart) Less(i, j int) bool { + bi, bj := b[i], b[j] + return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol +} + +// Boundary represents the position in a source file of the beginning or end of a +// block as reported by the coverage profile. In HTML mode, it will correspond to +// the opening or closing of a tag and will be used to colorize the source +type Boundary struct { + Offset int // Location as a byte offset in the source file. + Start bool // Is this the start of a block? + Count int // Event count from the cover profile. + Norm float64 // Count normalized to [0..1]. + Index int // Order in input file. +} + +// Boundaries returns a Profile as a set of Boundary objects within the provided src. +func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { + // Find maximum count. + max := 0 + for _, b := range p.Blocks { + if b.Count > max { + max = b.Count + } + } + // Divisor for normalization. + divisor := math.Log(float64(max)) + + // boundary returns a Boundary, populating the Norm field with a normalized Count. + index := 0 + boundary := func(offset int, start bool, count int) Boundary { + b := Boundary{Offset: offset, Start: start, Count: count, Index: index} + index++ + if !start || count == 0 { + return b + } + if max <= 1 { + b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. + } else if count > 0 { + b.Norm = math.Log(float64(count)) / divisor + } + return b + } + + line, col := 1, 2 // TODO: Why is this 2? + for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); { + b := p.Blocks[bi] + if b.StartLine == line && b.StartCol == col { + boundaries = append(boundaries, boundary(si, true, b.Count)) + } + if b.EndLine == line && b.EndCol == col || line > b.EndLine { + boundaries = append(boundaries, boundary(si, false, 0)) + bi++ + continue // Don't advance through src; maybe the next block starts here. + } + if src[si] == '\n' { + line++ + col = 0 + } + col++ + si++ + } + sort.Sort(boundariesByPos(boundaries)) + return +} + +type boundariesByPos []Boundary + +func (b boundariesByPos) Len() int { return len(b) } +func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b boundariesByPos) Less(i, j int) bool { + if b[i].Offset == b[j].Offset { + // Boundaries at the same offset should be ordered according to + // their original position. + return b[i].Index < b[j].Index + } + return b[i].Offset < b[j].Offset +} diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index af92df8721..7a8e98733a 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -46,6 +46,7 @@ golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f ## explicit +golang.org/x/tools/cover golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/internal/analysisflags golang.org/x/tools/go/analysis/internal/facts -- GitLab From 061a6903a232cb868780b1e724a75bf92a728489 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sat, 13 Mar 2021 16:52:16 -0800 Subject: [PATCH 0335/1298] all: add internal/itoa package This replaces five implementations scattered across low level packages. (And I plan to use it in a sixth soon.) Three of the five were byte-for-byte identical. Change-Id: I3bbbeeac63723a487986c912b604e10ad1e042f4 Reviewed-on: https://go-review.googlesource.com/c/go/+/301549 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/go/build/deps_test.go | 1 + src/internal/itoa/itoa.go | 33 ++++++++++++++++++++++++ src/internal/itoa/itoa_test.go | 40 ++++++++++++++++++++++++++++++ src/internal/poll/fd_io_plan9.go | 3 ++- src/internal/poll/strconv.go | 28 --------------------- src/net/dnsclient.go | 3 ++- src/net/dnsclient_unix.go | 3 ++- src/net/interface.go | 3 ++- src/net/interface_plan9.go | 5 ++-- src/net/ip.go | 7 ++++-- src/net/ipsock_plan9.go | 5 ++-- src/net/lookup_plan9.go | 3 ++- src/net/parse.go | 26 ------------------- src/net/tcpsock.go | 5 ++-- src/net/tcpsockopt_plan9.go | 3 ++- src/net/udpsock.go | 5 ++-- src/os/exec_plan9.go | 3 ++- src/os/exec_posix.go | 5 ++-- src/os/executable_plan9.go | 7 ++++-- src/os/signal/signal_plan9_test.go | 18 ++------------ src/os/str.go | 26 ------------------- src/os/tempfile.go | 7 ++++-- src/syscall/dll_windows.go | 3 ++- src/syscall/exec_linux.go | 9 ++++--- src/syscall/exec_plan9.go | 3 ++- src/syscall/export_test.go | 7 ------ src/syscall/str.go | 24 ------------------ src/syscall/syscall_js.go | 5 ++-- src/syscall/syscall_linux.go | 7 ++++-- src/syscall/syscall_test.go | 17 ------------- src/syscall/syscall_unix.go | 5 ++-- src/syscall/syscall_windows.go | 5 ++-- 32 files changed, 143 insertions(+), 181 deletions(-) create mode 100644 src/internal/itoa/itoa.go create mode 100644 src/internal/itoa/itoa_test.go delete mode 100644 src/syscall/export_test.go delete mode 100644 src/syscall/str.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index e05d0aac2e..63ef2428b1 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -83,6 +83,7 @@ var depsRules = ` # RUNTIME is the core runtime group of packages, all of them very light-weight. internal/abi, internal/cpu, unsafe < internal/bytealg + < internal/itoa < internal/unsafeheader < runtime/internal/sys < runtime/internal/atomic diff --git a/src/internal/itoa/itoa.go b/src/internal/itoa/itoa.go new file mode 100644 index 0000000000..c6062d9fe1 --- /dev/null +++ b/src/internal/itoa/itoa.go @@ -0,0 +1,33 @@ +// Copyright 2021 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. + +// Simple conversions to avoid depending on strconv. + +package itoa + +// Itoa converts val to a decimal string. +func Itoa(val int) string { + if val < 0 { + return "-" + Uitoa(uint(-val)) + } + return Uitoa(uint(val)) +} + +// Uitoa converts val to a decimal string. +func Uitoa(val uint) string { + if val == 0 { // avoid string allocation + return "0" + } + var buf [20]byte // big enough for 64bit value base 10 + i := len(buf) - 1 + for val >= 10 { + q := val / 10 + buf[i] = byte('0' + val - q*10) + i-- + val = q + } + // val < 10 + buf[i] = byte('0' + val) + return string(buf[i:]) +} diff --git a/src/internal/itoa/itoa_test.go b/src/internal/itoa/itoa_test.go new file mode 100644 index 0000000000..71931c1e3a --- /dev/null +++ b/src/internal/itoa/itoa_test.go @@ -0,0 +1,40 @@ +// Copyright 2021 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 itoa_test + +import ( + "fmt" + "internal/itoa" + "math" + "testing" +) + +var ( + minInt64 int64 = math.MinInt64 + maxInt64 int64 = math.MaxInt64 + maxUint64 uint64 = math.MaxUint64 +) + +func TestItoa(t *testing.T) { + tests := []int{int(minInt64), math.MinInt32, -999, -100, -1, 0, 1, 100, 999, math.MaxInt32, int(maxInt64)} + for _, tt := range tests { + got := itoa.Itoa(tt) + want := fmt.Sprint(tt) + if want != got { + t.Fatalf("Itoa(%d) = %s, want %s", tt, got, want) + } + } +} + +func TestUitoa(t *testing.T) { + tests := []uint{0, 1, 100, 999, math.MaxUint32, uint(maxUint64)} + for _, tt := range tests { + got := itoa.Uitoa(tt) + want := fmt.Sprint(tt) + if want != got { + t.Fatalf("Uitoa(%d) = %s, want %s", tt, got, want) + } + } +} diff --git a/src/internal/poll/fd_io_plan9.go b/src/internal/poll/fd_io_plan9.go index 287d11bd8c..3205ac8513 100644 --- a/src/internal/poll/fd_io_plan9.go +++ b/src/internal/poll/fd_io_plan9.go @@ -5,6 +5,7 @@ package poll import ( + "internal/itoa" "runtime" "sync" "syscall" @@ -71,7 +72,7 @@ func (aio *asyncIO) Cancel() { if aio.pid == -1 { return } - f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY) + f, e := syscall.Open("/proc/"+itoa.Itoa(aio.pid)+"/note", syscall.O_WRONLY) if e != nil { return } diff --git a/src/internal/poll/strconv.go b/src/internal/poll/strconv.go index fd5e20f1f4..c98332d3da 100644 --- a/src/internal/poll/strconv.go +++ b/src/internal/poll/strconv.go @@ -5,36 +5,8 @@ //go:build plan9 // +build plan9 -// Simple conversions to avoid depending on strconv. - package poll -// Convert integer to decimal string -func itoa(val int) string { - if val < 0 { - return "-" + uitoa(uint(-val)) - } - return uitoa(uint(val)) -} - -// Convert unsigned integer to decimal string -func uitoa(val uint) string { - if val == 0 { // avoid string allocation - return "0" - } - var buf [20]byte // big enough for 64bit value base 10 - i := len(buf) - 1 - for val >= 10 { - q := val / 10 - buf[i] = byte('0' + val - q*10) - i-- - val = q - } - // val < 10 - buf[i] = byte('0' + val) - return string(buf[i:]) -} - // stringsHasSuffix is strings.HasSuffix. It reports whether s ends in // suffix. func stringsHasSuffix(s, suffix string) bool { diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go index e9c73845d7..1bbe39650b 100644 --- a/src/net/dnsclient.go +++ b/src/net/dnsclient.go @@ -5,6 +5,7 @@ package net import ( + "internal/itoa" "sort" "golang.org/x/net/dns/dnsmessage" @@ -33,7 +34,7 @@ func reverseaddr(addr string) (arpa string, err error) { return "", &DNSError{Err: "unrecognized address", Name: addr} } if ip.To4() != nil { - return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil + return itoa.Uitoa(uint(ip[15])) + "." + itoa.Uitoa(uint(ip[14])) + "." + itoa.Uitoa(uint(ip[13])) + "." + itoa.Uitoa(uint(ip[12])) + ".in-addr.arpa.", nil } // Must be IPv6 buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index a3242ff3b2..86f64335ea 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -18,6 +18,7 @@ package net import ( "context" "errors" + "internal/itoa" "io" "os" "sync" @@ -510,7 +511,7 @@ func (o hostLookupOrder) String() string { if s, ok := lookupOrderName[o]; ok { return s } - return "hostLookupOrder=" + itoa(int(o)) + "??" + return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??" } // goLookupHost is the native Go implementation of LookupHost. diff --git a/src/net/interface.go b/src/net/interface.go index 914aaa010f..0e5d3202c9 100644 --- a/src/net/interface.go +++ b/src/net/interface.go @@ -6,6 +6,7 @@ package net import ( "errors" + "internal/itoa" "sync" "time" ) @@ -230,7 +231,7 @@ func (zc *ipv6ZoneCache) name(index int) string { zoneCache.RUnlock() } if !ok { // last resort - name = uitoa(uint(index)) + name = itoa.Uitoa(uint(index)) } return name } diff --git a/src/net/interface_plan9.go b/src/net/interface_plan9.go index 31bbaca467..957975c265 100644 --- a/src/net/interface_plan9.go +++ b/src/net/interface_plan9.go @@ -6,6 +6,7 @@ package net import ( "errors" + "internal/itoa" "os" ) @@ -38,8 +39,8 @@ func interfaceTable(ifindex int) ([]Interface, error) { func readInterface(i int) (*Interface, error) { ifc := &Interface{ - Index: i + 1, // Offset the index by one to suit the contract - Name: netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9 + Index: i + 1, // Offset the index by one to suit the contract + Name: netdir + "/ipifc/" + itoa.Itoa(i), // Name is the full path to the interface path in plan9 } ifcstat := ifc.Name + "/status" diff --git a/src/net/ip.go b/src/net/ip.go index c00fe8ed3c..18e3f3a2f5 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -12,7 +12,10 @@ package net -import "internal/bytealg" +import ( + "internal/bytealg" + "internal/itoa" +) // IP address lengths (bytes). const ( @@ -531,7 +534,7 @@ func (n *IPNet) String() string { if l == -1 { return nn.String() + "/" + m.String() } - return nn.String() + "/" + uitoa(uint(l)) + return nn.String() + "/" + itoa.Uitoa(uint(l)) } // Parse IPv4 address (d.d.d.d). diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go index 7a4b7a6041..8e984d5e5f 100644 --- a/src/net/ipsock_plan9.go +++ b/src/net/ipsock_plan9.go @@ -7,6 +7,7 @@ package net import ( "context" "internal/bytealg" + "internal/itoa" "io/fs" "os" "syscall" @@ -336,9 +337,9 @@ func plan9LocalAddr(addr Addr) string { if port == 0 { return "" } - return itoa(port) + return itoa.Itoa(port) } - return ip.String() + "!" + itoa(port) + return ip.String() + "!" + itoa.Itoa(port) } func hangupCtlWrite(ctx context.Context, proto string, ctl *os.File, msg string) error { diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go index 5fc23f098b..75c18b33ac 100644 --- a/src/net/lookup_plan9.go +++ b/src/net/lookup_plan9.go @@ -8,6 +8,7 @@ import ( "context" "errors" "internal/bytealg" + "internal/itoa" "io" "os" ) @@ -84,7 +85,7 @@ func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest str if len(ip) != 0 && !ip.IsUnspecified() { ips = ip.String() } - lines, err := queryCS(ctx, net, ips, itoa(port)) + lines, err := queryCS(ctx, net, ips, itoa.Itoa(port)) if err != nil { return } diff --git a/src/net/parse.go b/src/net/parse.go index cdb35bb826..6c230ab63f 100644 --- a/src/net/parse.go +++ b/src/net/parse.go @@ -172,32 +172,6 @@ func xtoi2(s string, e byte) (byte, bool) { return byte(n), ok && ei == 2 } -// Convert integer to decimal string. -func itoa(val int) string { - if val < 0 { - return "-" + uitoa(uint(-val)) - } - return uitoa(uint(val)) -} - -// Convert unsigned integer to decimal string. -func uitoa(val uint) string { - if val == 0 { // avoid string allocation - return "0" - } - var buf [20]byte // big enough for 64bit value base 10 - i := len(buf) - 1 - for val >= 10 { - q := val / 10 - buf[i] = byte('0' + val - q*10) - i-- - val = q - } - // val < 10 - buf[i] = byte('0' + val) - return string(buf[i:]) -} - // Convert i to a hexadecimal string. Leading zeros are not printed. func appendHex(dst []byte, i uint32) []byte { if i == 0 { diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go index 9a9b03a1e8..19a90143f3 100644 --- a/src/net/tcpsock.go +++ b/src/net/tcpsock.go @@ -6,6 +6,7 @@ package net import ( "context" + "internal/itoa" "io" "os" "syscall" @@ -31,9 +32,9 @@ func (a *TCPAddr) String() string { } ip := ipEmptyString(a.IP) if a.Zone != "" { - return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port)) + return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port)) } - return JoinHostPort(ip, itoa(a.Port)) + return JoinHostPort(ip, itoa.Itoa(a.Port)) } func (a *TCPAddr) isWildcard() bool { diff --git a/src/net/tcpsockopt_plan9.go b/src/net/tcpsockopt_plan9.go index fb56871857..264359dcf3 100644 --- a/src/net/tcpsockopt_plan9.go +++ b/src/net/tcpsockopt_plan9.go @@ -7,6 +7,7 @@ package net import ( + "internal/itoa" "syscall" "time" ) @@ -17,7 +18,7 @@ func setNoDelay(fd *netFD, noDelay bool) error { // Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - cmd := "keepalive " + itoa(int(d/time.Millisecond)) + cmd := "keepalive " + itoa.Itoa(int(d/time.Millisecond)) _, e := fd.ctl.WriteAt([]byte(cmd), 0) return e } diff --git a/src/net/udpsock.go b/src/net/udpsock.go index 571e099abd..bcd0e2763e 100644 --- a/src/net/udpsock.go +++ b/src/net/udpsock.go @@ -6,6 +6,7 @@ package net import ( "context" + "internal/itoa" "syscall" ) @@ -34,9 +35,9 @@ func (a *UDPAddr) String() string { } ip := ipEmptyString(a.IP) if a.Zone != "" { - return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port)) + return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port)) } - return JoinHostPort(ip, itoa(a.Port)) + return JoinHostPort(ip, itoa.Itoa(a.Port)) } func (a *UDPAddr) isWildcard() bool { diff --git a/src/os/exec_plan9.go b/src/os/exec_plan9.go index 8580153911..cc84f97669 100644 --- a/src/os/exec_plan9.go +++ b/src/os/exec_plan9.go @@ -5,6 +5,7 @@ package os import ( + "internal/itoa" "runtime" "syscall" "time" @@ -40,7 +41,7 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e } func (p *Process) writeProcFile(file string, data string) error { - f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0) + f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) if e != nil { return e } diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go index 443d4e0218..e8736f7c54 100644 --- a/src/os/exec_posix.go +++ b/src/os/exec_posix.go @@ -8,6 +8,7 @@ package os import ( + "internal/itoa" "internal/syscall/execenv" "runtime" "syscall" @@ -107,14 +108,14 @@ func (p *ProcessState) String() string { if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers res = "exit status " + uitox(uint(code)) } else { // unix systems use small decimal integers - res = "exit status " + itoa(code) // unix + res = "exit status " + itoa.Itoa(code) // unix } case status.Signaled(): res = "signal: " + status.Signal().String() case status.Stopped(): res = "stop signal: " + status.StopSignal().String() if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { - res += " (trap " + itoa(status.TrapCause()) + ")" + res += " (trap " + itoa.Itoa(status.TrapCause()) + ")" } case status.Continued(): res = "continued" diff --git a/src/os/executable_plan9.go b/src/os/executable_plan9.go index 105c03f0c1..ad7a4410dc 100644 --- a/src/os/executable_plan9.go +++ b/src/os/executable_plan9.go @@ -7,10 +7,13 @@ package os -import "syscall" +import ( + "internal/itoa" + "syscall" +) func executable() (string, error) { - fn := "/proc/" + itoa(Getpid()) + "/text" + fn := "/proc/" + itoa.Itoa(Getpid()) + "/text" f, err := Open(fn) if err != nil { return "", err diff --git a/src/os/signal/signal_plan9_test.go b/src/os/signal/signal_plan9_test.go index 10bfdc3ff1..8357199aa4 100644 --- a/src/os/signal/signal_plan9_test.go +++ b/src/os/signal/signal_plan9_test.go @@ -5,6 +5,7 @@ package signal import ( + "internal/itoa" "os" "runtime" "syscall" @@ -155,23 +156,8 @@ func TestStop(t *testing.T) { } } -func itoa(val int) string { - if val < 0 { - return "-" + itoa(-val) - } - var buf [32]byte // big enough for int64 - i := len(buf) - 1 - for val >= 10 { - buf[i] = byte(val%10 + '0') - i-- - val /= 10 - } - buf[i] = byte(val + '0') - return string(buf[i:]) -} - func postNote(pid int, note string) error { - f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0) + f, err := os.OpenFile("/proc/"+itoa.Itoa(pid)+"/note", os.O_WRONLY, 0) if err != nil { return err } diff --git a/src/os/str.go b/src/os/str.go index 9bfcc15aa8..35643e0d2f 100644 --- a/src/os/str.go +++ b/src/os/str.go @@ -6,32 +6,6 @@ package os -// itoa converts val (an int) to a decimal string. -func itoa(val int) string { - if val < 0 { - return "-" + uitoa(uint(-val)) - } - return uitoa(uint(val)) -} - -// uitoa converts val (a uint) to a decimal string. -func uitoa(val uint) string { - if val == 0 { // avoid string allocation - return "0" - } - var buf [20]byte // big enough for 64bit value base 10 - i := len(buf) - 1 - for val >= 10 { - q := val / 10 - buf[i] = byte('0' + val - q*10) - i-- - val = q - } - // val < 10 - buf[i] = byte('0' + val) - return string(buf[i:]) -} - // itox converts val (an int) to a hexdecimal string. func itox(val int) string { if val < 0 { diff --git a/src/os/tempfile.go b/src/os/tempfile.go index 1ad44f1163..5b681fcebf 100644 --- a/src/os/tempfile.go +++ b/src/os/tempfile.go @@ -4,7 +4,10 @@ package os -import "errors" +import ( + "errors" + "internal/itoa" +) // fastrand provided by runtime. // We generate random temporary file names so that there's a good @@ -13,7 +16,7 @@ import "errors" func fastrand() uint32 func nextRandom() string { - return uitoa(uint(fastrand())) + return itoa.Uitoa(uint(fastrand())) } // CreateTemp creates a new temporary file in the directory dir, diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go index d99da00089..16210ca5b5 100644 --- a/src/syscall/dll_windows.go +++ b/src/syscall/dll_windows.go @@ -5,6 +5,7 @@ package syscall import ( + "internal/itoa" "internal/syscall/windows/sysdll" "sync" "sync/atomic" @@ -215,7 +216,7 @@ func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { case 18: return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17]) default: - panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") + panic("Call " + p.Name + " with too many arguments " + itoa.Itoa(len(a)) + ".") } } diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 6353da4048..deb8aa38b7 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -8,6 +8,7 @@ package syscall import ( + "internal/itoa" "runtime" "unsafe" ) @@ -568,7 +569,7 @@ func forkExecPipe(p []int) (err error) { func formatIDMappings(idMap []SysProcIDMap) []byte { var data []byte for _, im := range idMap { - data = append(data, []byte(itoa(im.ContainerID)+" "+itoa(im.HostID)+" "+itoa(im.Size)+"\n")...) + data = append(data, []byte(itoa.Itoa(im.ContainerID)+" "+itoa.Itoa(im.HostID)+" "+itoa.Itoa(im.Size)+"\n")...) } return data } @@ -597,7 +598,7 @@ func writeIDMappings(path string, idMap []SysProcIDMap) error { // This is needed since kernel 3.19, because you can't write gid_map without // disabling setgroups() system call. func writeSetgroups(pid int, enable bool) error { - sgf := "/proc/" + itoa(pid) + "/setgroups" + sgf := "/proc/" + itoa.Itoa(pid) + "/setgroups" fd, err := Open(sgf, O_RDWR, 0) if err != nil { return err @@ -622,7 +623,7 @@ func writeSetgroups(pid int, enable bool) error { // for a process and it is called from the parent process. func writeUidGidMappings(pid int, sys *SysProcAttr) error { if sys.UidMappings != nil { - uidf := "/proc/" + itoa(pid) + "/uid_map" + uidf := "/proc/" + itoa.Itoa(pid) + "/uid_map" if err := writeIDMappings(uidf, sys.UidMappings); err != nil { return err } @@ -633,7 +634,7 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error { if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT { return err } - gidf := "/proc/" + itoa(pid) + "/gid_map" + gidf := "/proc/" + itoa.Itoa(pid) + "/gid_map" if err := writeIDMappings(gidf, sys.GidMappings); err != nil { return err } diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go index 12c4237f69..c469fe1812 100644 --- a/src/syscall/exec_plan9.go +++ b/src/syscall/exec_plan9.go @@ -7,6 +7,7 @@ package syscall import ( + "internal/itoa" "runtime" "sync" "unsafe" @@ -320,7 +321,7 @@ func cexecPipe(p []int) error { return e } - fd, e := Open("#d/"+itoa(p[1]), O_RDWR|O_CLOEXEC) + fd, e := Open("#d/"+itoa.Itoa(p[1]), O_RDWR|O_CLOEXEC) if e != nil { Close(p[0]) Close(p[1]) diff --git a/src/syscall/export_test.go b/src/syscall/export_test.go deleted file mode 100644 index 55c09e667e..0000000000 --- a/src/syscall/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2014 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 - -var Itoa = itoa diff --git a/src/syscall/str.go b/src/syscall/str.go deleted file mode 100644 index 2ddf04b227..0000000000 --- a/src/syscall/str.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 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 itoa(val int) string { // do it here rather than with fmt to avoid dependency - if val < 0 { - return "-" + uitoa(uint(-val)) - } - return uitoa(uint(val)) -} - -func uitoa(val uint) string { - var buf [32]byte // big enough for int64 - i := len(buf) - 1 - for val >= 10 { - buf[i] = byte(val%10 + '0') - i-- - val /= 10 - } - buf[i] = byte(val + '0') - return string(buf[i:]) -} diff --git a/src/syscall/syscall_js.go b/src/syscall/syscall_js.go index c17c6fcdcf..ed70d62284 100644 --- a/src/syscall/syscall_js.go +++ b/src/syscall/syscall_js.go @@ -8,6 +8,7 @@ package syscall import ( + "internal/itoa" "internal/oserror" "sync" "unsafe" @@ -60,7 +61,7 @@ func (e Errno) Error() string { return s } } - return "errno " + itoa(int(e)) + return "errno " + itoa.Itoa(int(e)) } func (e Errno) Is(target error) bool { @@ -106,7 +107,7 @@ func (s Signal) String() string { return str } } - return "signal " + itoa(int(s)) + return "signal " + itoa.Itoa(int(s)) } var signals = [...]string{} diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 3041f6f8fc..24e051dcbd 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -11,7 +11,10 @@ package syscall -import "unsafe" +import ( + "internal/itoa" + "unsafe" +) func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) @@ -225,7 +228,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) { func Futimes(fd int, tv []Timeval) (err error) { // Believe it or not, this is the best we can do on Linux // (and is what glibc does). - return Utimes("/proc/self/fd/"+itoa(fd), tv) + return Utimes("/proc/self/fd/"+itoa.Itoa(fd), tv) } const ImplementsGetwd = true diff --git a/src/syscall/syscall_test.go b/src/syscall/syscall_test.go index 5390f8aace..b2b9463b0f 100644 --- a/src/syscall/syscall_test.go +++ b/src/syscall/syscall_test.go @@ -5,7 +5,6 @@ package syscall_test import ( - "fmt" "internal/testenv" "os" "runtime" @@ -33,22 +32,6 @@ func TestEnv(t *testing.T) { testSetGetenv(t, "TESTENV", "") } -func TestItoa(t *testing.T) { - // Make most negative integer: 0x8000... - i := 1 - for i<<1 != 0 { - i <<= 1 - } - if i >= 0 { - t.Fatal("bad math") - } - s := syscall.Itoa(i) - f := fmt.Sprint(i) - if s != f { - t.Fatalf("itoa(%d) = %s, want %s", i, s, f) - } -} - // Check that permuting child process fds doesn't interfere with // reporting of fork/exec status. See Issue 14979. func TestExecErrPermutedFds(t *testing.T) { diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index 40fc8b8a30..5b405b99b4 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -8,6 +8,7 @@ package syscall import ( + "internal/itoa" "internal/oserror" "internal/race" "internal/unsafeheader" @@ -121,7 +122,7 @@ func (e Errno) Error() string { return s } } - return "errno " + itoa(int(e)) + return "errno " + itoa.Itoa(int(e)) } func (e Errno) Is(target error) bool { @@ -181,7 +182,7 @@ func (s Signal) String() string { return str } } - return "signal " + itoa(int(s)) + return "signal " + itoa.Itoa(int(s)) } func Read(fd int, p []byte) (n int, err error) { diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 65af6637ae..f9f78bd2b3 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -8,6 +8,7 @@ package syscall import ( errorspkg "errors" + "internal/itoa" "internal/oserror" "internal/race" "internal/unsafeheader" @@ -132,7 +133,7 @@ func (e Errno) Error() string { if err != nil { n, err = formatMessage(flags, 0, uint32(e), 0, b, nil) if err != nil { - return "winapi error #" + itoa(int(e)) + return "winapi error #" + itoa.Itoa(int(e)) } } // trim terminating \r and \n @@ -1152,7 +1153,7 @@ func (s Signal) String() string { return str } } - return "signal " + itoa(int(s)) + return "signal " + itoa.Itoa(int(s)) } func LoadCreateSymbolicLink() error { -- GitLab From a8b59fe3cdaeeb40c87d55122a45a2e390e60d88 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki Date: Sun, 14 Mar 2021 18:12:59 +0200 Subject: [PATCH 0336/1298] encoding/json: fix package shadowing in MarshalIndent example Prior to this CL, pasting the example from the website causes a compilation error for some programs because it was shadowing the "json" package. Change-Id: I39b68a66ca99468547f2027a7655cf1387b61e95 Reviewed-on: https://go-review.googlesource.com/c/go/+/301492 Reviewed-by: Joe Tsai Reviewed-by: Ian Lance Taylor Trust: Joe Tsai Run-TryBot: Joe Tsai TryBot-Result: Go Bot --- src/encoding/json/example_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go index 2088c34297..fbecf1b593 100644 --- a/src/encoding/json/example_test.go +++ b/src/encoding/json/example_test.go @@ -279,12 +279,12 @@ func ExampleMarshalIndent() { "b": 2, } - json, err := json.MarshalIndent(data, "", "") + b, err := json.MarshalIndent(data, "", "") if err != nil { log.Fatal(err) } - fmt.Println(string(json)) + fmt.Println(string(b)) // Output: // { // "a": 1, -- GitLab From 3cdd5c3bcc53298dd7de39cb6e2bd600308988b8 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Thu, 12 Nov 2020 16:02:55 +0100 Subject: [PATCH 0337/1298] cmd/link: regression test for issue #42484 Adds test to check that the compiler does not emit duplicate debug_line entries for the end of sequence address. Updates #42484 Change-Id: I3c5d1d606fcfd758aa1fd83ecc51d8edc054398b Reviewed-on: https://go-review.googlesource.com/c/go/+/270197 TryBot-Result: Go Bot Run-TryBot: Emmanuel Odeke Trust: Emmanuel Odeke Reviewed-by: Than McIntosh --- src/cmd/link/internal/ld/dwarf_test.go | 71 +++++++++++++++++++ .../internal/ld/testdata/issue42484/main.go | 16 +++++ 2 files changed, 87 insertions(+) create mode 100644 src/cmd/link/internal/ld/testdata/issue42484/main.go diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index f5f2258451..5e4151885a 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -1570,3 +1570,74 @@ func TestIssue39757(t *testing.T) { } } } + +func TestIssue42484(t *testing.T) { + testenv.MustHaveGoBuild(t) + + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; no DWARF symbol table in executables") + } + + t.Parallel() + + tmpdir, err := ioutil.TempDir("", "TestIssue42484") + if err != nil { + t.Fatalf("could not create directory: %v", err) + } + defer os.RemoveAll(tmpdir) + wd, err := os.Getwd() + if err != nil { + t.Fatalf("where am I? %v", err) + } + pdir := filepath.Join(wd, "testdata", "issue42484") + f := gobuildTestdata(t, tmpdir, pdir, NoOpt) + + var lastAddr uint64 + var lastFile string + var lastLine int + + dw, err := f.DWARF() + if err != nil { + t.Fatalf("error parsing DWARF: %v", err) + } + rdr := dw.Reader() + for { + e, err := rdr.Next() + if err != nil { + t.Fatalf("error reading DWARF: %v", err) + } + if e == nil { + break + } + if e.Tag != dwarf.TagCompileUnit { + continue + } + lnrdr, err := dw.LineReader(e) + if err != nil { + t.Fatalf("error creating DWARF line reader: %v", err) + } + if lnrdr != nil { + var lne dwarf.LineEntry + for { + err := lnrdr.Next(&lne) + if err == io.EOF { + break + } + if err != nil { + t.Fatalf("error reading next DWARF line: %v", err) + } + if lne.EndSequence { + continue + } + if lne.Address == lastAddr && (lne.File.Name != lastFile || lne.Line != lastLine) { + t.Errorf("address %#x is assigned to both %s:%d and %s:%d", lastAddr, lastFile, lastLine, lne.File.Name, lne.Line) + } + lastAddr = lne.Address + lastFile = lne.File.Name + lastLine = lne.Line + } + } + rdr.SkipChildren() + } + f.Close() +} diff --git a/src/cmd/link/internal/ld/testdata/issue42484/main.go b/src/cmd/link/internal/ld/testdata/issue42484/main.go new file mode 100644 index 0000000000..60fc110ffa --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue42484/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" +) + +func main() { + a := 0 + a++ + b := 0 + f1(a, b) +} + +func f1(a, b int) { + fmt.Printf("%d %d\n", a, b) +} -- GitLab From d0d38f0f707e69965a5f5a637fa568c646899d39 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 14 Mar 2021 14:27:06 -0700 Subject: [PATCH 0338/1298] cmd/compile: fix whitespace in comment The whitespace was there to align with the following comment, but the extra whitespace was unnecessary; it wasn't gofmt'd. Then the file got gofmt'd, but the whitespace didn't get fixed. Change-Id: I45aad9605b99d83545e4e611ae3ea1b2ff9e6bf6 Reviewed-on: https://go-review.googlesource.com/c/go/+/301649 Trust: Josh Bleecher Snyder Run-TryBot: Josh Bleecher Snyder Reviewed-by: Emmanuel Odeke --- src/cmd/compile/internal/ssa/gen/genericOps.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 2a5b77bad0..85c58ef74c 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -264,7 +264,7 @@ var genericOps = []opData{ // ±0 → ±0 (sign preserved) // x<0 → NaN // NaN → NaN - {name: "Sqrt", argLength: 1}, // √arg0 (floating point, double precision) + {name: "Sqrt", argLength: 1}, // √arg0 (floating point, double precision) {name: "Sqrt32", argLength: 1}, // √arg0 (floating point, single precision) // Round to integer, float64 only. -- GitLab From 6ccb5c49cca52766f6d288d128db67be6392c579 Mon Sep 17 00:00:00 2001 From: Tao Qingyun Date: Sun, 14 Mar 2021 00:09:05 +0000 Subject: [PATCH 0339/1298] cmd/link/internal/ld: fix typo in a comment Change-Id: I9ae39aa2da2bfa6bb5d3f279bca764128d9cc401 GitHub-Last-Rev: 7a5945ae120b911793a1510f371945ac17611440 GitHub-Pull-Request: golang/go#44990 Reviewed-on: https://go-review.googlesource.com/c/go/+/301529 Reviewed-by: Matthew Dempsky Trust: Tobias Klauser --- src/cmd/link/internal/ld/deadcode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index ea98fea4e5..a52652566b 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -118,7 +118,7 @@ func (d *deadcodePass) flood() { if isgotype { if d.dynlink { - // When dynaamic linking, a type may be passed across DSO + // When dynamic linking, a type may be passed across DSO // boundary and get converted to interface at the other side. d.ldr.SetAttrUsedInIface(symIdx, true) } -- GitLab From 4350e4961a6ea3d36a33271423735b37c96dd5bf Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Wed, 10 Mar 2021 17:06:54 -0600 Subject: [PATCH 0340/1298] crypto/md5: improve ppc64x performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mostly cleanup and simplification. This removes many unneeded register moves, loads, and bit twiddlings which were holdovers from porting this from the amd64 version. The updated code loads each block once per iteration instead of once per round. Similarly, the logical operations now match the original md5 specification. Likewise, add extra sizes to the benchtest to give more data points on how the implementation scales with input size. All in all, this is roughly a 20% improvement on ppc64le code running on POWER9 (POWER8 is similar, but around 16%): name old time/op new time/op delta Hash8Bytes 297ns ± 0% 255ns ± 0% -14.14% Hash64 527ns ± 0% 444ns ± 0% -15.76% Hash128 771ns ± 0% 645ns ± 0% -16.35% Hash256 1.26µs ± 0% 1.05µs ± 0% -16.68% Hash512 2.23µs ± 0% 1.85µs ± 0% -16.82% Hash1K 4.16µs ± 0% 3.46µs ± 0% -16.83% Hash8K 31.2µs ± 0% 26.0µs ± 0% -16.74% Hash1M 3.58ms ± 0% 2.98ms ± 0% -16.74% Hash8M 26.1ms ± 0% 21.7ms ± 0% -16.81% Hash8BytesUnaligned 297ns ± 0% 255ns ± 0% -14.08% Hash1KUnaligned 4.16µs ± 0% 3.46µs ± 0% -16.79% Hash8KUnaligned 31.2µs ± 0% 26.0µs ± 0% -16.78% name old speed new speed delta Hash8Bytes 26.9MB/s ± 0% 31.4MB/s ± 0% +16.45% Hash64 122MB/s ± 0% 144MB/s ± 0% +18.69% Hash128 166MB/s ± 0% 199MB/s ± 0% +19.54% Hash256 203MB/s ± 0% 244MB/s ± 0% +20.01% Hash512 230MB/s ± 0% 276MB/s ± 0% +20.18% Hash1K 246MB/s ± 0% 296MB/s ± 0% +20.26% Hash8K 263MB/s ± 0% 315MB/s ± 0% +20.11% Hash1M 293MB/s ± 0% 352MB/s ± 0% +20.10% Hash8M 321MB/s ± 0% 386MB/s ± 0% +20.21% Hash8BytesUnaligned 26.9MB/s ± 0% 31.4MB/s ± 0% +16.41% Hash1KUnaligned 246MB/s ± 0% 296MB/s ± 0% +20.19% Hash8KUnaligned 263MB/s ± 0% 315MB/s ± 0% +20.15% Change-Id: I269bfa6878966bb4f6a64dc349100f5dc453ab7c Reviewed-on: https://go-review.googlesource.com/c/go/+/300613 Run-TryBot: Paul Murphy Reviewed-by: Lynn Boger TryBot-Result: Go Bot Trust: Emmanuel Odeke --- src/crypto/md5/md5_test.go | 26 ++- src/crypto/md5/md5block_ppc64x.s | 303 ++++++++++++++++--------------- 2 files changed, 182 insertions(+), 147 deletions(-) diff --git a/src/crypto/md5/md5_test.go b/src/crypto/md5/md5_test.go index c0ac0971c4..acd456af21 100644 --- a/src/crypto/md5/md5_test.go +++ b/src/crypto/md5/md5_test.go @@ -212,7 +212,7 @@ func TestLargeHashes(t *testing.T) { } var bench = New() -var buf = make([]byte, 8192+1) +var buf = make([]byte, 1024*1024*8+1) var sum = make([]byte, bench.Size()) func benchmarkSize(b *testing.B, size int, unaligned bool) { @@ -235,6 +235,22 @@ func BenchmarkHash8Bytes(b *testing.B) { benchmarkSize(b, 8, false) } +func BenchmarkHash64(b *testing.B) { + benchmarkSize(b, 64, false) +} + +func BenchmarkHash128(b *testing.B) { + benchmarkSize(b, 128, false) +} + +func BenchmarkHash256(b *testing.B) { + benchmarkSize(b, 256, false) +} + +func BenchmarkHash512(b *testing.B) { + benchmarkSize(b, 512, false) +} + func BenchmarkHash1K(b *testing.B) { benchmarkSize(b, 1024, false) } @@ -243,6 +259,14 @@ func BenchmarkHash8K(b *testing.B) { benchmarkSize(b, 8192, false) } +func BenchmarkHash1M(b *testing.B) { + benchmarkSize(b, 1024*1024, false) +} + +func BenchmarkHash8M(b *testing.B) { + benchmarkSize(b, 8*1024*1024, false) +} + func BenchmarkHash8BytesUnaligned(b *testing.B) { benchmarkSize(b, 8, true) } diff --git a/src/crypto/md5/md5block_ppc64x.s b/src/crypto/md5/md5block_ppc64x.s index f309a1413d..e1f859e337 100644 --- a/src/crypto/md5/md5block_ppc64x.s +++ b/src/crypto/md5/md5block_ppc64x.s @@ -28,169 +28,179 @@ MOVWBR (idx)(ptr), dst #endif -TEXT ·block(SB),NOSPLIT,$0-32 - MOVD dig+0(FP), R10 - MOVD p+8(FP), R6 - MOVD p_len+16(FP), R5 - SLD $6, R5 - SRD $6, R5 - ADD R6, R5, R7 - - MOVWZ 0(R10), R22 - MOVWZ 4(R10), R3 - MOVWZ 8(R10), R4 - MOVWZ 12(R10), R5 - CMP R6, R7 - BEQ end - -loop: - MOVWZ R22, R14 - MOVWZ R3, R15 - MOVWZ R4, R16 - MOVWZ R5, R17 - - ENDIAN_MOVE(0,R6,R8,R21) - MOVWZ R5, R9 +#define M00 R18 +#define M01 R19 +#define M02 R20 +#define M03 R24 +#define M04 R25 +#define M05 R26 +#define M06 R27 +#define M07 R28 +#define M08 R29 +#define M09 R21 +#define M10 R11 +#define M11 R8 +#define M12 R7 +#define M13 R12 +#define M14 R23 +#define M15 R10 #define ROUND1(a, b, c, d, index, const, shift) \ - XOR c, R9; \ - ADD $const, a; \ - ADD R8, a; \ - AND b, R9; \ - XOR d, R9; \ - ENDIAN_MOVE(index*4,R6,R8,R21); \ + ADD $const, index, R9; \ ADD R9, a; \ - RLWMI $shift, a, $0xffffffff, a; \ - MOVWZ c, R9; \ - ADD b, a; \ - MOVWZ a, a - - ROUND1(R22,R3,R4,R5, 1,0xd76aa478, 7); - ROUND1(R5,R22,R3,R4, 2,0xe8c7b756,12); - ROUND1(R4,R5,R22,R3, 3,0x242070db,17); - ROUND1(R3,R4,R5,R22, 4,0xc1bdceee,22); - ROUND1(R22,R3,R4,R5, 5,0xf57c0faf, 7); - ROUND1(R5,R22,R3,R4, 6,0x4787c62a,12); - ROUND1(R4,R5,R22,R3, 7,0xa8304613,17); - ROUND1(R3,R4,R5,R22, 8,0xfd469501,22); - ROUND1(R22,R3,R4,R5, 9,0x698098d8, 7); - ROUND1(R5,R22,R3,R4,10,0x8b44f7af,12); - ROUND1(R4,R5,R22,R3,11,0xffff5bb1,17); - ROUND1(R3,R4,R5,R22,12,0x895cd7be,22); - ROUND1(R22,R3,R4,R5,13,0x6b901122, 7); - ROUND1(R5,R22,R3,R4,14,0xfd987193,12); - ROUND1(R4,R5,R22,R3,15,0xa679438e,17); - ROUND1(R3,R4,R5,R22, 0,0x49b40821,22); - - ENDIAN_MOVE(1*4,R6,R8,R21) - MOVWZ R5, R9 - MOVWZ R5, R10 + AND b, c, R9; \ + ANDN b, d, R31; \ + OR R9, R31, R9; \ + ADD R9, a; \ + ROTLW $shift, a; \ + ADD b, a; #define ROUND2(a, b, c, d, index, const, shift) \ - XOR $0xffffffff, R9; \ // NOTW R9 - ADD $const, a; \ - ADD R8, a; \ - AND b, R10; \ - AND c, R9; \ - ENDIAN_MOVE(index*4,R6,R8,R21); \ - OR R9, R10; \ - MOVWZ c, R9; \ - ADD R10, a; \ - MOVWZ c, R10; \ - RLWMI $shift, a, $0xffffffff, a; \ - ADD b, a; \ - MOVWZ a, a - - ROUND2(R22,R3,R4,R5, 6,0xf61e2562, 5); - ROUND2(R5,R22,R3,R4,11,0xc040b340, 9); - ROUND2(R4,R5,R22,R3, 0,0x265e5a51,14); - ROUND2(R3,R4,R5,R22, 5,0xe9b6c7aa,20); - ROUND2(R22,R3,R4,R5,10,0xd62f105d, 5); - ROUND2(R5,R22,R3,R4,15, 0x2441453, 9); - ROUND2(R4,R5,R22,R3, 4,0xd8a1e681,14); - ROUND2(R3,R4,R5,R22, 9,0xe7d3fbc8,20); - ROUND2(R22,R3,R4,R5,14,0x21e1cde6, 5); - ROUND2(R5,R22,R3,R4, 3,0xc33707d6, 9); - ROUND2(R4,R5,R22,R3, 8,0xf4d50d87,14); - ROUND2(R3,R4,R5,R22,13,0x455a14ed,20); - ROUND2(R22,R3,R4,R5, 2,0xa9e3e905, 5); - ROUND2(R5,R22,R3,R4, 7,0xfcefa3f8, 9); - ROUND2(R4,R5,R22,R3,12,0x676f02d9,14); - ROUND2(R3,R4,R5,R22, 0,0x8d2a4c8a,20); - - ENDIAN_MOVE(5*4,R6,R8,R21) - MOVWZ R4, R9 + ADD $const, index, R9; \ + ADD R9, a; \ + AND b, d, R31; \ + ANDN d, c, R9; \ + OR R9, R31; \ + ADD R31, a; \ + ROTLW $shift, a; \ + ADD b, a; #define ROUND3(a, b, c, d, index, const, shift) \ - ADD $const, a; \ - ADD R8, a; \ - ENDIAN_MOVE(index*4,R6,R8,R21); \ - XOR d, R9; \ - XOR b, R9; \ + ADD $const, index, R9; \ ADD R9, a; \ - RLWMI $shift, a, $0xffffffff, a; \ - MOVWZ b, R9; \ - ADD b, a; \ - MOVWZ a, a - - ROUND3(R22,R3,R4,R5, 8,0xfffa3942, 4); - ROUND3(R5,R22,R3,R4,11,0x8771f681,11); - ROUND3(R4,R5,R22,R3,14,0x6d9d6122,16); - ROUND3(R3,R4,R5,R22, 1,0xfde5380c,23); - ROUND3(R22,R3,R4,R5, 4,0xa4beea44, 4); - ROUND3(R5,R22,R3,R4, 7,0x4bdecfa9,11); - ROUND3(R4,R5,R22,R3,10,0xf6bb4b60,16); - ROUND3(R3,R4,R5,R22,13,0xbebfbc70,23); - ROUND3(R22,R3,R4,R5, 0,0x289b7ec6, 4); - ROUND3(R5,R22,R3,R4, 3,0xeaa127fa,11); - ROUND3(R4,R5,R22,R3, 6,0xd4ef3085,16); - ROUND3(R3,R4,R5,R22, 9, 0x4881d05,23); - ROUND3(R22,R3,R4,R5,12,0xd9d4d039, 4); - ROUND3(R5,R22,R3,R4,15,0xe6db99e5,11); - ROUND3(R4,R5,R22,R3, 2,0x1fa27cf8,16); - ROUND3(R3,R4,R5,R22, 0,0xc4ac5665,23); - - ENDIAN_MOVE(0,R6,R8,R21) - MOVWZ $0xffffffff, R9 - XOR R5, R9 + XOR d, c, R31; \ + XOR b, R31; \ + ADD R31, a; \ + ROTLW $shift, a; \ + ADD b, a; #define ROUND4(a, b, c, d, index, const, shift) \ - ADD $const, a; \ - ADD R8, a; \ - OR b, R9; \ - XOR c, R9; \ + ADD $const, index, R9; \ ADD R9, a; \ - ENDIAN_MOVE(index*4,R6,R8,R21); \ - MOVWZ $0xffffffff, R9; \ - RLWMI $shift, a, $0xffffffff, a; \ - XOR c, R9; \ - ADD b, a; \ - MOVWZ a, a - - ROUND4(R22,R3,R4,R5, 7,0xf4292244, 6); - ROUND4(R5,R22,R3,R4,14,0x432aff97,10); - ROUND4(R4,R5,R22,R3, 5,0xab9423a7,15); - ROUND4(R3,R4,R5,R22,12,0xfc93a039,21); - ROUND4(R22,R3,R4,R5, 3,0x655b59c3, 6); - ROUND4(R5,R22,R3,R4,10,0x8f0ccc92,10); - ROUND4(R4,R5,R22,R3, 1,0xffeff47d,15); - ROUND4(R3,R4,R5,R22, 8,0x85845dd1,21); - ROUND4(R22,R3,R4,R5,15,0x6fa87e4f, 6); - ROUND4(R5,R22,R3,R4, 6,0xfe2ce6e0,10); - ROUND4(R4,R5,R22,R3,13,0xa3014314,15); - ROUND4(R3,R4,R5,R22, 4,0x4e0811a1,21); - ROUND4(R22,R3,R4,R5,11,0xf7537e82, 6); - ROUND4(R5,R22,R3,R4, 2,0xbd3af235,10); - ROUND4(R4,R5,R22,R3, 9,0x2ad7d2bb,15); - ROUND4(R3,R4,R5,R22, 0,0xeb86d391,21); + ORN d, b, R31; \ + XOR c, R31; \ + ADD R31, a; \ + ROTLW $shift, a; \ + ADD b, a; + + +TEXT ·block(SB),NOSPLIT,$0-32 + MOVD dig+0(FP), R10 + MOVD p+8(FP), R6 + MOVD p_len+16(FP), R5 + + // We assume p_len >= 64 + SRD $6, R5 + MOVD R5, CTR + + MOVWZ 0(R10), R22 + MOVWZ 4(R10), R3 + MOVWZ 8(R10), R4 + MOVWZ 12(R10), R5 + +loop: + MOVD R22, R14 + MOVD R3, R15 + MOVD R4, R16 + MOVD R5, R17 + + ENDIAN_MOVE( 0,R6,M00,M15) + ENDIAN_MOVE( 4,R6,M01,M15) + ENDIAN_MOVE( 8,R6,M02,M15) + ENDIAN_MOVE(12,R6,M03,M15) + + ROUND1(R22,R3,R4,R5,M00,0xd76aa478, 7); + ROUND1(R5,R22,R3,R4,M01,0xe8c7b756,12); + ROUND1(R4,R5,R22,R3,M02,0x242070db,17); + ROUND1(R3,R4,R5,R22,M03,0xc1bdceee,22); + + ENDIAN_MOVE(16,R6,M04,M15) + ENDIAN_MOVE(20,R6,M05,M15) + ENDIAN_MOVE(24,R6,M06,M15) + ENDIAN_MOVE(28,R6,M07,M15) + + ROUND1(R22,R3,R4,R5,M04,0xf57c0faf, 7); + ROUND1(R5,R22,R3,R4,M05,0x4787c62a,12); + ROUND1(R4,R5,R22,R3,M06,0xa8304613,17); + ROUND1(R3,R4,R5,R22,M07,0xfd469501,22); + + ENDIAN_MOVE(32,R6,M08,M15) + ENDIAN_MOVE(36,R6,M09,M15) + ENDIAN_MOVE(40,R6,M10,M15) + ENDIAN_MOVE(44,R6,M11,M15) + + ROUND1(R22,R3,R4,R5,M08,0x698098d8, 7); + ROUND1(R5,R22,R3,R4,M09,0x8b44f7af,12); + ROUND1(R4,R5,R22,R3,M10,0xffff5bb1,17); + ROUND1(R3,R4,R5,R22,M11,0x895cd7be,22); + + ENDIAN_MOVE(48,R6,M12,M15) + ENDIAN_MOVE(52,R6,M13,M15) + ENDIAN_MOVE(56,R6,M14,M15) + ENDIAN_MOVE(60,R6,M15,M15) + + ROUND1(R22,R3,R4,R5,M12,0x6b901122, 7); + ROUND1(R5,R22,R3,R4,M13,0xfd987193,12); + ROUND1(R4,R5,R22,R3,M14,0xa679438e,17); + ROUND1(R3,R4,R5,R22,M15,0x49b40821,22); + + ROUND2(R22,R3,R4,R5,M01,0xf61e2562, 5); + ROUND2(R5,R22,R3,R4,M06,0xc040b340, 9); + ROUND2(R4,R5,R22,R3,M11,0x265e5a51,14); + ROUND2(R3,R4,R5,R22,M00,0xe9b6c7aa,20); + ROUND2(R22,R3,R4,R5,M05,0xd62f105d, 5); + ROUND2(R5,R22,R3,R4,M10, 0x2441453, 9); + ROUND2(R4,R5,R22,R3,M15,0xd8a1e681,14); + ROUND2(R3,R4,R5,R22,M04,0xe7d3fbc8,20); + ROUND2(R22,R3,R4,R5,M09,0x21e1cde6, 5); + ROUND2(R5,R22,R3,R4,M14,0xc33707d6, 9); + ROUND2(R4,R5,R22,R3,M03,0xf4d50d87,14); + ROUND2(R3,R4,R5,R22,M08,0x455a14ed,20); + ROUND2(R22,R3,R4,R5,M13,0xa9e3e905, 5); + ROUND2(R5,R22,R3,R4,M02,0xfcefa3f8, 9); + ROUND2(R4,R5,R22,R3,M07,0x676f02d9,14); + ROUND2(R3,R4,R5,R22,M12,0x8d2a4c8a,20); + + ROUND3(R22,R3,R4,R5,M05,0xfffa3942, 4); + ROUND3(R5,R22,R3,R4,M08,0x8771f681,11); + ROUND3(R4,R5,R22,R3,M11,0x6d9d6122,16); + ROUND3(R3,R4,R5,R22,M14,0xfde5380c,23); + ROUND3(R22,R3,R4,R5,M01,0xa4beea44, 4); + ROUND3(R5,R22,R3,R4,M04,0x4bdecfa9,11); + ROUND3(R4,R5,R22,R3,M07,0xf6bb4b60,16); + ROUND3(R3,R4,R5,R22,M10,0xbebfbc70,23); + ROUND3(R22,R3,R4,R5,M13,0x289b7ec6, 4); + ROUND3(R5,R22,R3,R4,M00,0xeaa127fa,11); + ROUND3(R4,R5,R22,R3,M03,0xd4ef3085,16); + ROUND3(R3,R4,R5,R22,M06, 0x4881d05,23); + ROUND3(R22,R3,R4,R5,M09,0xd9d4d039, 4); + ROUND3(R5,R22,R3,R4,M12,0xe6db99e5,11); + ROUND3(R4,R5,R22,R3,M15,0x1fa27cf8,16); + ROUND3(R3,R4,R5,R22,M02,0xc4ac5665,23); + + ROUND4(R22,R3,R4,R5,M00,0xf4292244, 6); + ROUND4(R5,R22,R3,R4,M07,0x432aff97,10); + ROUND4(R4,R5,R22,R3,M14,0xab9423a7,15); + ROUND4(R3,R4,R5,R22,M05,0xfc93a039,21); + ROUND4(R22,R3,R4,R5,M12,0x655b59c3, 6); + ROUND4(R5,R22,R3,R4,M03,0x8f0ccc92,10); + ROUND4(R4,R5,R22,R3,M10,0xffeff47d,15); + ROUND4(R3,R4,R5,R22,M01,0x85845dd1,21); + ROUND4(R22,R3,R4,R5,M08,0x6fa87e4f, 6); + ROUND4(R5,R22,R3,R4,M15,0xfe2ce6e0,10); + ROUND4(R4,R5,R22,R3,M06,0xa3014314,15); + ROUND4(R3,R4,R5,R22,M13,0x4e0811a1,21); + ROUND4(R22,R3,R4,R5,M04,0xf7537e82, 6); + ROUND4(R5,R22,R3,R4,M11,0xbd3af235,10); + ROUND4(R4,R5,R22,R3,M02,0x2ad7d2bb,15); + ROUND4(R3,R4,R5,R22,M09,0xeb86d391,21); ADD R14, R22 ADD R15, R3 ADD R16, R4 ADD R17, R5 ADD $64, R6 - CMP R6, R7 - BLT loop + BC 16, 0, loop // bdnz end: MOVD dig+0(FP), R10 @@ -198,4 +208,5 @@ end: MOVWZ R3, 4(R10) MOVWZ R4, 8(R10) MOVWZ R5, 12(R10) + RET -- GitLab From 7bfe32f39c59056c49f5776b104beaf09b010088 Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Tue, 9 Mar 2021 16:54:59 -0600 Subject: [PATCH 0341/1298] cmd/internal/obj: reorder ppc64 MOV* optab entries These are always sorted and grouped during initialization of the actual opcode -> optab map generation. Thus, their initial location in optab is mostly aimed at readability. This cleanup is intends to ease reviewing of future patches which simplify, combine, or remove MOV* optab entries. Change-Id: I87583ed34fab79e0f625880f419d499939e2a9e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/300612 Reviewed-by: Lynn Boger Trust: Emmanuel Odeke --- src/cmd/internal/obj/ppc64/asm9.go | 304 ++++++++++++++--------------- 1 file changed, 148 insertions(+), 156 deletions(-) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index e979cabddf..799df09687 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -94,11 +94,6 @@ var optab = []Optab{ {as: obj.ATEXT, a1: C_ADDR, a6: C_TEXTSIZE, type_: 0, size: 0}, {as: obj.ATEXT, a1: C_ADDR, a3: C_LCON, a6: C_TEXTSIZE, type_: 0, size: 0}, /* move register */ - {as: AMOVD, a1: C_REG, a6: C_REG, type_: 1, size: 4}, - {as: AMOVB, a1: C_REG, a6: C_REG, type_: 12, size: 4}, - {as: AMOVBZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_REG, type_: 12, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, {as: AADD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, {as: AADD, a1: C_REG, a6: C_REG, type_: 2, size: 4}, {as: AADD, a1: C_SCON, a2: C_REG, a6: C_REG, type_: 4, size: 4}, @@ -195,144 +190,177 @@ var optab = []Optab{ {as: AFADD, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 2, size: 4}, {as: AFABS, a1: C_FREG, a6: C_FREG, type_: 33, size: 4}, {as: AFABS, a6: C_FREG, type_: 33, size: 4}, - {as: AFMOVD, a1: C_FREG, a6: C_FREG, type_: 33, size: 4}, {as: AFMADD, a1: C_FREG, a2: C_FREG, a3: C_FREG, a6: C_FREG, type_: 34, size: 4}, {as: AFMUL, a1: C_FREG, a6: C_FREG, type_: 32, size: 4}, {as: AFMUL, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 32, size: 4}, - /* store, short offset */ - {as: AMOVD, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVW, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVWZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVBZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVBZU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVB, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, {as: AMOVBU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, - {as: AMOVBZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, - {as: AMOVB, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, - {as: AMOVBZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, - {as: AMOVB, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, - {as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, - {as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, - {as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, {as: AMOVBU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 9, size: 8}, + {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, - /* load, short offset */ - {as: AMOVD, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVW, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZU, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, {as: AMOVBZU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVB, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, - {as: AMOVBU, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, - {as: AMOVD, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, - {as: AMOVW, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, - {as: AMOVWZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, - {as: AMOVBZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, - {as: AMOVB, a1: C_SEXT, a6: C_REG, type_: 9, size: 8}, - {as: AMOVD, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, - {as: AMOVW, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, - {as: AMOVWZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, - {as: AMOVBZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + + {as: AMOVHBR, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AMOVHBR, a1: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 45, size: 4}, + {as: AMOVHBR, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, + + {as: AMOVB, a1: C_ADDR, a6: C_REG, type_: 76, size: 12}, + {as: AMOVB, a1: C_LAUTO, a6: C_REG, type_: 37, size: 12}, + {as: AMOVB, a1: C_LEXT, a6: C_REG, type_: 37, size: 12}, + {as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 37, size: 12}, + {as: AMOVB, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVB, a1: C_REG, a6: C_REG, type_: 12, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, {as: AMOVB, a1: C_SAUTO, a6: C_REG, type_: 9, size: 8}, - {as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVWZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, - {as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVB, a1: C_SEXT, a6: C_REG, type_: 9, size: 8}, {as: AMOVB, a1: C_SOREG, a6: C_REG, type_: 9, size: 8}, - {as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 9, size: 8}, + {as: AMOVB, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 9, size: 8}, - /* store, long offset */ - {as: AMOVD, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, - {as: AMOVW, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, - {as: AMOVWZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, - {as: AMOVBZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, - {as: AMOVB, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, - {as: AMOVD, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, - {as: AMOVW, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, - {as: AMOVWZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVBZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVBZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVBZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, {as: AMOVBZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, - {as: AMOVB, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, - {as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, - {as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, - {as: AMOVWZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, {as: AMOVBZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, - {as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, - {as: AMOVD, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, - {as: AMOVW, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, - {as: AMOVWZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, - {as: AMOVBZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, - {as: AMOVB, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVBZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVBZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVBZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - /* load, long offset */ - {as: AMOVD, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, - {as: AMOVW, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, - {as: AMOVWZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, - {as: AMOVBZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, - {as: AMOVB, a1: C_LEXT, a6: C_REG, type_: 37, size: 12}, + {as: AMOVD, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, + {as: AMOVD, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_CTR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_GOTADDR, a6: C_REG, type_: 81, size: 8}, + {as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, {as: AMOVD, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, - {as: AMOVW, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, - {as: AMOVWZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, - {as: AMOVBZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, - {as: AMOVB, a1: C_LAUTO, a6: C_REG, type_: 37, size: 12}, + {as: AMOVD, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, + {as: AMOVD, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVD, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, {as: AMOVD, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, - {as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, - {as: AMOVWZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, - {as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, - {as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 37, size: 12}, - {as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, - {as: AMOVW, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, - {as: AMOVWZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, - {as: AMOVBZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, - {as: AMOVB, a1: C_ADDR, a6: C_REG, type_: 76, size: 12}, - - {as: AMOVD, a1: C_TLS_LE, a6: C_REG, type_: 79, size: 4}, + {as: AMOVD, a1: C_LR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_MSR, a6: C_REG, type_: 54, size: 4}, /* mfmsr */ + {as: AMOVD, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVD, a1: C_REG, a6: C_LR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsrd */ + {as: AMOVD, a1: C_REG, a6: C_REG, type_: 1, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVD, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVD, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVD, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, {as: AMOVD, a1: C_TLS_IE, a6: C_REG, type_: 80, size: 8}, - - {as: AMOVD, a1: C_GOTADDR, a6: C_REG, type_: 81, size: 8}, + {as: AMOVD, a1: C_TLS_LE, a6: C_REG, type_: 79, size: 4}, {as: AMOVD, a1: C_TOCADDR, a6: C_REG, type_: 95, size: 8}, + {as: AMOVD, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVD, a1: C_XER, a6: C_REG, type_: 66, size: 4}, + {as: AMOVD, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, - /* load constant */ - {as: AMOVD, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVD, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, - {as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, - {as: AMOVD, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVD, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVW, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ - {as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVW, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, - {as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, {as: AMOVW, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, {as: AMOVW, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVWZ, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ - {as: AMOVWZ, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVWZ, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, - {as: AMOVWZ, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVW, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, + {as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVW, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, + {as: AMOVW, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVW, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVW, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVW, a1: C_REG, a6: C_REG, type_: 12, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVW, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ + {as: AMOVW, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVW, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVW, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVW, a1: C_XER, a6: C_REG, type_: 66, size: 4}, + {as: AMOVW, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_ADDCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, {as: AMOVWZ, a1: C_ANDCON, a6: C_REG, type_: 3, size: 4}, - - /* load unsigned/long constants (TO DO: check) */ - {as: AMOVD, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVD, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, - {as: AMOVW, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, - {as: AMOVW, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, - {as: AMOVWZ, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, + {as: AMOVWZ, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVWZ, a1: C_LAUTO, a6: C_REG, type_: 36, size: 8}, {as: AMOVWZ, a1: C_LCON, a6: C_REG, type_: 19, size: 8}, - {as: AMOVHBR, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 45, size: 4}, - {as: AMOVHBR, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4}, - {as: AMOVHBR, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 44, size: 4}, - {as: AMOVHBR, a1: C_REG, a6: C_ZOREG, type_: 44, size: 4}, + {as: AMOVWZ, a1: C_LECON, a6: C_REG, type_: 26, size: 8}, + {as: AMOVWZ, a1: C_LEXT, a6: C_REG, type_: 36, size: 8}, + {as: AMOVWZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, + {as: AMOVWZ, a1: C_REG, a2: C_REG, a6: C_ZOREG, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_LAUTO, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_LEXT, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, + {as: AMOVWZ, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsr */ + {as: AMOVWZ, a1: C_REG, a6: C_REG, type_: 13, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SAUTO, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SEXT, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_REG, a6: C_XER, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_SACON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_SAUTO, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SECON, a6: C_REG, type_: 3, size: 4}, /* TO DO: check */ + {as: AMOVWZ, a1: C_SEXT, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4}, + {as: AMOVWZ, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_UCON, a6: C_REG, type_: 3, size: 4}, + {as: AMOVWZ, a1: C_XER, a6: C_REG, type_: 66, size: 4}, + {as: AMOVWZ, a1: C_ZOREG, a2: C_REG, a6: C_REG, type_: 8, size: 4}, + + {as: AMOVFL, a1: C_CREG, a6: C_CREG, type_: 67, size: 4}, + {as: AMOVFL, a1: C_FPSCR, a6: C_CREG, type_: 73, size: 4}, + {as: AMOVFL, a1: C_FPSCR, a6: C_FREG, type_: 53, size: 4}, + {as: AMOVFL, a1: C_FREG, a3: C_LCON, a6: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_FREG, a6: C_FPSCR, type_: 64, size: 4}, + {as: AMOVFL, a1: C_LCON, a6: C_FPSCR, type_: 65, size: 4}, + {as: AMOVFL, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, + {as: AMOVFL, a1: C_REG, a6: C_LCON, type_: 69, size: 4}, + {as: ASYSCALL, type_: 5, size: 4}, {as: ASYSCALL, a1: C_REG, type_: 77, size: 12}, {as: ASYSCALL, a1: C_SCON, type_: 77, size: 12}, @@ -352,6 +380,7 @@ var optab = []Optab{ {as: ABC, a1: C_SCON, a2: C_REG, a6: C_LR, type_: 18, size: 4}, {as: ABC, a1: C_SCON, a2: C_REG, a6: C_CTR, type_: 18, size: 4}, {as: ABC, a6: C_ZOREG, type_: 15, size: 8}, + {as: AFMOVD, a1: C_FREG, a6: C_FREG, type_: 33, size: 4}, {as: AFMOVD, a1: C_SEXT, a6: C_FREG, type_: 8, size: 4}, {as: AFMOVD, a1: C_SAUTO, a6: C_FREG, type_: 8, size: 4}, {as: AFMOVD, a1: C_SOREG, a6: C_FREG, type_: 8, size: 4}, @@ -392,14 +421,6 @@ var optab = []Optab{ {as: AREMD, a1: C_REG, a6: C_REG, type_: 51, size: 12}, {as: AREMD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 51, size: 12}, {as: AMTFSB0, a1: C_SCON, type_: 52, size: 4}, - {as: AMOVFL, a1: C_FPSCR, a6: C_FREG, type_: 53, size: 4}, - {as: AMOVFL, a1: C_FREG, a6: C_FPSCR, type_: 64, size: 4}, - {as: AMOVFL, a1: C_FREG, a3: C_LCON, a6: C_FPSCR, type_: 64, size: 4}, - {as: AMOVFL, a1: C_LCON, a6: C_FPSCR, type_: 65, size: 4}, - {as: AMOVD, a1: C_MSR, a6: C_REG, type_: 54, size: 4}, /* mfmsr */ - {as: AMOVD, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsrd */ - {as: AMOVWZ, a1: C_REG, a6: C_MSR, type_: 54, size: 4}, /* mtmsr */ - /* Other ISA 2.05+ instructions */ {as: APOPCNTD, a1: C_REG, a6: C_REG, type_: 93, size: 4}, /* population count, x-form */ {as: ACMPB, a1: C_REG, a2: C_REG, a6: C_REG, type_: 92, size: 4}, /* compare byte, x-form */ @@ -562,35 +583,6 @@ var optab = []Optab{ /* VSX vector integer-FP conversion */ {as: AXVCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */ - /* 64-bit special registers */ - {as: AMOVD, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_LR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, - {as: AMOVD, a1: C_REG, a6: C_XER, type_: 66, size: 4}, - {as: AMOVD, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_LR, a6: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_CTR, a6: C_REG, type_: 66, size: 4}, - {as: AMOVD, a1: C_XER, a6: C_REG, type_: 66, size: 4}, - - /* 32-bit special registers (gloss over sign-extension or not?) */ - {as: AMOVW, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_XER, type_: 66, size: 4}, - {as: AMOVW, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, - {as: AMOVW, a1: C_XER, a6: C_REG, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_SPR, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_CTR, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_XER, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_SPR, a6: C_REG, type_: 66, size: 4}, - {as: AMOVWZ, a1: C_XER, a6: C_REG, type_: 66, size: 4}, - {as: AMOVFL, a1: C_FPSCR, a6: C_CREG, type_: 73, size: 4}, - {as: AMOVFL, a1: C_CREG, a6: C_CREG, type_: 67, size: 4}, - {as: AMOVW, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, - {as: AMOVWZ, a1: C_CREG, a6: C_REG, type_: 68, size: 4}, - {as: AMOVFL, a1: C_REG, a6: C_LCON, type_: 69, size: 4}, - {as: AMOVFL, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, - {as: AMOVW, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, - {as: AMOVWZ, a1: C_REG, a6: C_CREG, type_: 69, size: 4}, {as: ACMP, a1: C_REG, a6: C_REG, type_: 70, size: 4}, {as: ACMP, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4}, {as: ACMP, a1: C_REG, a6: C_ADDCON, type_: 71, size: 4}, -- GitLab From 0f4bb9627ebc27d4e669e41d7f58396e063abb70 Mon Sep 17 00:00:00 2001 From: Ethan Hur Date: Sun, 14 Mar 2021 13:43:26 +0000 Subject: [PATCH 0342/1298] cmd/compile: fix outdated comment variable xtop has removed and refactored after go 1.16, but there are comments referring xtop. It may mislead new contributors to be confused. Change-Id: Id79c747d8daef14049b29e70a4ecd34054a28a5e GitHub-Last-Rev: 94b55208862fdc9fa0de39aacf2c9ef9987cef56 GitHub-Pull-Request: golang/go#44995 Reviewed-on: https://go-review.googlesource.com/c/go/+/301629 Reviewed-by: Matthew Dempsky Trust: Keith Randall --- src/cmd/compile/internal/typecheck/func.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 367df8e9f4..86058a0c73 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -308,7 +308,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) { return } - // Don't give a name and add to xtop if we are typechecking an inlined + // Don't give a name and add to Target.Decls if we are typechecking an inlined // body in ImportedBody(), since we only want to create the named function // when the closure is actually inlined (and then we force a typecheck // explicitly in (*inlsubst).node()). @@ -354,7 +354,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) { ir.Dump(s, fn) } if !inTypeCheckInl { - // Add function to xtop once only when we give it a name + // Add function to Target.Decls once only when we give it a name Target.Decls = append(Target.Decls, fn) } } -- GitLab From 8ac6544564be04ed1c0bbf7831ad0f8ed1f067ed Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 15 Mar 2021 10:03:30 -0700 Subject: [PATCH 0343/1298] bytes: correct tense in comment Undo incorrect change accidentally made in CL 299109. Change-Id: Iba29827d0fbd3637c311cebc50c2f4ea437fc582 Reviewed-on: https://go-review.googlesource.com/c/go/+/301830 Trust: Ian Lance Taylor Reviewed-by: Tobias Klauser --- src/bytes/buffer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index 01764c694e..549b077708 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -387,7 +387,7 @@ var errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was // UnreadByte unreads the last byte returned by the most recent successful // read operation that read at least one byte. If a write has happened since -// the last read, if the last read returned an error, or if the read reads zero +// the last read, if the last read returned an error, or if the read read zero // bytes, UnreadByte returns an error. func (b *Buffer) UnreadByte() error { if b.lastRead == opInvalid { -- GitLab From c4190fc34dbfe8c7859a91b07ed31a33633d08df Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 12 Mar 2021 18:45:52 -0500 Subject: [PATCH 0344/1298] cmd/compile: remove ARMv5 special case in register allocator The register allocator has a special case that doesn't allocate LR on ARMv5. This was necessary when softfloat expansion was done by the assembler. Now softfloat calls are inserted by SSA, so it works as normal. Remove this special case. Change-Id: I5502f07597f4d4b675dc16b6b0d7cb47e1e8974b Reviewed-on: https://go-review.googlesource.com/c/go/+/301792 Trust: Cherry Zhang Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/regalloc.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 15f6412a85..c104a36888 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -605,12 +605,6 @@ func (s *regAllocState) init(f *Func) { // Leaf functions don't save/restore the link register. s.allocatable &^= 1 << uint(s.f.Config.LinkReg) } - if s.f.Config.arch == "arm" && objabi.GOARM == 5 { - // On ARMv5 we insert softfloat calls at each FP instruction. - // This clobbers LR almost everywhere. Disable allocating LR - // on ARMv5. - s.allocatable &^= 1 << uint(s.f.Config.LinkReg) - } } if s.f.Config.ctxt.Flag_dynlink { switch s.f.Config.arch { -- GitLab From a8d9fb2fcd1fc11b41651e0ea608b3a3e90755b7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 15 Mar 2021 17:54:35 +0100 Subject: [PATCH 0345/1298] cmd/internal/moddeps: fix typo in TestAllDependencies log messages s/dependecies/dependencies/ Change-Id: I454668a36192e345965173d76be12cbd5917ea34 Reviewed-on: https://go-review.googlesource.com/c/go/+/301849 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Dmitri Shuralyov --- src/cmd/internal/moddeps/moddeps_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index cba401c896..78c291e203 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -61,7 +61,7 @@ func TestAllDependencies(t *testing.T) { _, err := cmd.Output() if err != nil { t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr) - t.Logf("(Run 'go mod vendor' in %s to ensure that dependecies have been vendored.)", m.Dir) + t.Logf("(Run 'go mod vendor' in %s to ensure that dependencies have been vendored.)", m.Dir) } return } @@ -179,7 +179,7 @@ func TestAllDependencies(t *testing.T) { r.run(t, goBinCopy, "generate", `-run=^//go:generate bundle `, pkgs) // See issue 41409. advice := "$ cd " + m.Dir + "\n" + "$ go mod tidy # to remove extraneous dependencies\n" + - "$ go mod vendor # to vendor dependecies\n" + + "$ go mod vendor # to vendor dependencies\n" + "$ go generate -run=bundle " + pkgs + " # to regenerate bundled packages\n" if m.Path == "std" { r.run(t, goBinCopy, "generate", "syscall", "internal/syscall/...") // See issue 43440. -- GitLab From 2d4042d4ab3a2021819dce91eb228daf8fa5e557 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Fri, 26 Feb 2021 02:27:24 -0800 Subject: [PATCH 0346/1298] all: update golang.org/x/* dependencies Updates src/ and src/cmd/* dependencies, using go mod vendor as well as updatestd -branch=master -goroot=$GOROOT This change was ran in anticipation of bringing in x/net/http2 CL 237957. For #32112. For #36905. Change-Id: If8cefc348463b6d82d85020b57db411213720ef8 Reviewed-on: https://go-review.googlesource.com/c/go/+/296789 Trust: Emmanuel Odeke Trust: Dmitri Shuralyov Trust: Bryan C. Mills Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Alexander Rakoczy --- src/cmd/go.mod | 13 +- src/cmd/go.sum | 25 +- .../pprof/internal/binutils/addr2liner.go | 24 +- .../internal/binutils/addr2liner_llvm.go | 36 +- .../pprof/internal/binutils/addr2liner_nm.go | 58 +- .../pprof/internal/binutils/binutils.go | 65 +- .../google/pprof/internal/binutils/disasm.go | 3 + .../google/pprof/internal/driver/driver.go | 6 +- .../google/pprof/internal/driver/webhtml.go | 1 + .../google/pprof/internal/elfexec/elfexec.go | 81 + .../google/pprof/internal/graph/dotgraph.go | 4 +- .../pprof/internal/measurement/measurement.go | 240 +- .../google/pprof/internal/report/source.go | 727 +- .../pprof/internal/report/source_html.go | 3 +- .../github.com/google/pprof/profile/merge.go | 5 +- .../google/pprof/profile/profile.go | 18 +- .../golang.org/x/arch/arm64/arm64asm/inst.go | 10 +- .../x/arch/arm64/arm64asm/plan9x.go | 14 +- .../golang.org/x/arch/ppc64/ppc64asm/gnu.go | 181 +- .../x/arch/ppc64/ppc64asm/tables.go | 13 +- .../golang.org/x/arch/x86/x86asm/tables.go | 16353 ++++++++-------- .../golang.org/x/crypto/ed25519/ed25519.go | 1 + .../x/crypto/ed25519/ed25519_go113.go | 1 + .../x/crypto/ssh/terminal/terminal.go | 987 +- src/cmd/vendor/golang.org/x/sys/plan9/asm.s | 8 + .../golang.org/x/sys/plan9/asm_plan9_386.s | 30 + .../golang.org/x/sys/plan9/asm_plan9_amd64.s | 30 + .../golang.org/x/sys/plan9/asm_plan9_arm.s | 25 + .../golang.org/x/sys/plan9/const_plan9.go | 70 + .../golang.org/x/sys/plan9/dir_plan9.go | 212 + .../golang.org/x/sys/plan9/env_plan9.go | 31 + .../golang.org/x/sys/plan9/errors_plan9.go | 50 + .../vendor/golang.org/x/sys/plan9/mkall.sh | 150 + .../vendor/golang.org/x/sys/plan9/mkerrors.sh | 246 + .../golang.org/x/sys/plan9/mksysnum_plan9.sh | 23 + .../golang.org/x/sys/plan9/pwd_go15_plan9.go | 21 + .../golang.org/x/sys/plan9/pwd_plan9.go | 23 + src/cmd/vendor/golang.org/x/sys/plan9/race.go | 30 + .../vendor/golang.org/x/sys/plan9/race0.go | 25 + src/cmd/vendor/golang.org/x/sys/plan9/str.go | 22 + .../vendor/golang.org/x/sys/plan9/syscall.go | 116 + .../golang.org/x/sys/plan9/syscall_plan9.go | 349 + .../x/sys/plan9/zsyscall_plan9_386.go | 284 + .../x/sys/plan9/zsyscall_plan9_amd64.go | 284 + .../x/sys/plan9/zsyscall_plan9_arm.go | 284 + .../golang.org/x/sys/plan9/zsysnum_plan9.go | 49 + .../vendor/golang.org/x/sys/unix/aliases.go | 3 +- .../golang.org/x/sys/unix/asm_zos_s390x.s | 426 + .../golang.org/x/sys/unix/cap_freebsd.go | 1 + .../vendor/golang.org/x/sys/unix/constants.go | 3 +- .../golang.org/x/sys/unix/dev_aix_ppc.go | 4 +- .../golang.org/x/sys/unix/dev_aix_ppc64.go | 4 +- .../vendor/golang.org/x/sys/unix/dev_zos.go | 29 + .../vendor/golang.org/x/sys/unix/dirent.go | 1 + .../golang.org/x/sys/unix/endian_big.go | 1 + .../golang.org/x/sys/unix/endian_little.go | 1 + .../vendor/golang.org/x/sys/unix/env_unix.go | 3 +- .../vendor/golang.org/x/sys/unix/epoll_zos.go | 221 + src/cmd/vendor/golang.org/x/sys/unix/fcntl.go | 1 + .../x/sys/unix/fcntl_linux_32bit.go | 1 + src/cmd/vendor/golang.org/x/sys/unix/fdset.go | 1 + .../golang.org/x/sys/unix/fstatfs_zos.go | 164 + src/cmd/vendor/golang.org/x/sys/unix/gccgo.go | 4 +- .../x/sys/unix/gccgo_linux_amd64.go | 1 + src/cmd/vendor/golang.org/x/sys/unix/ioctl.go | 1 + .../vendor/golang.org/x/sys/unix/ioctl_zos.go | 74 + .../vendor/golang.org/x/sys/unix/mkerrors.sh | 22 +- .../golang.org/x/sys/unix/pagesize_unix.go | 1 + .../golang.org/x/sys/unix/ptrace_darwin.go | 1 + .../golang.org/x/sys/unix/ptrace_ios.go | 1 + src/cmd/vendor/golang.org/x/sys/unix/race.go | 1 + src/cmd/vendor/golang.org/x/sys/unix/race0.go | 3 +- .../x/sys/unix/readdirent_getdents.go | 1 + .../x/sys/unix/readdirent_getdirentries.go | 1 + .../golang.org/x/sys/unix/sockcmsg_unix.go | 3 +- .../x/sys/unix/sockcmsg_unix_other.go | 7 +- src/cmd/vendor/golang.org/x/sys/unix/str.go | 1 + .../vendor/golang.org/x/sys/unix/syscall.go | 3 +- .../golang.org/x/sys/unix/syscall_aix.go | 1 + .../golang.org/x/sys/unix/syscall_aix_ppc.go | 4 +- .../x/sys/unix/syscall_aix_ppc64.go | 4 +- .../golang.org/x/sys/unix/syscall_bsd.go | 1 + .../x/sys/unix/syscall_darwin.1_12.go | 1 + .../x/sys/unix/syscall_darwin.1_13.go | 1 + .../golang.org/x/sys/unix/syscall_darwin.go | 2 +- .../x/sys/unix/syscall_darwin_386.go | 1 + .../x/sys/unix/syscall_darwin_amd64.go | 1 + .../x/sys/unix/syscall_darwin_arm64.go | 1 + .../x/sys/unix/syscall_darwin_libSystem.go | 1 + .../x/sys/unix/syscall_dragonfly.go | 7 +- .../x/sys/unix/syscall_dragonfly_amd64.go | 1 + .../golang.org/x/sys/unix/syscall_freebsd.go | 9 + .../x/sys/unix/syscall_freebsd_386.go | 1 + .../x/sys/unix/syscall_freebsd_amd64.go | 1 + .../x/sys/unix/syscall_freebsd_arm.go | 1 + .../x/sys/unix/syscall_freebsd_arm64.go | 1 + .../golang.org/x/sys/unix/syscall_illumos.go | 1 + .../golang.org/x/sys/unix/syscall_linux.go | 89 +- .../x/sys/unix/syscall_linux_386.go | 1 + .../x/sys/unix/syscall_linux_amd64.go | 1 + .../x/sys/unix/syscall_linux_amd64_gc.go | 4 +- .../x/sys/unix/syscall_linux_arm.go | 1 + .../x/sys/unix/syscall_linux_arm64.go | 1 + .../golang.org/x/sys/unix/syscall_linux_gc.go | 1 + .../x/sys/unix/syscall_linux_gc_386.go | 1 + .../x/sys/unix/syscall_linux_gc_arm.go | 1 + .../x/sys/unix/syscall_linux_gccgo_386.go | 1 + .../x/sys/unix/syscall_linux_gccgo_arm.go | 1 + .../x/sys/unix/syscall_linux_mips64x.go | 1 + .../x/sys/unix/syscall_linux_mipsx.go | 1 + .../x/sys/unix/syscall_linux_ppc64x.go | 1 + .../x/sys/unix/syscall_linux_riscv64.go | 1 + .../x/sys/unix/syscall_linux_s390x.go | 1 + .../x/sys/unix/syscall_linux_sparc64.go | 1 + .../x/sys/unix/syscall_netbsd_386.go | 1 + .../x/sys/unix/syscall_netbsd_amd64.go | 1 + .../x/sys/unix/syscall_netbsd_arm.go | 1 + .../x/sys/unix/syscall_netbsd_arm64.go | 1 + .../x/sys/unix/syscall_openbsd_386.go | 1 + .../x/sys/unix/syscall_openbsd_amd64.go | 1 + .../x/sys/unix/syscall_openbsd_arm.go | 1 + .../x/sys/unix/syscall_openbsd_arm64.go | 1 + .../x/sys/unix/syscall_solaris_amd64.go | 1 + .../golang.org/x/sys/unix/syscall_unix.go | 1 + .../golang.org/x/sys/unix/syscall_unix_gc.go | 5 +- .../x/sys/unix/syscall_unix_gc_ppc64x.go | 1 + .../x/sys/unix/syscall_zos_s390x.go | 1781 ++ .../golang.org/x/sys/unix/timestruct.go | 3 +- .../vendor/golang.org/x/sys/unix/xattr_bsd.go | 1 + .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 1 + .../x/sys/unix/zerrors_aix_ppc64.go | 1 + .../x/sys/unix/zerrors_darwin_386.go | 1 + .../x/sys/unix/zerrors_darwin_amd64.go | 1 + .../x/sys/unix/zerrors_darwin_arm.go | 1 + .../x/sys/unix/zerrors_darwin_arm64.go | 1 + .../x/sys/unix/zerrors_dragonfly_amd64.go | 1 + .../x/sys/unix/zerrors_freebsd_386.go | 7 + .../x/sys/unix/zerrors_freebsd_amd64.go | 7 + .../x/sys/unix/zerrors_freebsd_arm.go | 7 + .../x/sys/unix/zerrors_freebsd_arm64.go | 7 + .../golang.org/x/sys/unix/zerrors_linux.go | 9 + .../x/sys/unix/zerrors_linux_386.go | 7 + .../x/sys/unix/zerrors_linux_amd64.go | 7 + .../x/sys/unix/zerrors_linux_arm.go | 7 + .../x/sys/unix/zerrors_linux_arm64.go | 7 + .../x/sys/unix/zerrors_linux_mips.go | 7 + .../x/sys/unix/zerrors_linux_mips64.go | 7 + .../x/sys/unix/zerrors_linux_mips64le.go | 7 + .../x/sys/unix/zerrors_linux_mipsle.go | 7 + .../x/sys/unix/zerrors_linux_ppc64.go | 7 + .../x/sys/unix/zerrors_linux_ppc64le.go | 7 + .../x/sys/unix/zerrors_linux_riscv64.go | 7 + .../x/sys/unix/zerrors_linux_s390x.go | 7 + .../x/sys/unix/zerrors_linux_sparc64.go | 7 + .../x/sys/unix/zerrors_netbsd_386.go | 1 + .../x/sys/unix/zerrors_netbsd_amd64.go | 1 + .../x/sys/unix/zerrors_netbsd_arm.go | 1 + .../x/sys/unix/zerrors_netbsd_arm64.go | 1 + .../x/sys/unix/zerrors_openbsd_386.go | 1 + .../x/sys/unix/zerrors_openbsd_amd64.go | 1 + .../x/sys/unix/zerrors_openbsd_arm.go | 1 + .../x/sys/unix/zerrors_openbsd_arm64.go | 1 + .../x/sys/unix/zerrors_openbsd_mips64.go | 1 + .../x/sys/unix/zerrors_solaris_amd64.go | 1 + .../x/sys/unix/zerrors_zos_s390x.go | 831 + .../x/sys/unix/zptrace_armnn_linux.go | 1 + .../x/sys/unix/zptrace_mipsnn_linux.go | 1 + .../x/sys/unix/zptrace_mipsnnle_linux.go | 1 + .../x/sys/unix/zptrace_x86_linux.go | 1 + .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 1 + .../x/sys/unix/zsyscall_aix_ppc64.go | 1 + .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 4 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 4 +- .../x/sys/unix/zsyscall_darwin_386.1_13.go | 1 + .../x/sys/unix/zsyscall_darwin_386.go | 1 + .../x/sys/unix/zsyscall_darwin_amd64.1_13.go | 1 + .../x/sys/unix/zsyscall_darwin_amd64.go | 1 + .../x/sys/unix/zsyscall_darwin_arm.1_13.go | 1 + .../x/sys/unix/zsyscall_darwin_arm.go | 1 + .../x/sys/unix/zsyscall_darwin_arm64.1_13.go | 1 + .../x/sys/unix/zsyscall_darwin_arm64.go | 1 + .../x/sys/unix/zsyscall_dragonfly_amd64.go | 5 +- .../x/sys/unix/zsyscall_freebsd_386.go | 1 + .../x/sys/unix/zsyscall_freebsd_amd64.go | 1 + .../x/sys/unix/zsyscall_freebsd_arm.go | 1 + .../x/sys/unix/zsyscall_freebsd_arm64.go | 1 + .../x/sys/unix/zsyscall_illumos_amd64.go | 1 + .../golang.org/x/sys/unix/zsyscall_linux.go | 1 + .../x/sys/unix/zsyscall_linux_386.go | 1 + .../x/sys/unix/zsyscall_linux_amd64.go | 1 + .../x/sys/unix/zsyscall_linux_arm.go | 1 + .../x/sys/unix/zsyscall_linux_arm64.go | 1 + .../x/sys/unix/zsyscall_linux_mips.go | 1 + .../x/sys/unix/zsyscall_linux_mips64.go | 1 + .../x/sys/unix/zsyscall_linux_mips64le.go | 1 + .../x/sys/unix/zsyscall_linux_mipsle.go | 1 + .../x/sys/unix/zsyscall_linux_ppc64.go | 1 + .../x/sys/unix/zsyscall_linux_ppc64le.go | 1 + .../x/sys/unix/zsyscall_linux_riscv64.go | 1 + .../x/sys/unix/zsyscall_linux_s390x.go | 1 + .../x/sys/unix/zsyscall_linux_sparc64.go | 1 + .../x/sys/unix/zsyscall_netbsd_386.go | 1 + .../x/sys/unix/zsyscall_netbsd_amd64.go | 1 + .../x/sys/unix/zsyscall_netbsd_arm.go | 1 + .../x/sys/unix/zsyscall_netbsd_arm64.go | 1 + .../x/sys/unix/zsyscall_openbsd_386.go | 1 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 1 + .../x/sys/unix/zsyscall_openbsd_arm.go | 1 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 1 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 1 + .../x/sys/unix/zsyscall_solaris_amd64.go | 1 + .../x/sys/unix/zsyscall_zos_s390x.go | 1217 ++ .../x/sys/unix/zsysctl_openbsd_386.go | 1 + .../x/sys/unix/zsysctl_openbsd_amd64.go | 1 + .../x/sys/unix/zsysctl_openbsd_arm.go | 1 + .../x/sys/unix/zsysctl_openbsd_arm64.go | 1 + .../x/sys/unix/zsysctl_openbsd_mips64.go | 1 + .../x/sys/unix/zsysnum_darwin_386.go | 1 + .../x/sys/unix/zsysnum_darwin_amd64.go | 1 + .../x/sys/unix/zsysnum_darwin_arm.go | 1 + .../x/sys/unix/zsysnum_darwin_arm64.go | 1 + .../x/sys/unix/zsysnum_dragonfly_amd64.go | 1 + .../x/sys/unix/zsysnum_freebsd_386.go | 1 + .../x/sys/unix/zsysnum_freebsd_amd64.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_386.go | 1 + .../x/sys/unix/zsysnum_linux_amd64.go | 1 + .../x/sys/unix/zsysnum_linux_arm.go | 1 + .../x/sys/unix/zsysnum_linux_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_mips.go | 1 + .../x/sys/unix/zsysnum_linux_mips64.go | 1 + .../x/sys/unix/zsysnum_linux_mips64le.go | 1 + .../x/sys/unix/zsysnum_linux_mipsle.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 1 + .../x/sys/unix/zsysnum_linux_riscv64.go | 1 + .../x/sys/unix/zsysnum_linux_s390x.go | 1 + .../x/sys/unix/zsysnum_linux_sparc64.go | 1 + .../x/sys/unix/zsysnum_netbsd_386.go | 1 + .../x/sys/unix/zsysnum_netbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_386.go | 1 + .../x/sys/unix/zsysnum_openbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_mips64.go | 1 + .../x/sys/unix/zsysnum_zos_s390x.go | 2670 +++ .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 1 + .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 1 + .../x/sys/unix/ztypes_darwin_386.go | 1 + .../x/sys/unix/ztypes_darwin_amd64.go | 1 + .../x/sys/unix/ztypes_darwin_arm.go | 1 + .../x/sys/unix/ztypes_darwin_arm64.go | 1 + .../x/sys/unix/ztypes_dragonfly_amd64.go | 1 + .../x/sys/unix/ztypes_freebsd_386.go | 10 + .../x/sys/unix/ztypes_freebsd_amd64.go | 10 + .../x/sys/unix/ztypes_freebsd_arm.go | 10 + .../x/sys/unix/ztypes_freebsd_arm64.go | 10 + .../golang.org/x/sys/unix/ztypes_linux.go | 30 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 1 + .../x/sys/unix/ztypes_linux_amd64.go | 1 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 1 + .../x/sys/unix/ztypes_linux_arm64.go | 1 + .../x/sys/unix/ztypes_linux_mips.go | 1 + .../x/sys/unix/ztypes_linux_mips64.go | 1 + .../x/sys/unix/ztypes_linux_mips64le.go | 1 + .../x/sys/unix/ztypes_linux_mipsle.go | 1 + .../x/sys/unix/ztypes_linux_ppc64.go | 1 + .../x/sys/unix/ztypes_linux_ppc64le.go | 1 + .../x/sys/unix/ztypes_linux_riscv64.go | 1 + .../x/sys/unix/ztypes_linux_s390x.go | 1 + .../x/sys/unix/ztypes_linux_sparc64.go | 1 + .../x/sys/unix/ztypes_netbsd_386.go | 1 + .../x/sys/unix/ztypes_netbsd_amd64.go | 1 + .../x/sys/unix/ztypes_netbsd_arm.go | 1 + .../x/sys/unix/ztypes_netbsd_arm64.go | 1 + .../x/sys/unix/ztypes_openbsd_386.go | 1 + .../x/sys/unix/ztypes_openbsd_amd64.go | 1 + .../x/sys/unix/ztypes_openbsd_arm.go | 1 + .../x/sys/unix/ztypes_openbsd_arm64.go | 1 + .../x/sys/unix/ztypes_openbsd_mips64.go | 1 + .../x/sys/unix/ztypes_solaris_amd64.go | 1 + .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 402 + .../golang.org/x/sys/windows/exec_windows.go | 35 + .../golang.org/x/sys/windows/mkerrors.bash | 7 + .../x/sys/windows/security_windows.go | 13 + .../x/sys/windows/syscall_windows.go | 190 +- .../golang.org/x/sys/windows/types_windows.go | 678 + .../x/sys/windows/zerrors_windows.go | 2619 ++- .../x/sys/windows/zsyscall_windows.go | 337 +- src/cmd/vendor/golang.org/x/term/AUTHORS | 3 + .../vendor/golang.org/x/term/CONTRIBUTING.md | 26 + src/cmd/vendor/golang.org/x/term/CONTRIBUTORS | 3 + src/cmd/vendor/golang.org/x/term/LICENSE | 27 + src/cmd/vendor/golang.org/x/term/PATENTS | 22 + src/cmd/vendor/golang.org/x/term/README.md | 19 + src/cmd/vendor/golang.org/x/term/go.mod | 5 + src/cmd/vendor/golang.org/x/term/go.sum | 2 + .../terminal/util_plan9.go => term/term.go} | 40 +- .../vendor/golang.org/x/term/term_plan9.go | 42 + .../util_solaris.go => term/term_solaris.go} | 41 +- .../terminal/util.go => term/term_unix.go} | 48 +- .../util_linux.go => term/term_unix_aix.go} | 4 +- .../util_bsd.go => term/term_unix_bsd.go} | 3 +- .../util_aix.go => term/term_unix_linux.go} | 6 +- .../vendor/golang.org/x/term/term_unix_zos.go | 10 + .../golang.org/x/term/term_unsupported.go | 39 + .../util_windows.go => term/term_windows.go} | 48 +- src/cmd/vendor/golang.org/x/term/terminal.go | 987 + src/cmd/vendor/modules.txt | 14 +- src/go.mod | 10 +- src/go.sum | 19 +- src/net/http/h2_bundle.go | 30 +- .../x/crypto/chacha20/chacha_arm64.go | 3 +- .../x/crypto/chacha20/chacha_arm64.s | 2 +- .../x/crypto/chacha20/chacha_noasm.go | 3 +- .../x/crypto/chacha20/chacha_ppc64le.go | 3 +- .../x/crypto/chacha20/chacha_ppc64le.s | 2 +- .../x/crypto/chacha20/chacha_s390x.go | 3 +- .../x/crypto/chacha20/chacha_s390x.s | 2 +- .../chacha20poly1305_amd64.go | 3 +- .../chacha20poly1305/chacha20poly1305_amd64.s | 2 +- .../chacha20poly1305_noasm.go | 3 +- .../x/crypto/curve25519/curve25519_amd64.go | 3 +- .../x/crypto/curve25519/curve25519_amd64.s | 2 +- .../x/crypto/curve25519/curve25519_noasm.go | 3 +- .../x/crypto/internal/subtle/aliasing.go | 3 +- ...iasing_appengine.go => aliasing_purego.go} | 3 +- .../x/crypto/poly1305/bits_compat.go | 1 + .../x/crypto/poly1305/bits_go1.13.go | 1 + .../golang.org/x/crypto/poly1305/mac_noasm.go | 3 +- .../golang.org/x/crypto/poly1305/sum_amd64.go | 3 +- .../golang.org/x/crypto/poly1305/sum_amd64.s | 2 +- .../x/crypto/poly1305/sum_ppc64le.go | 3 +- .../x/crypto/poly1305/sum_ppc64le.s | 2 +- .../golang.org/x/crypto/poly1305/sum_s390x.go | 3 +- .../golang.org/x/crypto/poly1305/sum_s390x.s | 2 +- .../golang.org/x/net/idna/idna10.0.0.go | 1 + src/vendor/golang.org/x/net/idna/idna9.0.0.go | 1 + .../golang.org/x/net/idna/tables10.0.0.go | 1 + .../golang.org/x/net/idna/tables11.0.0.go | 1 + .../golang.org/x/net/idna/tables12.0.0.go | 1 + .../golang.org/x/net/idna/tables13.0.0.go | 1 + .../golang.org/x/net/idna/tables9.0.0.go | 1 + .../golang.org/x/net/nettest/nettest_stub.go | 1 + .../golang.org/x/net/nettest/nettest_unix.go | 1 + src/vendor/golang.org/x/net/route/address.go | 1 + src/vendor/golang.org/x/net/route/binary.go | 1 + .../golang.org/x/net/route/interface.go | 1 + .../x/net/route/interface_announce.go | 1 + .../x/net/route/interface_classic.go | 1 + .../x/net/route/interface_multicast.go | 1 + src/vendor/golang.org/x/net/route/message.go | 1 + src/vendor/golang.org/x/net/route/route.go | 1 + .../golang.org/x/net/route/route_classic.go | 1 + src/vendor/golang.org/x/net/route/sys.go | 1 + src/vendor/golang.org/x/net/route/syscall.go | 1 + .../x/net/route/syscall_go1_12_darwin.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_aix.go | 1 + .../golang.org/x/sys/cpu/cpu_gc_arm64.go | 1 + .../golang.org/x/sys/cpu/cpu_gc_s390x.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 1 + .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 1 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 1 + .../golang.org/x/sys/cpu/cpu_gccgo_x86.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_linux.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 1 + .../golang.org/x/sys/cpu/cpu_mips64x.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 1 + .../golang.org/x/sys/cpu/cpu_other_arm.go | 1 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 4 +- .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 1 + .../golang.org/x/sys/cpu/cpu_riscv64.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_wasm.go | 1 + src/vendor/golang.org/x/sys/cpu/cpu_x86.go | 1 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 4 +- .../x/sys/cpu/syscall_aix_ppc64_gc.go | 4 +- .../x/text/secure/bidirule/bidirule10.0.0.go | 1 + .../x/text/secure/bidirule/bidirule9.0.0.go | 1 + .../golang.org/x/text/unicode/bidi/bidi.go | 221 +- .../golang.org/x/text/unicode/bidi/core.go | 63 +- .../x/text/unicode/bidi/tables10.0.0.go | 1 + .../x/text/unicode/bidi/tables11.0.0.go | 1 + .../x/text/unicode/bidi/tables12.0.0.go | 1 + .../x/text/unicode/bidi/tables13.0.0.go | 1 + .../x/text/unicode/bidi/tables9.0.0.go | 1 + .../x/text/unicode/norm/tables10.0.0.go | 1 + .../x/text/unicode/norm/tables11.0.0.go | 1 + .../x/text/unicode/norm/tables12.0.0.go | 1 + .../x/text/unicode/norm/tables13.0.0.go | 1 + .../x/text/unicode/norm/tables9.0.0.go | 1 + src/vendor/modules.txt | 8 +- 397 files changed, 25495 insertions(+), 9874 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/asm.s create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/asm_plan9_386.s create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/asm_plan9_arm.s create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/const_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/dir_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/env_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/errors_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/mkall.sh create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/mkerrors.sh create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/pwd_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/race.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/race0.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/str.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/syscall.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/syscall_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go create mode 100644 src/cmd/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/asm_zos_s390x.s create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/dev_zos.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/epoll_zos.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/fstatfs_zos.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/ioctl_zos.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go create mode 100644 src/cmd/vendor/golang.org/x/term/AUTHORS create mode 100644 src/cmd/vendor/golang.org/x/term/CONTRIBUTING.md create mode 100644 src/cmd/vendor/golang.org/x/term/CONTRIBUTORS create mode 100644 src/cmd/vendor/golang.org/x/term/LICENSE create mode 100644 src/cmd/vendor/golang.org/x/term/PATENTS create mode 100644 src/cmd/vendor/golang.org/x/term/README.md create mode 100644 src/cmd/vendor/golang.org/x/term/go.mod create mode 100644 src/cmd/vendor/golang.org/x/term/go.sum rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_plan9.go => term/term.go} (52%) create mode 100644 src/cmd/vendor/golang.org/x/term/term_plan9.go rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_solaris.go => term/term_solaris.go} (61%) rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util.go => term/term_unix.go} (53%) rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_linux.go => term/term_unix_aix.go} (74%) rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_bsd.go => term/term_unix_bsd.go} (80%) rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_aix.go => term/term_unix_linux.go} (71%) create mode 100644 src/cmd/vendor/golang.org/x/term/term_unix_zos.go create mode 100644 src/cmd/vendor/golang.org/x/term/term_unsupported.go rename src/cmd/vendor/golang.org/x/{crypto/ssh/terminal/util_windows.go => term/term_windows.go} (53%) create mode 100644 src/cmd/vendor/golang.org/x/term/terminal.go rename src/vendor/golang.org/x/crypto/internal/subtle/{aliasing_appengine.go => aliasing_purego.go} (97%) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 306143f088..d78fabe196 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -1,12 +1,13 @@ module cmd -go 1.16 +go 1.17 require ( - github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 - golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff - golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 + github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 + golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72 + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa - golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e // indirect - golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f + golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/tools v0.1.1-0.20210312185553-8e4f4c86593a ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 97fbd5c0a9..706230f4cf 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -1,18 +1,18 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 h1:HyOHhUtuB/Ruw/L5s5pG2D0kckkN2/IzBs9OClGHnHI= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff h1:XmKBi9R6duxOB3lfc72wyrwiOY7X2Jl1wuI+RFOyMDE= -golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72 h1:CdaLHkic8S6xdhpWgHmtWij2rv2DTGwPuJZjjEDGk2w= +golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa h1:++oSKjoJSsXNHyhUdK1BtBKMAaMHER+GWyKN3319OZA= golang.org/x/mod v0.4.3-0.20210310185834-19d50cac98aa/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -23,17 +23,22 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e h1:f5mksnk+hgXHnImpZoWj64ja99j9zV7YUgrVG95uFE4= -golang.org/x/sys v0.0.0-20210218145245-beda7e5e158e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f h1:R8L2zr6nSvQoIIw/EiaPP6HfmxeiArf+Nh/CWTC60wQ= -golang.org/x/tools v0.1.1-0.20210220032852-2363391a5b2f/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210312185553-8e4f4c86593a h1:dM42cKDDlU6VAcfE6/ANedIkHqAPncj3GWNGqjv0f0Q= +golang.org/x/tools v0.1.1-0.20210312185553-8e4f4c86593a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go index c0661bf4aa..0c702398d3 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go @@ -70,7 +70,11 @@ func (a *addr2LinerJob) write(s string) error { } func (a *addr2LinerJob) readLine() (string, error) { - return a.out.ReadString('\n') + s, err := a.out.ReadString('\n') + if err != nil { + return "", err + } + return strings.TrimSpace(s), nil } // close releases any resources used by the addr2liner object. @@ -115,19 +119,11 @@ func newAddr2Liner(cmd, file string, base uint64) (*addr2Liner, error) { return a, nil } -func (d *addr2Liner) readString() (string, error) { - s, err := d.rw.readLine() - if err != nil { - return "", err - } - return strings.TrimSpace(s), nil -} - // readFrame parses the addr2line output for a single address. It // returns a populated plugin.Frame and whether it has reached the end of the // data. func (d *addr2Liner) readFrame() (plugin.Frame, bool) { - funcname, err := d.readString() + funcname, err := d.rw.readLine() if err != nil { return plugin.Frame{}, true } @@ -135,12 +131,12 @@ func (d *addr2Liner) readFrame() (plugin.Frame, bool) { // If addr2line returns a hex address we can assume it is the // sentinel. Read and ignore next two lines of output from // addr2line - d.readString() - d.readString() + d.rw.readLine() + d.rw.readLine() return plugin.Frame{}, true } - fileline, err := d.readString() + fileline, err := d.rw.readLine() if err != nil { return plugin.Frame{}, true } @@ -186,7 +182,7 @@ func (d *addr2Liner) rawAddrInfo(addr uint64) ([]plugin.Frame, error) { return nil, err } - resp, err := d.readString() + resp, err := d.rw.readLine() if err != nil { return nil, err } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go index 68fa5593ad..24c48e649b 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go @@ -43,15 +43,21 @@ type llvmSymbolizerJob struct { cmd *exec.Cmd in io.WriteCloser out *bufio.Reader + // llvm-symbolizer requires the symbol type, CODE or DATA, for symbolization. + symType string } func (a *llvmSymbolizerJob) write(s string) error { - _, err := fmt.Fprint(a.in, s+"\n") + _, err := fmt.Fprintln(a.in, a.symType, s) return err } func (a *llvmSymbolizerJob) readLine() (string, error) { - return a.out.ReadString('\n') + s, err := a.out.ReadString('\n') + if err != nil { + return "", err + } + return strings.TrimSpace(s), nil } // close releases any resources used by the llvmSymbolizer object. @@ -64,13 +70,17 @@ func (a *llvmSymbolizerJob) close() { // information about the given executable file. If file is a shared // library, base should be the address at which it was mapped in the // program under consideration. -func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) { +func newLLVMSymbolizer(cmd, file string, base uint64, isData bool) (*llvmSymbolizer, error) { if cmd == "" { cmd = defaultLLVMSymbolizer } j := &llvmSymbolizerJob{ - cmd: exec.Command(cmd, "-inlining", "-demangle=false"), + cmd: exec.Command(cmd, "-inlining", "-demangle=false"), + symType: "CODE", + } + if isData { + j.symType = "DATA" } var err error @@ -97,19 +107,11 @@ func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) { return a, nil } -func (d *llvmSymbolizer) readString() (string, error) { - s, err := d.rw.readLine() - if err != nil { - return "", err - } - return strings.TrimSpace(s), nil -} - // readFrame parses the llvm-symbolizer output for a single address. It // returns a populated plugin.Frame and whether it has reached the end of the // data. func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) { - funcname, err := d.readString() + funcname, err := d.rw.readLine() if err != nil { return plugin.Frame{}, true } @@ -121,13 +123,17 @@ func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) { funcname = "" } - fileline, err := d.readString() + fileline, err := d.rw.readLine() if err != nil { return plugin.Frame{Func: funcname}, true } linenumber := 0 - if fileline == "??:0" { + // The llvm-symbolizer outputs the ::. + // When it cannot identify the source code location, it outputs "??:0:0". + // Older versions output just the filename and line number, so we check for + // both conditions here. + if fileline == "??:0" || fileline == "??:0:0" { fileline = "" } else { switch split := strings.Split(fileline, ":"); len(split) { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go index 1987bd3dab..8e0ccc728d 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go @@ -29,27 +29,42 @@ const ( defaultNM = "nm" ) -// addr2LinerNM is a connection to an nm command for obtaining address +// addr2LinerNM is a connection to an nm command for obtaining symbol // information from a binary. type addr2LinerNM struct { - m []symbolInfo // Sorted list of addresses from binary. + m []symbolInfo // Sorted list of symbol addresses from binary. } type symbolInfo struct { address uint64 + size uint64 name string + symType string } -// newAddr2LinerNM starts the given nm command reporting information about the -// given executable file. If file is a shared library, base should be -// the address at which it was mapped in the program under -// consideration. +// isData returns if the symbol has a known data object symbol type. +func (s *symbolInfo) isData() bool { + // The following symbol types are taken from https://linux.die.net/man/1/nm: + // Lowercase letter means local symbol, uppercase denotes a global symbol. + // - b or B: the symbol is in the uninitialized data section, e.g. .bss; + // - d or D: the symbol is in the initialized data section; + // - r or R: the symbol is in a read only data section; + // - v or V: the symbol is a weak object; + // - W: the symbol is a weak symbol that has not been specifically tagged as a + // weak object symbol. Experiments with some binaries, showed these to be + // mostly data objects. + return strings.ContainsAny(s.symType, "bBdDrRvVW") +} + +// newAddr2LinerNM starts the given nm command reporting information about the +// given executable file. If file is a shared library, base should be the +// address at which it was mapped in the program under consideration. func newAddr2LinerNM(cmd, file string, base uint64) (*addr2LinerNM, error) { if cmd == "" { cmd = defaultNM } var b bytes.Buffer - c := exec.Command(cmd, "-n", file) + c := exec.Command(cmd, "--numeric-sort", "--print-size", "--format=posix", file) c.Stdout = &b if err := c.Run(); err != nil { return nil, err @@ -74,17 +89,23 @@ func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) { return nil, err } line = strings.TrimSpace(line) - fields := strings.SplitN(line, " ", 3) - if len(fields) != 3 { + fields := strings.Split(line, " ") + if len(fields) != 4 { + continue + } + address, err := strconv.ParseUint(fields[2], 16, 64) + if err != nil { continue } - address, err := strconv.ParseUint(fields[0], 16, 64) + size, err := strconv.ParseUint(fields[3], 16, 64) if err != nil { continue } a.m = append(a.m, symbolInfo{ address: address + base, - name: fields[2], + size: size, + name: fields[0], + symType: fields[1], }) } @@ -94,7 +115,7 @@ func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) { // addrInfo returns the stack frame information for a specific program // address. It returns nil if the address could not be identified. func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) { - if len(a.m) == 0 || addr < a.m[0].address || addr > a.m[len(a.m)-1].address { + if len(a.m) == 0 || addr < a.m[0].address || addr >= (a.m[len(a.m)-1].address+a.m[len(a.m)-1].size) { return nil, nil } @@ -113,12 +134,11 @@ func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) { } } - // Address is between a.m[low] and a.m[high]. - // Pick low, as it represents [low, high). - f := []plugin.Frame{ - { - Func: a.m[low].name, - }, + // Address is between a.m[low] and a.m[high]. Pick low, as it represents + // [low, high). For data symbols, we use a strict check that the address is in + // the [start, start + size) range of a.m[low]. + if a.m[low].isData() && addr >= (a.m[low].address+a.m[low].size) { + return nil, nil } - return f, nil + return []plugin.Frame{{Func: a.m[low].name}}, nil } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go index 4b67cc4ab0..576a6ee66a 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go @@ -18,6 +18,7 @@ package binutils import ( "debug/elf" "debug/macho" + "debug/pe" "encoding/binary" "errors" "fmt" @@ -255,7 +256,7 @@ func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([] if !b.objdumpFound { return nil, errors.New("cannot disasm: no objdump tool available") } - args := []string{"--disassemble-all", "--demangle", "--no-show-raw-insn", + args := []string{"--disassemble", "--demangle", "--no-show-raw-insn", "--line-numbers", fmt.Sprintf("--start-address=%#x", start), fmt.Sprintf("--stop-address=%#x", end)} @@ -337,6 +338,15 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi return f, nil } + peMagic := string(header[:2]) + if peMagic == "MZ" { + f, err := b.openPE(name, start, limit, offset) + if err != nil { + return nil, fmt.Errorf("error reading PE file %s: %v", name, err) + } + return f, nil + } + return nil, fmt.Errorf("unrecognized binary format: %s", name) } @@ -440,7 +450,23 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi } } - base, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), stextOffset, start, limit, offset) + var ph *elf.ProgHeader + // For user space executables, find the actual program segment that is + // associated with the given mapping. Skip this search if limit <= start. + // We cannot use just a check on the start address of the mapping to tell if + // it's a kernel / .ko module mapping, because with quipper address remapping + // enabled, the address would be in the lower half of the address space. + if stextOffset == nil && start < limit && limit < (uint64(1)<<63) { + ph, err = elfexec.FindProgHeaderForMapping(ef, offset, limit-start) + if err != nil { + return nil, fmt.Errorf("failed to find program header for file %q, mapping pgoff %x, memsz=%x: %v", name, offset, limit-start, err) + } + } else { + // For the kernel, find the program segment that includes the .text section. + ph = elfexec.FindTextProgHeader(ef) + } + + base, err := elfexec.GetBase(&ef.FileHeader, ph, stextOffset, start, limit, offset) if err != nil { return nil, fmt.Errorf("could not identify base for %s: %v", name, err) } @@ -451,10 +477,38 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi buildID = fmt.Sprintf("%x", id) } } + isData := ph != nil && ph.Flags&elf.PF_X == 0 + if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) { + return &fileNM{file: file{b, name, base, buildID, isData}}, nil + } + return &fileAddr2Line{file: file{b, name, base, buildID, isData}}, nil +} + +func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFile, error) { + pf, err := pe.Open(name) + if err != nil { + return nil, fmt.Errorf("error parsing %s: %v", name, err) + } + defer pf.Close() + + var imageBase uint64 + switch h := pf.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(h.ImageBase) + case *pe.OptionalHeader64: + imageBase = uint64(h.ImageBase) + default: + return nil, fmt.Errorf("unknown OptionalHeader %T", pf.OptionalHeader) + } + + var base uint64 + if start > 0 { + base = start - imageBase + } if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) { - return &fileNM{file: file{b, name, base, buildID}}, nil + return &fileNM{file: file{b: b, name: name, base: base}}, nil } - return &fileAddr2Line{file: file{b, name, base, buildID}}, nil + return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil } // file implements the binutils.ObjFile interface. @@ -463,6 +517,7 @@ type file struct { name string base uint64 buildID string + isData bool } func (f *file) Name() string { @@ -538,7 +593,7 @@ func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) { } func (f *fileAddr2Line) init() { - if llvmSymbolizer, err := newLLVMSymbolizer(f.b.llvmSymbolizer, f.name, f.base); err == nil { + if llvmSymbolizer, err := newLLVMSymbolizer(f.b.llvmSymbolizer, f.name, f.base, f.isData); err == nil { f.llvmSymbolizer = llvmSymbolizer return } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go index d0be614bdc..e64adf58cd 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go @@ -19,6 +19,7 @@ import ( "io" "regexp" "strconv" + "strings" "github.com/google/pprof/internal/plugin" "github.com/ianlancetaylor/demangle" @@ -121,6 +122,7 @@ func disassemble(asm []byte) ([]plugin.Inst, error) { break } } + input = strings.TrimSpace(input) if fields := objdumpAsmOutputRE.FindStringSubmatch(input); len(fields) == 3 { if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { @@ -167,6 +169,7 @@ func nextSymbol(buf *bytes.Buffer) (uint64, string, error) { return 0, "", err } } + line = strings.TrimSpace(line) if fields := nmOutputRE.FindStringSubmatch(line); len(fields) == 4 { if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go index 878f2e1ead..3967a12d45 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go @@ -163,7 +163,7 @@ func applyCommandOverrides(cmd string, outputFormat int, cfg config) config { trim := cfg.Trim switch cmd { - case "disasm", "weblist": + case "disasm": trim = false cfg.Granularity = "addresses" // Force the 'noinlines' mode so that source locations for a given address @@ -172,6 +172,10 @@ func applyCommandOverrides(cmd string, outputFormat int, cfg config) config { // This is because the merge is done by address and in case of an inlined // stack each of the inlined entries is a separate callgraph node. cfg.NoInlines = true + case "weblist": + trim = false + cfg.Granularity = "addresses" + cfg.NoInlines = false // Need inline info to support call expansion case "peek": trim = false case "list": diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go index 4f7610c7e5..b8e8b50b94 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go @@ -62,6 +62,7 @@ a { .header .title h1 { font-size: 1.75em; margin-right: 1rem; + margin-bottom: 4px; } .header .title a { color: #212121; diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go index d520765cc9..3b3c6ee89f 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go @@ -283,3 +283,84 @@ func FindTextProgHeader(f *elf.File) *elf.ProgHeader { } return nil } + +// FindProgHeaderForMapping returns the loadable program segment header that is +// fully contained in the runtime mapping with file offset pgoff and memory size +// memsz, or an error if the segment cannot be determined. The function returns +// a nil program header and no error if the ELF binary has no loadable segments. +func FindProgHeaderForMapping(f *elf.File, pgoff, memsz uint64) (*elf.ProgHeader, error) { + var headers []*elf.ProgHeader + loadables := 0 + for _, p := range f.Progs { + if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz { + headers = append(headers, &p.ProgHeader) + } + if p.Type == elf.PT_LOAD { + loadables++ + } + } + if len(headers) == 1 { + return headers[0], nil + } + // Some ELF files don't contain any program segments, e.g. .ko loadable kernel + // modules. Don't return an error in such cases. + if loadables == 0 { + return nil, nil + } + if len(headers) == 0 { + return nil, fmt.Errorf("no program header matches file offset %x and memory size %x", pgoff, memsz) + } + + // Segments are mapped page aligned. In some cases, segments may be smaller + // than a page, which causes the next segment to start at a file offset that + // is logically on the same page if we were to align file offsets by page. + // Example: + // LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 + // 0x00000000000006fc 0x00000000000006fc R E 0x200000 + // LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 + // 0x0000000000000230 0x0000000000000238 RW 0x200000 + // + // In this case, perf records the following mappings for this executable: + // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x400000(0x1000) @ 0 00:3c 512041 0]: r-xp exename + // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x600000(0x2000) @ 0 00:3c 512041 0]: rw-p exename + // + // Both mappings have file offset 0. The first mapping is one page length and + // it can include only the first loadable segment. Due to page alignment, the + // second mapping starts also at file offset 0, and it spans two pages. It can + // include both the first and the second loadable segments. We must return the + // correct program header to compute the correct base offset. + // + // We cannot use the mapping protections to distinguish between segments, + // because protections are not passed through to this function. + // We cannot use the start address to differentiate between segments, because + // with ASLR, the mapping start address can be any value. + // + // We use a heuristic to compute the minimum mapping size required for a + // segment, assuming mappings are 4k page aligned, and return the segment that + // matches the given mapping size. + const pageSize = 4096 + + // The memory size based heuristic makes sense only if the mapping size is a + // multiple of 4k page size. + if memsz%pageSize != 0 { + return nil, fmt.Errorf("mapping size = %x and %d segments match the passed in mapping", memsz, len(headers)) + } + + // Return an error if no segment, or multiple segments match the size, so we can debug. + var ph *elf.ProgHeader + pageMask := ^uint64(pageSize - 1) + for _, h := range headers { + wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask) + if wantSize != memsz { + continue + } + if ph != nil { + return nil, fmt.Errorf("found second program header (%#v) that matches memsz %x, first program header is %#v", *h, memsz, *ph) + } + ph = h + } + if ph == nil { + return nil, fmt.Errorf("found %d matching program headers, but none matches mapping size %x", len(headers), memsz) + } + return ph, nil +} diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go index 8cb87da9af..8008675248 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go @@ -322,8 +322,8 @@ func (b *builder) addEdge(edge *Edge, from, to int, hasNodelets bool) { } // dotColor returns a color for the given score (between -1.0 and -// 1.0), with -1.0 colored red, 0.0 colored grey, and 1.0 colored -// green. If isBackground is true, then a light (low-saturation) +// 1.0), with -1.0 colored green, 0.0 colored grey, and 1.0 colored +// red. If isBackground is true, then a light (low-saturation) // color is returned (suitable for use as a background color); // otherwise, a darker color is returned (suitable for use as a // foreground color). diff --git a/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go index e95b261bc2..53325740a3 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go @@ -111,8 +111,9 @@ func compatibleValueTypes(v1, v2 *profile.ValueType) bool { } return v1.Unit == v2.Unit || - (isTimeUnit(v1.Unit) && isTimeUnit(v2.Unit)) || - (isMemoryUnit(v1.Unit) && isMemoryUnit(v2.Unit)) + (timeUnits.sniffUnit(v1.Unit) != nil && timeUnits.sniffUnit(v2.Unit) != nil) || + (memoryUnits.sniffUnit(v1.Unit) != nil && memoryUnits.sniffUnit(v2.Unit) != nil) || + (gcuUnits.sniffUnit(v1.Unit) != nil && gcuUnits.sniffUnit(v2.Unit) != nil) } // Scale a measurement from an unit to a different unit and returns @@ -124,12 +125,15 @@ func Scale(value int64, fromUnit, toUnit string) (float64, string) { v, u := Scale(-value, fromUnit, toUnit) return -v, u } - if m, u, ok := memoryLabel(value, fromUnit, toUnit); ok { + if m, u, ok := memoryUnits.convertUnit(value, fromUnit, toUnit); ok { return m, u } - if t, u, ok := timeLabel(value, fromUnit, toUnit); ok { + if t, u, ok := timeUnits.convertUnit(value, fromUnit, toUnit); ok { return t, u } + if g, u, ok := gcuUnits.convertUnit(value, fromUnit, toUnit); ok { + return g, u + } // Skip non-interesting units. switch toUnit { case "count", "sample", "unit", "minimum", "auto": @@ -172,157 +176,121 @@ func Percentage(value, total int64) string { } } -// isMemoryUnit returns whether a name is recognized as a memory size -// unit. -func isMemoryUnit(unit string) bool { - switch strings.TrimSuffix(strings.ToLower(unit), "s") { - case "byte", "b", "kilobyte", "kb", "megabyte", "mb", "gigabyte", "gb": - return true - } - return false +// unit includes a list of aliases representing a specific unit and a factor +// which one can multiple a value in the specified unit by to get the value +// in terms of the base unit. +type unit struct { + canonicalName string + aliases []string + factor float64 } -func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) { - fromUnit = strings.TrimSuffix(strings.ToLower(fromUnit), "s") - toUnit = strings.TrimSuffix(strings.ToLower(toUnit), "s") - - switch fromUnit { - case "byte", "b": - case "kb", "kbyte", "kilobyte": - value *= 1024 - case "mb", "mbyte", "megabyte": - value *= 1024 * 1024 - case "gb", "gbyte", "gigabyte": - value *= 1024 * 1024 * 1024 - case "tb", "tbyte", "terabyte": - value *= 1024 * 1024 * 1024 * 1024 - case "pb", "pbyte", "petabyte": - value *= 1024 * 1024 * 1024 * 1024 * 1024 - default: - return 0, "", false - } +// unitType includes a list of units that are within the same category (i.e. +// memory or time units) and a default unit to use for this type of unit. +type unitType struct { + defaultUnit unit + units []unit +} - if toUnit == "minimum" || toUnit == "auto" { - switch { - case value < 1024: - toUnit = "b" - case value < 1024*1024: - toUnit = "kb" - case value < 1024*1024*1024: - toUnit = "mb" - case value < 1024*1024*1024*1024: - toUnit = "gb" - case value < 1024*1024*1024*1024*1024: - toUnit = "tb" - default: - toUnit = "pb" +// findByAlias returns the unit associated with the specified alias. It returns +// nil if the unit with such alias is not found. +func (ut unitType) findByAlias(alias string) *unit { + for _, u := range ut.units { + for _, a := range u.aliases { + if alias == a { + return &u + } } } - - var output float64 - switch toUnit { - default: - output, toUnit = float64(value), "B" - case "kb", "kbyte", "kilobyte": - output, toUnit = float64(value)/1024, "kB" - case "mb", "mbyte", "megabyte": - output, toUnit = float64(value)/(1024*1024), "MB" - case "gb", "gbyte", "gigabyte": - output, toUnit = float64(value)/(1024*1024*1024), "GB" - case "tb", "tbyte", "terabyte": - output, toUnit = float64(value)/(1024*1024*1024*1024), "TB" - case "pb", "pbyte", "petabyte": - output, toUnit = float64(value)/(1024*1024*1024*1024*1024), "PB" - } - return output, toUnit, true + return nil } -// isTimeUnit returns whether a name is recognized as a time unit. -func isTimeUnit(unit string) bool { +// sniffUnit simpifies the input alias and returns the unit associated with the +// specified alias. It returns nil if the unit with such alias is not found. +func (ut unitType) sniffUnit(unit string) *unit { unit = strings.ToLower(unit) if len(unit) > 2 { unit = strings.TrimSuffix(unit, "s") } - - switch unit { - case "nanosecond", "ns", "microsecond", "millisecond", "ms", "s", "second", "sec", "hr", "day", "week", "year": - return true - } - return false + return ut.findByAlias(unit) } -func timeLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) { - fromUnit = strings.ToLower(fromUnit) - if len(fromUnit) > 2 { - fromUnit = strings.TrimSuffix(fromUnit, "s") +// autoScale takes in the value with units of the base unit and returns +// that value scaled to a reasonable unit if a reasonable unit is +// found. +func (ut unitType) autoScale(value float64) (float64, string, bool) { + var f float64 + var unit string + for _, u := range ut.units { + if u.factor >= f && (value/u.factor) >= 1.0 { + f = u.factor + unit = u.canonicalName + } } - - toUnit = strings.ToLower(toUnit) - if len(toUnit) > 2 { - toUnit = strings.TrimSuffix(toUnit, "s") + if f == 0 { + return 0, "", false } + return value / f, unit, true +} - var d time.Duration - switch fromUnit { - case "nanosecond", "ns": - d = time.Duration(value) * time.Nanosecond - case "microsecond": - d = time.Duration(value) * time.Microsecond - case "millisecond", "ms": - d = time.Duration(value) * time.Millisecond - case "second", "sec", "s": - d = time.Duration(value) * time.Second - case "cycle": - return float64(value), "", true - default: +// convertUnit converts a value from the fromUnit to the toUnit, autoscaling +// the value if the toUnit is "minimum" or "auto". If the fromUnit is not +// included in the unitType, then a false boolean will be returned. If the +// toUnit is not in the unitType, the value will be returned in terms of the +// default unitType. +func (ut unitType) convertUnit(value int64, fromUnitStr, toUnitStr string) (float64, string, bool) { + fromUnit := ut.sniffUnit(fromUnitStr) + if fromUnit == nil { return 0, "", false } - - if toUnit == "minimum" || toUnit == "auto" { - switch { - case d < 1*time.Microsecond: - toUnit = "ns" - case d < 1*time.Millisecond: - toUnit = "us" - case d < 1*time.Second: - toUnit = "ms" - case d < 1*time.Minute: - toUnit = "sec" - case d < 1*time.Hour: - toUnit = "min" - case d < 24*time.Hour: - toUnit = "hour" - case d < 15*24*time.Hour: - toUnit = "day" - case d < 120*24*time.Hour: - toUnit = "week" - default: - toUnit = "year" + v := float64(value) * fromUnit.factor + if toUnitStr == "minimum" || toUnitStr == "auto" { + if v, u, ok := ut.autoScale(v); ok { + return v, u, true } + return v / ut.defaultUnit.factor, ut.defaultUnit.canonicalName, true } - - var output float64 - dd := float64(d) - switch toUnit { - case "ns", "nanosecond": - output, toUnit = dd/float64(time.Nanosecond), "ns" - case "us", "microsecond": - output, toUnit = dd/float64(time.Microsecond), "us" - case "ms", "millisecond": - output, toUnit = dd/float64(time.Millisecond), "ms" - case "min", "minute": - output, toUnit = dd/float64(time.Minute), "mins" - case "hour", "hr": - output, toUnit = dd/float64(time.Hour), "hrs" - case "day": - output, toUnit = dd/float64(24*time.Hour), "days" - case "week", "wk": - output, toUnit = dd/float64(7*24*time.Hour), "wks" - case "year", "yr": - output, toUnit = dd/float64(365*24*time.Hour), "yrs" - default: - // "sec", "second", "s" handled by default case. - output, toUnit = dd/float64(time.Second), "s" + toUnit := ut.sniffUnit(toUnitStr) + if toUnit == nil { + return v / ut.defaultUnit.factor, ut.defaultUnit.canonicalName, true } - return output, toUnit, true + return v / toUnit.factor, toUnit.canonicalName, true +} + +var memoryUnits = unitType{ + units: []unit{ + {"B", []string{"b", "byte"}, 1}, + {"kB", []string{"kb", "kbyte", "kilobyte"}, float64(1 << 10)}, + {"MB", []string{"mb", "mbyte", "megabyte"}, float64(1 << 20)}, + {"GB", []string{"gb", "gbyte", "gigabyte"}, float64(1 << 30)}, + {"TB", []string{"tb", "tbyte", "terabyte"}, float64(1 << 40)}, + {"PB", []string{"pb", "pbyte", "petabyte"}, float64(1 << 50)}, + }, + defaultUnit: unit{"B", []string{"b", "byte"}, 1}, +} + +var timeUnits = unitType{ + units: []unit{ + {"ns", []string{"ns", "nanosecond"}, float64(time.Nanosecond)}, + {"us", []string{"μs", "us", "microsecond"}, float64(time.Microsecond)}, + {"ms", []string{"ms", "millisecond"}, float64(time.Millisecond)}, + {"s", []string{"s", "sec", "second"}, float64(time.Second)}, + {"hrs", []string{"hour", "hr"}, float64(time.Hour)}, + }, + defaultUnit: unit{"s", []string{}, float64(time.Second)}, +} + +var gcuUnits = unitType{ + units: []unit{ + {"n*GCU", []string{"nanogcu"}, 1e-9}, + {"u*GCU", []string{"microgcu"}, 1e-6}, + {"m*GCU", []string{"milligcu"}, 1e-3}, + {"GCU", []string{"gcu"}, 1}, + {"k*GCU", []string{"kilogcu"}, 1e3}, + {"M*GCU", []string{"megagcu"}, 1e6}, + {"G*GCU", []string{"gigagcu"}, 1e9}, + {"T*GCU", []string{"teragcu"}, 1e12}, + {"P*GCU", []string{"petagcu"}, 1e15}, + }, + defaultUnit: unit{"GCU", []string{}, 1.0}, } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go index b480535439..4f841eff5d 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go @@ -24,12 +24,15 @@ import ( "io" "os" "path/filepath" + "regexp" + "sort" "strconv" "strings" "github.com/google/pprof/internal/graph" "github.com/google/pprof/internal/measurement" "github.com/google/pprof/internal/plugin" + "github.com/google/pprof/profile" ) // printSource prints an annotated source listing, include all @@ -126,191 +129,554 @@ func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error { return nil } +// sourcePrinter holds state needed for generating source+asm HTML listing. +type sourcePrinter struct { + reader *sourceReader + objectTool plugin.ObjTool + objects map[string]plugin.ObjFile // Opened object files + sym *regexp.Regexp // May be nil + files map[string]*sourceFile // Set of files to print. + insts map[uint64]instructionInfo // Instructions of interest (keyed by address). + + // Set of function names that we are interested in (because they had + // a sample and match sym). + interest map[string]bool + + // Mapping from system function names to printable names. + prettyNames map[string]string +} + +// instructionInfo holds collected information for an instruction. +type instructionInfo struct { + objAddr uint64 // Address in object file (with base subtracted out) + length int // Instruction length in bytes + disasm string // Disassembly of instruction + file string // For top-level function in which instruction occurs + line int // For top-level function in which instruction occurs + flat, cum int64 // Samples to report (divisor already applied) +} + +// sourceFile contains collected information for files we will print. +type sourceFile struct { + fname string + cum int64 + flat int64 + lines map[int][]sourceInst // Instructions to show per line + funcName map[int]string // Function name per line +} + +// sourceInst holds information for an instruction to be displayed. +type sourceInst struct { + addr uint64 + stack []callID // Inlined call-stack +} + +// sourceFunction contains information for a contiguous range of lines per function we +// will print. +type sourceFunction struct { + name string + begin, end int // Line numbers (end is not included in the range) + flat, cum int64 +} + +// addressRange is a range of addresses plus the object file that contains it. +type addressRange struct { + begin, end uint64 + obj plugin.ObjFile + mapping *profile.Mapping + score int64 // Used to order ranges for processing +} + // PrintWebList prints annotated source listing of rpt to w. +// rpt.prof should contain inlined call info. func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) error { - o := rpt.options - g := rpt.newGraph(nil) + sourcePath := rpt.options.SourcePath + if sourcePath == "" { + wd, err := os.Getwd() + if err != nil { + return fmt.Errorf("could not stat current dir: %v", err) + } + sourcePath = wd + } + sp := newSourcePrinter(rpt, obj, sourcePath) + sp.print(w, maxFiles, rpt) + sp.close() + return nil +} + +func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourcePrinter { + sp := &sourcePrinter{ + reader: newSourceReader(sourcePath, rpt.options.TrimPath), + objectTool: obj, + objects: map[string]plugin.ObjFile{}, + sym: rpt.options.Symbol, + files: map[string]*sourceFile{}, + insts: map[uint64]instructionInfo{}, + prettyNames: map[string]string{}, + interest: map[string]bool{}, + } // If the regexp source can be parsed as an address, also match // functions that land on that address. var address *uint64 - if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil { - address = &hex + if sp.sym != nil { + if hex, err := strconv.ParseUint(sp.sym.String(), 0, 64); err == nil { + address = &hex + } } - sourcePath := o.SourcePath - if sourcePath == "" { - wd, err := os.Getwd() - if err != nil { - return fmt.Errorf("could not stat current dir: %v", err) + addrs := map[uint64]bool{} + flat := map[uint64]int64{} + cum := map[uint64]int64{} + + // Record an interest in the function corresponding to lines[index]. + markInterest := func(addr uint64, lines []profile.Line, index int) { + fn := lines[index] + if fn.Function == nil { + return } - sourcePath = wd + sp.interest[fn.Function.Name] = true + sp.interest[fn.Function.SystemName] = true + addrs[addr] = true } - reader := newSourceReader(sourcePath, o.TrimPath) - type fileFunction struct { - fileName, functionName string + // See if sp.sym matches line. + matches := func(line profile.Line) bool { + if line.Function == nil { + return false + } + return sp.sym.MatchString(line.Function.Name) || + sp.sym.MatchString(line.Function.SystemName) || + sp.sym.MatchString(line.Function.Filename) } - // Extract interesting symbols from binary files in the profile and - // classify samples per symbol. - symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj) - symNodes := nodesPerSymbol(g.Nodes, symbols) + // Extract sample counts and compute set of interesting functions. + for _, sample := range rpt.prof.Sample { + value := rpt.options.SampleValue(sample.Value) + if rpt.options.SampleMeanDivisor != nil { + div := rpt.options.SampleMeanDivisor(sample.Value) + if div != 0 { + value /= div + } + } + + // Find call-sites matching sym. + for i := len(sample.Location) - 1; i >= 0; i-- { + loc := sample.Location[i] + for _, line := range loc.Line { + if line.Function == nil { + continue + } + sp.prettyNames[line.Function.SystemName] = line.Function.Name + } - // Identify sources associated to a symbol by examining - // symbol samples. Classify samples per source file. - fileNodes := make(map[fileFunction]graph.Nodes) - if len(symNodes) == 0 { - for _, n := range g.Nodes { - if n.Info.File == "" || !o.Symbol.MatchString(n.Info.Name) { + cum[loc.Address] += value + if i == 0 { + flat[loc.Address] += value + } + + if sp.sym == nil || (address != nil && loc.Address == *address) { + // Interested in top-level entry of stack. + if len(loc.Line) > 0 { + markInterest(loc.Address, loc.Line, len(loc.Line)-1) + } continue } - ff := fileFunction{n.Info.File, n.Info.Name} - fileNodes[ff] = append(fileNodes[ff], n) - } - } else { - for _, nodes := range symNodes { - for _, n := range nodes { - if n.Info.File != "" { - ff := fileFunction{n.Info.File, n.Info.Name} - fileNodes[ff] = append(fileNodes[ff], n) + + // Seach in inlined stack for a match. + matchFile := (loc.Mapping != nil && sp.sym.MatchString(loc.Mapping.File)) + for j, line := range loc.Line { + if (j == 0 && matchFile) || matches(line) { + markInterest(loc.Address, loc.Line, j) } } } } - if len(fileNodes) == 0 { - return fmt.Errorf("no source information for %s", o.Symbol.String()) - } - - sourceFiles := make(graph.Nodes, 0, len(fileNodes)) - for _, nodes := range fileNodes { - sNode := *nodes[0] - sNode.Flat, sNode.Cum = nodes.Sum() - sourceFiles = append(sourceFiles, &sNode) - } + sp.expandAddresses(rpt, addrs, flat) + sp.initSamples(flat, cum) + return sp +} - // Limit number of files printed? - if maxFiles < 0 { - sourceFiles.Sort(graph.FileOrder) - } else { - sourceFiles.Sort(graph.FlatNameOrder) - if maxFiles < len(sourceFiles) { - sourceFiles = sourceFiles[:maxFiles] +func (sp *sourcePrinter) close() { + for _, objFile := range sp.objects { + if objFile != nil { + objFile.Close() } } +} - // Print each file associated with this function. - for _, n := range sourceFiles { - ff := fileFunction{n.Info.File, n.Info.Name} - fns := fileNodes[ff] +func (sp *sourcePrinter) expandAddresses(rpt *Report, addrs map[uint64]bool, flat map[uint64]int64) { + // We found interesting addresses (ones with non-zero samples) above. + // Get covering address ranges and disassemble the ranges. + ranges := sp.splitIntoRanges(rpt.prof, addrs, flat) - asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj, o.IntelSyntax) - start, end := sourceCoordinates(asm) + // Trim ranges if there are too many. + const maxRanges = 25 + sort.Slice(ranges, func(i, j int) bool { + return ranges[i].score > ranges[j].score + }) + if len(ranges) > maxRanges { + ranges = ranges[:maxRanges] + } - fnodes, path, err := getSourceFromFile(ff.fileName, reader, fns, start, end) + for _, r := range ranges { + base := r.obj.Base() + insts, err := sp.objectTool.Disasm(r.mapping.File, r.begin-base, r.end-base, + rpt.options.IntelSyntax) if err != nil { - fnodes, path = getMissingFunctionSource(ff.fileName, asm, start, end) + // TODO(sanjay): Report that the covered addresses are missing. + continue } - printFunctionHeader(w, ff.functionName, path, n.Flat, n.Cum, rpt) - for _, fn := range fnodes { - printFunctionSourceLine(w, fn, asm[fn.Info.Lineno], reader, rpt) + var lastFrames []plugin.Frame + var lastAddr, maxAddr uint64 + for i, inst := range insts { + addr := inst.Addr + base + + // Guard against duplicate output from Disasm. + if addr <= maxAddr { + continue + } + maxAddr = addr + + length := 1 + if i+1 < len(insts) && insts[i+1].Addr > inst.Addr { + // Extend to next instruction. + length = int(insts[i+1].Addr - inst.Addr) + } + + // Get inlined-call-stack for address. + frames, err := r.obj.SourceLine(addr) + if err != nil { + // Construct a frame from disassembler output. + frames = []plugin.Frame{{Func: inst.Function, File: inst.File, Line: inst.Line}} + } + + x := instructionInfo{objAddr: inst.Addr, length: length, disasm: inst.Text} + if len(frames) > 0 { + // We could consider using the outer-most caller's source + // location so we give the some hint as to where the + // inlining happened that led to this instruction. So for + // example, suppose we have the following (inlined) call + // chains for this instruction: + // F1->G->H + // F2->G->H + // We could tag the instructions from the first call with + // F1 and instructions from the second call with F2. But + // that leads to a somewhat confusing display. So for now, + // we stick with just the inner-most location (i.e., H). + // In the future we will consider changing the display to + // make caller info more visible. + index := 0 // Inner-most frame + x.file = frames[index].File + x.line = frames[index].Line + } + sp.insts[addr] = x + + // We sometimes get instructions with a zero reported line number. + // Make such instructions have the same line info as the preceding + // instruction, if an earlier instruction is found close enough. + const neighborhood = 32 + if len(frames) > 0 && frames[0].Line != 0 { + lastFrames = frames + lastAddr = addr + } else if (addr-lastAddr <= neighborhood) && lastFrames != nil { + frames = lastFrames + } + + // See if the stack contains a function we are interested in. + for i, f := range frames { + if !sp.interest[f.Func] { + continue + } + + // Record sub-stack under frame's file/line. + fname := canonicalizeFileName(f.File) + file := sp.files[fname] + if file == nil { + file = &sourceFile{ + fname: fname, + lines: map[int][]sourceInst{}, + funcName: map[int]string{}, + } + sp.files[fname] = file + } + callees := frames[:i] + stack := make([]callID, 0, len(callees)) + for j := len(callees) - 1; j >= 0; j-- { // Reverse so caller is first + stack = append(stack, callID{ + file: callees[j].File, + line: callees[j].Line, + }) + } + file.lines[f.Line] = append(file.lines[f.Line], sourceInst{addr, stack}) + + // Remember the first function name encountered per source line + // and assume that that line belongs to that function. + if _, ok := file.funcName[f.Line]; !ok { + file.funcName[f.Line] = f.Func + } + } } - printFunctionClosing(w) } - return nil } -// sourceCoordinates returns the lowest and highest line numbers from -// a set of assembly statements. -func sourceCoordinates(asm map[int][]assemblyInstruction) (start, end int) { - for l := range asm { - if start == 0 || l < start { - start = l +// splitIntoRanges converts the set of addresses we are interested in into a set of address +// ranges to disassemble. +func (sp *sourcePrinter) splitIntoRanges(prof *profile.Profile, set map[uint64]bool, flat map[uint64]int64) []addressRange { + // List of mappings so we can stop expanding address ranges at mapping boundaries. + mappings := append([]*profile.Mapping{}, prof.Mapping...) + sort.Slice(mappings, func(i, j int) bool { return mappings[i].Start < mappings[j].Start }) + + var result []addressRange + addrs := make([]uint64, 0, len(set)) + for addr := range set { + addrs = append(addrs, addr) + } + sort.Slice(addrs, func(i, j int) bool { return addrs[i] < addrs[j] }) + + mappingIndex := 0 + const expand = 500 // How much to expand range to pick up nearby addresses. + for i, n := 0, len(addrs); i < n; { + begin, end := addrs[i], addrs[i] + sum := flat[begin] + i++ + + // Advance to mapping containing addrs[i] + for mappingIndex < len(mappings) && mappings[mappingIndex].Limit <= begin { + mappingIndex++ + } + if mappingIndex >= len(mappings) { + // TODO(sanjay): Report missed address and its samples. + break + } + m := mappings[mappingIndex] + obj := sp.objectFile(m) + if obj == nil { + // TODO(sanjay): Report missed address and its samples. + continue + } + + // Find following addresses that are close enough to addrs[i]. + for i < n && addrs[i] <= end+2*expand && addrs[i] < m.Limit { + // When we expand ranges by "expand" on either side, the ranges + // for addrs[i] and addrs[i-1] will merge. + end = addrs[i] + sum += flat[end] + i++ } - if end == 0 || l > end { - end = l + if m.Start-begin >= expand { + begin -= expand + } else { + begin = m.Start + } + if m.Limit-end >= expand { + end += expand + } else { + end = m.Limit } + + result = append(result, addressRange{begin, end, obj, m, sum}) } - return start, end + return result } -// assemblyPerSourceLine disassembles the binary containing a symbol -// and classifies the assembly instructions according to its -// corresponding source line, annotating them with a set of samples. -func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj plugin.ObjTool, intelSyntax bool) map[int][]assemblyInstruction { - assembly := make(map[int][]assemblyInstruction) - // Identify symbol to use for this collection of samples. - o := findMatchingSymbol(objSyms, rs) - if o == nil { - return assembly +func (sp *sourcePrinter) initSamples(flat, cum map[uint64]int64) { + for addr, inst := range sp.insts { + // Move all samples that were assigned to the middle of an instruction to the + // beginning of that instruction. This takes care of samples that were recorded + // against pc+1. + instEnd := addr + uint64(inst.length) + for p := addr; p < instEnd; p++ { + inst.flat += flat[p] + inst.cum += cum[p] + } + sp.insts[addr] = inst } +} - // Extract assembly for matched symbol - insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End, intelSyntax) - if err != nil { - return assembly - } - - srcBase := filepath.Base(src) - anodes := annotateAssembly(insts, rs, o.base) - var lineno = 0 - var prevline = 0 - for _, an := range anodes { - // Do not rely solely on the line number produced by Disasm - // since it is not what we want in the presence of inlining. - // - // E.g., suppose we are printing source code for F and this - // instruction is from H where F called G called H and both - // of those calls were inlined. We want to use the line - // number from F, not from H (which is what Disasm gives us). - // - // So find the outer-most linenumber in the source file. - found := false - if frames, err := o.file.SourceLine(an.address + o.base); err == nil { - for i := len(frames) - 1; i >= 0; i-- { - if filepath.Base(frames[i].File) == srcBase { - for j := i - 1; j >= 0; j-- { - an.inlineCalls = append(an.inlineCalls, callID{frames[j].File, frames[j].Line}) - } - lineno = frames[i].Line - found = true - break +func (sp *sourcePrinter) print(w io.Writer, maxFiles int, rpt *Report) { + // Finalize per-file counts. + for _, file := range sp.files { + seen := map[uint64]bool{} + for _, line := range file.lines { + for _, x := range line { + if seen[x.addr] { + // Same address can be displayed multiple times in a file + // (e.g., if we show multiple inlined functions). + // Avoid double-counting samples in this case. + continue } + seen[x.addr] = true + inst := sp.insts[x.addr] + file.cum += inst.cum + file.flat += inst.flat } } - if !found && filepath.Base(an.file) == srcBase { - lineno = an.line + } + + // Get sorted list of files to print. + var files []*sourceFile + for _, f := range sp.files { + files = append(files, f) + } + order := func(i, j int) bool { return files[i].flat > files[j].flat } + if maxFiles < 0 { + // Order by name for compatibility with old code. + order = func(i, j int) bool { return files[i].fname < files[j].fname } + maxFiles = len(files) + } + sort.Slice(files, order) + for i, f := range files { + if i < maxFiles { + sp.printFile(w, f, rpt) + } + } +} + +func (sp *sourcePrinter) printFile(w io.Writer, f *sourceFile, rpt *Report) { + for _, fn := range sp.functions(f) { + if fn.cum == 0 { + continue } + printFunctionHeader(w, fn.name, f.fname, fn.flat, fn.cum, rpt) + var asm []assemblyInstruction + for l := fn.begin; l < fn.end; l++ { + lineContents, ok := sp.reader.line(f.fname, l) + if !ok { + if len(f.lines[l]) == 0 { + // Outside of range of valid lines and nothing to print. + continue + } + if l == 0 { + // Line number 0 shows up if line number is not known. + lineContents = "" + } else { + // Past end of file, but have data to print. + lineContents = "???" + } + } - if lineno != 0 { - if lineno != prevline { - // This instruction starts a new block - // of contiguous instructions on this line. - an.startsBlock = true + // Make list of assembly instructions. + asm = asm[:0] + var flatSum, cumSum int64 + var lastAddr uint64 + for _, inst := range f.lines[l] { + addr := inst.addr + x := sp.insts[addr] + flatSum += x.flat + cumSum += x.cum + startsBlock := (addr != lastAddr+uint64(sp.insts[lastAddr].length)) + lastAddr = addr + + // divisors already applied, so leave flatDiv,cumDiv as 0 + asm = append(asm, assemblyInstruction{ + address: x.objAddr, + instruction: x.disasm, + function: fn.name, + file: x.file, + line: x.line, + flat: x.flat, + cum: x.cum, + startsBlock: startsBlock, + inlineCalls: inst.stack, + }) } - prevline = lineno - assembly[lineno] = append(assembly[lineno], an) + + printFunctionSourceLine(w, l, flatSum, cumSum, lineContents, asm, sp.reader, rpt) } + printFunctionClosing(w) } - - return assembly } -// findMatchingSymbol looks for the symbol that corresponds to a set -// of samples, by comparing their addresses. -func findMatchingSymbol(objSyms []*objSymbol, ns graph.Nodes) *objSymbol { - for _, n := range ns { - for _, o := range objSyms { - if filepath.Base(o.sym.File) == filepath.Base(n.Info.Objfile) && - o.sym.Start <= n.Info.Address-o.base && - n.Info.Address-o.base <= o.sym.End { - return o +// functions splits apart the lines to show in a file into a list of per-function ranges. +func (sp *sourcePrinter) functions(f *sourceFile) []sourceFunction { + var funcs []sourceFunction + + // Get interesting lines in sorted order. + lines := make([]int, 0, len(f.lines)) + for l := range f.lines { + lines = append(lines, l) + } + sort.Ints(lines) + + // Merge adjacent lines that are in same function and not too far apart. + const mergeLimit = 20 + for _, l := range lines { + name := f.funcName[l] + if pretty, ok := sp.prettyNames[name]; ok { + // Use demangled name if available. + name = pretty + } + + fn := sourceFunction{name: name, begin: l, end: l + 1} + for _, x := range f.lines[l] { + inst := sp.insts[x.addr] + fn.flat += inst.flat + fn.cum += inst.cum + } + + // See if we should merge into preceding function. + if len(funcs) > 0 { + last := funcs[len(funcs)-1] + if l-last.end < mergeLimit && last.name == name { + last.end = l + 1 + last.flat += fn.flat + last.cum += fn.cum + funcs[len(funcs)-1] = last + continue } } + + // Add new function. + funcs = append(funcs, fn) } - return nil + + // Expand function boundaries to show neighborhood. + const expand = 5 + for i, f := range funcs { + if i == 0 { + // Extend backwards, stopping at line number 1, but do not disturb 0 + // since that is a special line number that can show up when addr2line + // cannot determine the real line number. + if f.begin > expand { + f.begin -= expand + } else if f.begin > 1 { + f.begin = 1 + } + } else { + // Find gap from predecessor and divide between predecessor and f. + halfGap := (f.begin - funcs[i-1].end) / 2 + if halfGap > expand { + halfGap = expand + } + funcs[i-1].end += halfGap + f.begin -= halfGap + } + funcs[i] = f + } + + // Also extend the ending point of the last function. + if len(funcs) > 0 { + funcs[len(funcs)-1].end += expand + } + + return funcs +} + +// objectFile return the object for the named file, opening it if necessary. +// It returns nil on error. +func (sp *sourcePrinter) objectFile(m *profile.Mapping) plugin.ObjFile { + if object, ok := sp.objects[m.File]; ok { + return object // May be nil if we detected an error earlier. + } + object, err := sp.objectTool.Open(m.File, m.Start, m.Limit, m.Offset) + if err != nil { + object = nil + } + sp.objects[m.File] = object // Cache even on error. + return object } // printHeader prints the page header for a weblist report. @@ -348,22 +714,23 @@ func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, } // printFunctionSourceLine prints a source line and the corresponding assembly. -func printFunctionSourceLine(w io.Writer, fn *graph.Node, assembly []assemblyInstruction, reader *sourceReader, rpt *Report) { +func printFunctionSourceLine(w io.Writer, lineNo int, flat, cum int64, lineContents string, + assembly []assemblyInstruction, reader *sourceReader, rpt *Report) { if len(assembly) == 0 { fmt.Fprintf(w, " %6d %10s %10s %8s %s \n", - fn.Info.Lineno, - valueOrDot(fn.Flat, rpt), valueOrDot(fn.Cum, rpt), - "", template.HTMLEscapeString(fn.Info.Name)) + lineNo, + valueOrDot(flat, rpt), valueOrDot(cum, rpt), + "", template.HTMLEscapeString(lineContents)) return } fmt.Fprintf(w, " %6d %10s %10s %8s %s ", - fn.Info.Lineno, - valueOrDot(fn.Flat, rpt), valueOrDot(fn.Cum, rpt), - "", template.HTMLEscapeString(fn.Info.Name)) - srcIndent := indentation(fn.Info.Name) + lineNo, + valueOrDot(flat, rpt), valueOrDot(cum, rpt), + "", template.HTMLEscapeString(lineContents)) + srcIndent := indentation(lineContents) fmt.Fprint(w, "") var curCalls []callID for i, an := range assembly { @@ -374,15 +741,9 @@ func printFunctionSourceLine(w io.Writer, fn *graph.Node, assembly []assemblyIns var fileline string if an.file != "" { - fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.file), an.line) + fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(filepath.Base(an.file)), an.line) } flat, cum := an.flat, an.cum - if an.flatDiv != 0 { - flat = flat / an.flatDiv - } - if an.cumDiv != 0 { - cum = cum / an.cumDiv - } // Print inlined call context. for j, c := range an.inlineCalls { @@ -398,15 +759,18 @@ func printFunctionSourceLine(w io.Writer, fn *graph.Node, assembly []assemblyIns text := strings.Repeat(" ", srcIndent+4+4*j) + strings.TrimSpace(fline) fmt.Fprintf(w, " %8s %10s %10s %8s %s %s:%d\n", "", "", "", "", - template.HTMLEscapeString(fmt.Sprintf("%-80s", text)), + template.HTMLEscapeString(rightPad(text, 80)), template.HTMLEscapeString(filepath.Base(c.file)), c.line) } curCalls = an.inlineCalls text := strings.Repeat(" ", srcIndent+4+4*len(curCalls)) + an.instruction fmt.Fprintf(w, " %8s %10s %10s %8x: %s %s\n", "", valueOrDot(flat, rpt), valueOrDot(cum, rpt), an.address, - template.HTMLEscapeString(fmt.Sprintf("%-80s", text)), - template.HTMLEscapeString(fileline)) + template.HTMLEscapeString(rightPad(text, 80)), + // fileline should not be escaped since it was formed by appending + // line number (just digits) to an escaped file name. Escaping here + // would cause double-escaping of file name. + fileline) } fmt.Fprintln(w, "") } @@ -482,36 +846,6 @@ func getSourceFromFile(file string, reader *sourceReader, fns graph.Nodes, start return src, file, nil } -// getMissingFunctionSource creates a dummy function body to point to -// the source file and annotates it with the samples in asm. -func getMissingFunctionSource(filename string, asm map[int][]assemblyInstruction, start, end int) (graph.Nodes, string) { - var fnodes graph.Nodes - for i := start; i <= end; i++ { - insts := asm[i] - if len(insts) == 0 { - continue - } - var group assemblyInstruction - for _, insn := range insts { - group.flat += insn.flat - group.cum += insn.cum - group.flatDiv += insn.flatDiv - group.cumDiv += insn.cumDiv - } - flat := group.flatValue() - cum := group.cumValue() - fnodes = append(fnodes, &graph.Node{ - Info: graph.NodeInfo{ - Name: "???", - Lineno: i, - }, - Flat: flat, - Cum: cum, - }) - } - return fnodes, filename -} - // sourceReader provides access to source code with caching of file contents. type sourceReader struct { // searchPath is a filepath.ListSeparator-separated list of directories where @@ -543,6 +877,7 @@ func (reader *sourceReader) fileError(path string) error { return reader.errors[path] } +// line returns the line numbered "lineno" in path, or _,false if lineno is out of range. func (reader *sourceReader) line(path string, lineno int) (string, bool) { lines, ok := reader.files[path] if !ok { @@ -651,3 +986,37 @@ func indentation(line string) int { } return column } + +// rightPad pads the input with spaces on the right-hand-side to make it have +// at least width n. It treats tabs as enough spaces that lead to the next +// 8-aligned tab-stop. +func rightPad(s string, n int) string { + var str strings.Builder + + // Convert tabs to spaces as we go so padding works regardless of what prefix + // is placed before the result. + column := 0 + for _, c := range s { + column++ + if c == '\t' { + str.WriteRune(' ') + for column%8 != 0 { + column++ + str.WriteRune(' ') + } + } else { + str.WriteRune(c) + } + } + for column < n { + column++ + str.WriteRune(' ') + } + return str.String() +} + +func canonicalizeFileName(fname string) string { + fname = strings.TrimPrefix(fname, "/proc/self/cwd/") + fname = strings.TrimPrefix(fname, "./") + return filepath.Clean(fname) +} diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go index 02a6d77248..26e8bdbba8 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go @@ -25,12 +25,11 @@ func AddSourceTemplates(t *template.Template) { } const weblistPageCSS = `