mirror of
https://github.com/golang/go.git
synced 2025-05-17 05:14:40 +00:00
[dev.link] all: merge branch 'master' into dev.link
Clean merge. Change-Id: I2ae070c60c011779a0f0a1344f5b6d45ef10d8a1
This commit is contained in:
commit
440852c464
@ -183,6 +183,29 @@ func IndexAny(s []byte, chars string) int {
|
|||||||
// Avoid scanning all of s.
|
// Avoid scanning all of s.
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
if len(s) == 1 {
|
||||||
|
r := rune(s[0])
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
// search utf8.RuneError.
|
||||||
|
for _, r = range chars {
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if bytealg.IndexByteString(chars, s[0]) >= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(chars) == 1 {
|
||||||
|
r := rune(chars[0])
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
r = utf8.RuneError
|
||||||
|
}
|
||||||
|
return IndexRune(s, r)
|
||||||
|
}
|
||||||
if len(s) > 8 {
|
if len(s) > 8 {
|
||||||
if as, isASCII := makeASCIISet(chars); isASCII {
|
if as, isASCII := makeASCIISet(chars); isASCII {
|
||||||
for i, c := range s {
|
for i, c := range s {
|
||||||
@ -197,14 +220,26 @@ func IndexAny(s []byte, chars string) int {
|
|||||||
for i := 0; i < len(s); i += width {
|
for i := 0; i < len(s); i += width {
|
||||||
r := rune(s[i])
|
r := rune(s[i])
|
||||||
if r < utf8.RuneSelf {
|
if r < utf8.RuneSelf {
|
||||||
width = 1
|
if bytealg.IndexByteString(chars, s[i]) >= 0 {
|
||||||
} else {
|
|
||||||
r, width = utf8.DecodeRune(s[i:])
|
|
||||||
}
|
|
||||||
for _, ch := range chars {
|
|
||||||
if r == ch {
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
width = 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, width = utf8.DecodeRune(s[i:])
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
for _, r = range chars {
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
|
||||||
|
// package should not import the strings package, use bytealg.IndexString
|
||||||
|
// instead. And this does not seem to lose much performance.
|
||||||
|
if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@ -229,14 +264,60 @@ func LastIndexAny(s []byte, chars string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(s) == 1 {
|
||||||
|
r := rune(s[0])
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
for _, r = range chars {
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if bytealg.IndexByteString(chars, s[0]) >= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(chars) == 1 {
|
||||||
|
cr := rune(chars[0])
|
||||||
|
if cr >= utf8.RuneSelf {
|
||||||
|
cr = utf8.RuneError
|
||||||
|
}
|
||||||
for i := len(s); i > 0; {
|
for i := len(s); i > 0; {
|
||||||
r, size := utf8.DecodeLastRune(s[:i])
|
r, size := utf8.DecodeLastRune(s[:i])
|
||||||
i -= size
|
i -= size
|
||||||
for _, c := range chars {
|
if r == cr {
|
||||||
if r == c {
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i := len(s); i > 0; {
|
||||||
|
r := rune(s[i-1])
|
||||||
|
if r < utf8.RuneSelf {
|
||||||
|
if bytealg.IndexByteString(chars, s[i-1]) >= 0 {
|
||||||
|
return i - 1
|
||||||
|
}
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, size := utf8.DecodeLastRune(s[:i])
|
||||||
|
i -= size
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
for _, r = range chars {
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
|
||||||
|
// package should not import the strings package, use bytealg.IndexString
|
||||||
|
// instead. And this does not seem to lose much performance.
|
||||||
|
if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,7 @@ var indexAnyTests = []BinOpTest{
|
|||||||
{"", "abc", -1},
|
{"", "abc", -1},
|
||||||
{"a", "", -1},
|
{"a", "", -1},
|
||||||
{"a", "a", 0},
|
{"a", "a", 0},
|
||||||
|
{"\x80", "\xffb", 0},
|
||||||
{"aaa", "a", 0},
|
{"aaa", "a", 0},
|
||||||
{"abc", "xyz", -1},
|
{"abc", "xyz", -1},
|
||||||
{"abc", "xcz", 2},
|
{"abc", "xcz", 2},
|
||||||
@ -179,6 +180,7 @@ var indexAnyTests = []BinOpTest{
|
|||||||
{dots + dots + dots, " ", -1},
|
{dots + dots + dots, " ", -1},
|
||||||
{"012abcba210", "\xffb", 4},
|
{"012abcba210", "\xffb", 4},
|
||||||
{"012\x80bcb\x80210", "\xffb", 3},
|
{"012\x80bcb\x80210", "\xffb", 3},
|
||||||
|
{"0123456\xcf\x80abc", "\xcfb\x80", 10},
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastIndexAnyTests = []BinOpTest{
|
var lastIndexAnyTests = []BinOpTest{
|
||||||
@ -187,6 +189,7 @@ var lastIndexAnyTests = []BinOpTest{
|
|||||||
{"", "abc", -1},
|
{"", "abc", -1},
|
||||||
{"a", "", -1},
|
{"a", "", -1},
|
||||||
{"a", "a", 0},
|
{"a", "a", 0},
|
||||||
|
{"\x80", "\xffb", 0},
|
||||||
{"aaa", "a", 2},
|
{"aaa", "a", 2},
|
||||||
{"abc", "xyz", -1},
|
{"abc", "xyz", -1},
|
||||||
{"abc", "ab", 1},
|
{"abc", "ab", 1},
|
||||||
@ -197,6 +200,7 @@ var lastIndexAnyTests = []BinOpTest{
|
|||||||
{dots + dots + dots, " ", -1},
|
{dots + dots + dots, " ", -1},
|
||||||
{"012abcba210", "\xffb", 6},
|
{"012abcba210", "\xffb", 6},
|
||||||
{"012\x80bcb\x80210", "\xffb", 7},
|
{"012\x80bcb\x80210", "\xffb", 7},
|
||||||
|
{"0123456\xcf\x80abc", "\xcfb\x80", 10},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute f on each test case. funcName should be the name of f; it's used
|
// Execute f on each test case. funcName should be the name of f; it's used
|
||||||
@ -1890,10 +1894,10 @@ func BenchmarkBytesCompare(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkIndexAnyASCII(b *testing.B) {
|
func BenchmarkIndexAnyASCII(b *testing.B) {
|
||||||
x := Repeat([]byte{'#'}, 4096) // Never matches set
|
x := Repeat([]byte{'#'}, 2048) // Never matches set
|
||||||
cs := "0123456789abcdef"
|
cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
for k := 1; k <= 4096; k <<= 4 {
|
for k := 1; k <= 2048; k <<= 4 {
|
||||||
for j := 1; j <= 16; j <<= 1 {
|
for j := 1; j <= 64; j <<= 1 {
|
||||||
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
|
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
IndexAny(x[:k], cs[:j])
|
IndexAny(x[:k], cs[:j])
|
||||||
@ -1903,6 +1907,48 @@ func BenchmarkIndexAnyASCII(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkIndexAnyUTF8(b *testing.B) {
|
||||||
|
x := Repeat([]byte{'#'}, 2048) // Never matches set
|
||||||
|
cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
|
||||||
|
for k := 1; k <= 2048; k <<= 4 {
|
||||||
|
for j := 1; j <= 64; j <<= 1 {
|
||||||
|
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
IndexAny(x[:k], cs[:j])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLastIndexAnyASCII(b *testing.B) {
|
||||||
|
x := Repeat([]byte{'#'}, 2048) // Never matches set
|
||||||
|
cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
for k := 1; k <= 2048; k <<= 4 {
|
||||||
|
for j := 1; j <= 64; j <<= 1 {
|
||||||
|
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
LastIndexAny(x[:k], cs[:j])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLastIndexAnyUTF8(b *testing.B) {
|
||||||
|
x := Repeat([]byte{'#'}, 2048) // Never matches set
|
||||||
|
cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
|
||||||
|
for k := 1; k <= 2048; k <<= 4 {
|
||||||
|
for j := 1; j <= 64; j <<= 1 {
|
||||||
|
b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
LastIndexAny(x[:k], cs[:j])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkTrimASCII(b *testing.B) {
|
func BenchmarkTrimASCII(b *testing.B) {
|
||||||
cs := "0123456789abcdef"
|
cs := "0123456789abcdef"
|
||||||
for k := 1; k <= 4096; k <<= 4 {
|
for k := 1; k <= 4096; k <<= 4 {
|
||||||
|
7
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
7
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@ -1064,7 +1064,7 @@ label1:
|
|||||||
// VSX AND, XX3-form
|
// VSX AND, XX3-form
|
||||||
// <MNEMONIC> XA,XB,XT produces
|
// <MNEMONIC> XA,XB,XT produces
|
||||||
// <mnemonic> XT,XA,XB
|
// <mnemonic> XT,XA,XB
|
||||||
XXLANDQ VS0,VS1,VS32
|
XXLAND VS0,VS1,VS32
|
||||||
XXLANDC VS0,VS1,VS32
|
XXLANDC VS0,VS1,VS32
|
||||||
XXLEQV VS0,VS1,VS32
|
XXLEQV VS0,VS1,VS32
|
||||||
XXLNAND VS0,VS1,VS32
|
XXLNAND VS0,VS1,VS32
|
||||||
@ -1093,6 +1093,11 @@ label1:
|
|||||||
// <mnemonic> XT,XB,UIM
|
// <mnemonic> XT,XB,UIM
|
||||||
XXSPLTW VS0,$3,VS32
|
XXSPLTW VS0,$3,VS32
|
||||||
|
|
||||||
|
// VSX permute, XX3-form
|
||||||
|
// <MNEMONIC> XA,XB,XT produces
|
||||||
|
// <mnemonic> XT,XA,XB
|
||||||
|
XXPERM VS0,VS1,VS32
|
||||||
|
|
||||||
// VSX permute, XX3-form
|
// VSX permute, XX3-form
|
||||||
// <MNEMONIC> XA,XB,DM,XT produces
|
// <MNEMONIC> XA,XB,DM,XT produces
|
||||||
// <mnemonic> XT,XA,XB,DM
|
// <mnemonic> XT,XA,XB,DM
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -802,6 +803,28 @@ func (p *Package) packedAttribute() string {
|
|||||||
return s + "))"
|
return s + "))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exportParamName returns the value of param as it should be
|
||||||
|
// displayed in a c header file. If param contains any non-ASCII
|
||||||
|
// characters, this function will return the character p followed by
|
||||||
|
// the value of position; otherwise, this function will return the
|
||||||
|
// value of param.
|
||||||
|
func exportParamName(param string, position int) string {
|
||||||
|
if param == "" {
|
||||||
|
return fmt.Sprintf("p%d", position)
|
||||||
|
}
|
||||||
|
|
||||||
|
pname := param
|
||||||
|
|
||||||
|
for i := 0; i < len(param); i++ {
|
||||||
|
if param[i] > unicode.MaxASCII {
|
||||||
|
pname = fmt.Sprintf("p%d", position)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pname
|
||||||
|
}
|
||||||
|
|
||||||
// Write out the various stubs we need to support functions exported
|
// Write out the various stubs we need to support functions exported
|
||||||
// from Go so that they are callable from C.
|
// from Go so that they are callable from C.
|
||||||
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
@ -915,42 +938,45 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
if i > 0 || fn.Recv != nil {
|
if i > 0 || fn.Recv != nil {
|
||||||
s += ", "
|
s += ", "
|
||||||
}
|
}
|
||||||
s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
|
s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
|
||||||
})
|
})
|
||||||
s += ")"
|
s += ")"
|
||||||
|
|
||||||
if len(exp.Doc) > 0 {
|
if len(exp.Doc) > 0 {
|
||||||
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
|
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
|
||||||
|
if !strings.HasSuffix(exp.Doc, "\n") {
|
||||||
|
fmt.Fprint(fgcch, "\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
}
|
||||||
|
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||||
fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
|
fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
|
||||||
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||||
}
|
}
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
|
fmt.Fprintf(fgcc, "\t_cgo_a.recv = recv;\n")
|
||||||
}
|
}
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
|
fmt.Fprintf(fgcc, "\t_cgo_a.p%d = %s;\n", i, exportParamName(aname, i))
|
||||||
})
|
})
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
||||||
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
|
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &_cgo_a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
|
fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
||||||
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
|
fmt.Fprintf(fgcc, "\treturn _cgo_a.r0;\n")
|
||||||
} else {
|
} else {
|
||||||
forFieldList(fntype.Results,
|
forFieldList(fntype.Results,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
|
fmt.Fprintf(fgcc, "\tr.r%d = _cgo_a.r%d;\n", i, i)
|
||||||
})
|
})
|
||||||
fmt.Fprintf(fgcc, "\treturn r;\n")
|
fmt.Fprintf(fgcc, "\treturn r;\n")
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,6 @@ Flags:
|
|||||||
-lang version
|
-lang version
|
||||||
Set language version to compile, as in -lang=go1.12.
|
Set language version to compile, as in -lang=go1.12.
|
||||||
Default is current version.
|
Default is current version.
|
||||||
-largemodel
|
|
||||||
Generate code that assumes a large memory model.
|
|
||||||
-linkobj file
|
-linkobj file
|
||||||
Write linker-specific object to file and compiler-specific
|
Write linker-specific object to file and compiler-specific
|
||||||
object to usual output file (as specified by -o).
|
object to usual output file (as specified by -o).
|
||||||
|
@ -186,6 +186,7 @@ func algtype1(t *types.Type) (AlgKind, *types.Type) {
|
|||||||
|
|
||||||
// genhash returns a symbol which is the closure used to compute
|
// genhash returns a symbol which is the closure used to compute
|
||||||
// the hash of a value of type t.
|
// the hash of a value of type t.
|
||||||
|
// Note: the generated function must match runtime.typehash exactly.
|
||||||
func genhash(t *types.Type) *obj.LSym {
|
func genhash(t *types.Type) *obj.LSym {
|
||||||
switch algtype(t) {
|
switch algtype(t) {
|
||||||
default:
|
default:
|
||||||
|
@ -673,10 +673,6 @@ func evconst(n *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OCOMPLEX:
|
case OCOMPLEX:
|
||||||
if nl == nil || nr == nil {
|
|
||||||
// TODO(mdempsky): Remove after early OAS2FUNC rewrite CL lands.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||||
// make it a complex literal
|
// make it a complex literal
|
||||||
c := newMpcmplx()
|
c := newMpcmplx()
|
||||||
|
@ -1371,7 +1371,7 @@ func (e *Escape) finish(fns []*Node) {
|
|||||||
fn.Esc = EscFuncTagged
|
fn.Esc = EscFuncTagged
|
||||||
|
|
||||||
narg := 0
|
narg := 0
|
||||||
for _, fs := range types.RecvsParams {
|
for _, fs := range &types.RecvsParams {
|
||||||
for _, f := range fs(fn.Type).Fields().Slice() {
|
for _, f := range fs(fn.Type).Fields().Slice() {
|
||||||
narg++
|
narg++
|
||||||
f.Note = e.paramTag(fn, narg, f)
|
f.Note = e.paramTag(fn, narg, f)
|
||||||
|
@ -585,28 +585,44 @@ s%^ ........*\]%&~%g
|
|||||||
s%~ %%g
|
s%~ %%g
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func symfmt(s *types.Sym, flag FmtFlag, mode fmtMode) string {
|
func symfmt(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
|
||||||
if s.Pkg != nil && flag&FmtShort == 0 {
|
if s.Pkg != nil && flag&FmtShort == 0 {
|
||||||
switch mode {
|
switch mode {
|
||||||
case FErr: // This is for the user
|
case FErr: // This is for the user
|
||||||
if s.Pkg == builtinpkg || s.Pkg == localpkg {
|
if s.Pkg == builtinpkg || s.Pkg == localpkg {
|
||||||
return s.Name
|
b.WriteString(s.Name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the name was used by multiple packages, display the full path,
|
// If the name was used by multiple packages, display the full path,
|
||||||
if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
|
if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
|
||||||
return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
|
fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return s.Pkg.Name + "." + s.Name
|
b.WriteString(s.Pkg.Name)
|
||||||
|
b.WriteByte('.')
|
||||||
|
b.WriteString(s.Name)
|
||||||
|
return
|
||||||
|
|
||||||
case FDbg:
|
case FDbg:
|
||||||
return s.Pkg.Name + "." + s.Name
|
b.WriteString(s.Pkg.Name)
|
||||||
|
b.WriteByte('.')
|
||||||
|
b.WriteString(s.Name)
|
||||||
|
return
|
||||||
|
|
||||||
case FTypeIdName:
|
case FTypeIdName:
|
||||||
return s.Pkg.Name + "." + s.Name // dcommontype, typehash
|
// dcommontype, typehash
|
||||||
|
b.WriteString(s.Pkg.Name)
|
||||||
|
b.WriteByte('.')
|
||||||
|
b.WriteString(s.Name)
|
||||||
|
return
|
||||||
|
|
||||||
case FTypeId:
|
case FTypeId:
|
||||||
return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
|
// (methodsym), typesym, weaksym
|
||||||
|
b.WriteString(s.Pkg.Prefix)
|
||||||
|
b.WriteByte('.')
|
||||||
|
b.WriteString(s.Name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,13 +635,15 @@ func symfmt(s *types.Sym, flag FmtFlag, mode fmtMode) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mode == FDbg {
|
if mode == FDbg {
|
||||||
return fmt.Sprintf("@%q.%s", s.Pkg.Path, name)
|
fmt.Fprintf(b, "@%q.%s", s.Pkg.Path, name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return name
|
b.WriteString(name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Name
|
b.WriteString(s.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var basicnames = []string{
|
var basicnames = []string{
|
||||||
@ -652,16 +670,16 @@ var basicnames = []string{
|
|||||||
TBLANK: "blank",
|
TBLANK: "blank",
|
||||||
}
|
}
|
||||||
|
|
||||||
var tconvBufferPool = sync.Pool{
|
var fmtBufferPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return new(bytes.Buffer)
|
return new(bytes.Buffer)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
|
func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
|
||||||
buf := tconvBufferPool.Get().(*bytes.Buffer)
|
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
defer tconvBufferPool.Put(buf)
|
defer fmtBufferPool.Put(buf)
|
||||||
|
|
||||||
tconv2(buf, t, flag, mode, nil)
|
tconv2(buf, t, flag, mode, nil)
|
||||||
return types.InternString(buf.Bytes())
|
return types.InternString(buf.Bytes())
|
||||||
@ -703,7 +721,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
|||||||
case FTypeIdName, FTypeId:
|
case FTypeIdName, FTypeId:
|
||||||
t = types.Types[t.Etype]
|
t = types.Types[t.Etype]
|
||||||
default:
|
default:
|
||||||
b.WriteString(sconv(t.Sym, FmtShort, mode))
|
sconv2(b, t.Sym, FmtShort, mode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -718,15 +736,16 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
|||||||
case FTypeId, FTypeIdName:
|
case FTypeId, FTypeIdName:
|
||||||
if flag&FmtShort != 0 {
|
if flag&FmtShort != 0 {
|
||||||
if t.Vargen != 0 {
|
if t.Vargen != 0 {
|
||||||
fmt.Fprintf(b, "%s·%d", sconv(t.Sym, FmtShort, mode), t.Vargen)
|
sconv2(b, t.Sym, FmtShort, mode)
|
||||||
|
fmt.Fprintf(b, "·%d", t.Vargen)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.WriteString(sconv(t.Sym, FmtShort, mode))
|
sconv2(b, t.Sym, FmtShort, mode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode == FTypeIdName {
|
if mode == FTypeIdName {
|
||||||
b.WriteString(sconv(t.Sym, FmtUnsigned, mode))
|
sconv2(b, t.Sym, FmtUnsigned, mode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,7 +755,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.WriteString(smodeString(t.Sym, mode))
|
sconv2(b, t.Sym, 0, mode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,13 +864,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
|||||||
// Wrong interface definitions may have types lacking a symbol.
|
// Wrong interface definitions may have types lacking a symbol.
|
||||||
break
|
break
|
||||||
case types.IsExported(f.Sym.Name):
|
case types.IsExported(f.Sym.Name):
|
||||||
b.WriteString(sconv(f.Sym, FmtShort, mode))
|
sconv2(b, f.Sym, FmtShort, mode)
|
||||||
default:
|
default:
|
||||||
flag1 := FmtLeft
|
flag1 := FmtLeft
|
||||||
if flag&FmtUnsigned != 0 {
|
if flag&FmtUnsigned != 0 {
|
||||||
flag1 = FmtUnsigned
|
flag1 = FmtUnsigned
|
||||||
}
|
}
|
||||||
b.WriteString(sconv(f.Sym, flag1, mode))
|
sconv2(b, f.Sym, flag1, mode)
|
||||||
}
|
}
|
||||||
tconv2(b, f.Type, FmtShort, mode, visited)
|
tconv2(b, f.Type, FmtShort, mode, visited)
|
||||||
}
|
}
|
||||||
@ -941,7 +960,7 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
|||||||
b.WriteString("undefined")
|
b.WriteString("undefined")
|
||||||
if t.Sym != nil {
|
if t.Sym != nil {
|
||||||
b.WriteByte(' ')
|
b.WriteByte(' ')
|
||||||
b.WriteString(smodeString(t.Sym, mode))
|
sconv2(b, t.Sym, 0, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
case TUNSAFEPTR:
|
case TUNSAFEPTR:
|
||||||
@ -1731,9 +1750,30 @@ func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
|
|||||||
if s.Name == "_" {
|
if s.Name == "_" {
|
||||||
return "_"
|
return "_"
|
||||||
}
|
}
|
||||||
|
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset()
|
||||||
|
defer fmtBufferPool.Put(buf)
|
||||||
|
|
||||||
flag, mode = flag.update(mode)
|
flag, mode = flag.update(mode)
|
||||||
return symfmt(s, flag, mode)
|
symfmt(buf, s, flag, mode)
|
||||||
|
return types.InternString(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func sconv2(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
|
||||||
|
if flag&FmtLong != 0 {
|
||||||
|
panic("linksymfmt")
|
||||||
|
}
|
||||||
|
if s == nil {
|
||||||
|
b.WriteString("<S>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.Name == "_" {
|
||||||
|
b.WriteString("_")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
flag, mode = flag.update(mode)
|
||||||
|
symfmt(b, s, flag, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visited map[*types.Type]int, funarg types.Funarg) {
|
func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visited map[*types.Type]int, funarg types.Funarg) {
|
||||||
|
@ -954,7 +954,7 @@ func (w *exportWriter) funcExt(n *Node) {
|
|||||||
w.symIdx(n.Sym)
|
w.symIdx(n.Sym)
|
||||||
|
|
||||||
// Escape analysis.
|
// Escape analysis.
|
||||||
for _, fs := range types.RecvsParams {
|
for _, fs := range &types.RecvsParams {
|
||||||
for _, f := range fs(n.Type).FieldSlice() {
|
for _, f := range fs(n.Type).FieldSlice() {
|
||||||
w.string(f.Note)
|
w.string(f.Note)
|
||||||
}
|
}
|
||||||
|
@ -660,7 +660,7 @@ func (r *importReader) funcExt(n *Node) {
|
|||||||
r.symIdx(n.Sym)
|
r.symIdx(n.Sym)
|
||||||
|
|
||||||
// Escape analysis.
|
// Escape analysis.
|
||||||
for _, fs := range types.RecvsParams {
|
for _, fs := range &types.RecvsParams {
|
||||||
for _, f := range fs(n.Type).FieldSlice() {
|
for _, f := range fs(n.Type).FieldSlice() {
|
||||||
f.Note = r.string()
|
f.Note = r.string()
|
||||||
}
|
}
|
||||||
|
@ -1070,7 +1070,7 @@ func loadsys() {
|
|||||||
typecheckok = true
|
typecheckok = true
|
||||||
|
|
||||||
typs := runtimeTypes()
|
typs := runtimeTypes()
|
||||||
for _, d := range runtimeDecls {
|
for _, d := range &runtimeDecls {
|
||||||
sym := Runtimepkg.Lookup(d.name)
|
sym := Runtimepkg.Lookup(d.name)
|
||||||
typ := typs[d.typ]
|
typ := typs[d.typ]
|
||||||
switch d.tag {
|
switch d.tag {
|
||||||
@ -1373,7 +1373,7 @@ var concurrentFlagOK = [256]bool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func concurrentBackendAllowed() bool {
|
func concurrentBackendAllowed() bool {
|
||||||
for i, x := range Debug {
|
for i, x := range &Debug {
|
||||||
if x != 0 && !concurrentFlagOK[i] {
|
if x != 0 && !concurrentFlagOK[i] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -646,7 +646,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
|
|||||||
}
|
}
|
||||||
n := p.nod(expr, op, p.expr(expr.X), nil)
|
n := p.nod(expr, op, p.expr(expr.X), nil)
|
||||||
var index [3]*Node
|
var index [3]*Node
|
||||||
for i, x := range expr.Index {
|
for i, x := range &expr.Index {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
index[i] = p.expr(x)
|
index[i] = p.expr(x)
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) {
|
|||||||
if v.Type.Etype != types.TTUPLE {
|
if v.Type.Etype != types.TTUPLE {
|
||||||
v.Fatalf("location pair %s has non-tuple type %v", loc, v.Type)
|
v.Fatalf("location pair %s has non-tuple type %v", loc, v.Type)
|
||||||
}
|
}
|
||||||
for i, loc1 := range loc {
|
for i, loc1 := range &loc {
|
||||||
if loc1 == nil {
|
if loc1 == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -705,12 +705,6 @@ func (lv *Liveness) markUnsafePoints() {
|
|||||||
v = v.Args[0]
|
v = v.Args[0]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case ssa.OpRISCV64SUBW:
|
|
||||||
// RISCV64 lowers Neq32 to include a SUBW with multiple arguments.
|
|
||||||
// TODO(jsing): it would be preferable not to use Neq32 for
|
|
||||||
// writeBuffer.enabled checks on this platform.
|
|
||||||
v = v.Args[0]
|
|
||||||
continue
|
|
||||||
case ssa.Op386MOVLload, ssa.OpARM64MOVWUload, ssa.OpPPC64MOVWZload, ssa.OpWasmI64Load32U:
|
case ssa.Op386MOVLload, ssa.OpARM64MOVWUload, ssa.OpPPC64MOVWZload, ssa.OpWasmI64Load32U:
|
||||||
// Args[0] is the address of the write
|
// Args[0] is the address of the write
|
||||||
// barrier control. Ignore Args[1],
|
// barrier control. Ignore Args[1],
|
||||||
|
@ -3216,7 +3216,7 @@ func init() {
|
|||||||
var p4 []*sys.Arch
|
var p4 []*sys.Arch
|
||||||
var p8 []*sys.Arch
|
var p8 []*sys.Arch
|
||||||
var lwatomics []*sys.Arch
|
var lwatomics []*sys.Arch
|
||||||
for _, a := range sys.Archs {
|
for _, a := range &sys.Archs {
|
||||||
all = append(all, a)
|
all = append(all, a)
|
||||||
if a.PtrSize == 4 {
|
if a.PtrSize == 4 {
|
||||||
p4 = append(p4, a)
|
p4 = append(p4, a)
|
||||||
|
@ -66,7 +66,7 @@ var builtinFuncs = [...]struct {
|
|||||||
// isBuiltinFuncName reports whether name matches a builtin function
|
// isBuiltinFuncName reports whether name matches a builtin function
|
||||||
// name.
|
// name.
|
||||||
func isBuiltinFuncName(name string) bool {
|
func isBuiltinFuncName(name string) bool {
|
||||||
for _, fn := range builtinFuncs {
|
for _, fn := range &builtinFuncs {
|
||||||
if fn.name == name {
|
if fn.name == name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ func initUniverse() {
|
|||||||
|
|
||||||
// lexinit initializes known symbols and the basic types.
|
// lexinit initializes known symbols and the basic types.
|
||||||
func lexinit() {
|
func lexinit() {
|
||||||
for _, s := range basicTypes {
|
for _, s := range &basicTypes {
|
||||||
etype := s.etype
|
etype := s.etype
|
||||||
if int(etype) >= len(types.Types) {
|
if int(etype) >= len(types.Types) {
|
||||||
Fatalf("lexinit: %s bad etype", s.name)
|
Fatalf("lexinit: %s bad etype", s.name)
|
||||||
@ -111,13 +111,13 @@ func lexinit() {
|
|||||||
asNode(s2.Def).Name = new(Name)
|
asNode(s2.Def).Name = new(Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range builtinFuncs {
|
for _, s := range &builtinFuncs {
|
||||||
s2 := builtinpkg.Lookup(s.name)
|
s2 := builtinpkg.Lookup(s.name)
|
||||||
s2.Def = asTypesNode(newname(s2))
|
s2.Def = asTypesNode(newname(s2))
|
||||||
asNode(s2.Def).SetSubOp(s.op)
|
asNode(s2.Def).SetSubOp(s.op)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range unsafeFuncs {
|
for _, s := range &unsafeFuncs {
|
||||||
s2 := unsafepkg.Lookup(s.name)
|
s2 := unsafepkg.Lookup(s.name)
|
||||||
s2.Def = asTypesNode(newname(s2))
|
s2.Def = asTypesNode(newname(s2))
|
||||||
asNode(s2.Def).SetSubOp(s.op)
|
asNode(s2.Def).SetSubOp(s.op)
|
||||||
@ -402,7 +402,7 @@ func lexinit1() {
|
|||||||
dowidth(types.Runetype)
|
dowidth(types.Runetype)
|
||||||
|
|
||||||
// backend-dependent builtin types (e.g. int).
|
// backend-dependent builtin types (e.g. int).
|
||||||
for _, s := range typedefs {
|
for _, s := range &typedefs {
|
||||||
s1 := builtinpkg.Lookup(s.name)
|
s1 := builtinpkg.Lookup(s.name)
|
||||||
|
|
||||||
sameas := s.sameas32
|
sameas := s.sameas32
|
||||||
|
@ -390,7 +390,7 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
|
|||||||
var w io.WriteCloser
|
var w io.WriteCloser
|
||||||
|
|
||||||
if slashPkgPath == "" {
|
if slashPkgPath == "" {
|
||||||
slashPkgPath = string(0)
|
slashPkgPath = "\000"
|
||||||
}
|
}
|
||||||
subdirpath := filepath.Join(dest, pathEscape(slashPkgPath))
|
subdirpath := filepath.Join(dest, pathEscape(slashPkgPath))
|
||||||
err := os.MkdirAll(subdirpath, 0755)
|
err := os.MkdirAll(subdirpath, 0755)
|
||||||
|
225
src/cmd/compile/internal/ssa/addressingmodes.go
Normal file
225
src/cmd/compile/internal/ssa/addressingmodes.go
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// 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 ssa
|
||||||
|
|
||||||
|
// addressingModes combines address calculations into memory operations
|
||||||
|
// that can perform complicated addressing modes.
|
||||||
|
func addressingModes(f *Func) {
|
||||||
|
switch f.Config.arch {
|
||||||
|
default:
|
||||||
|
// Most architectures can't do this.
|
||||||
|
return
|
||||||
|
case "amd64", "386":
|
||||||
|
// TODO: s390x?
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp []*Value
|
||||||
|
for _, b := range f.Blocks {
|
||||||
|
for _, v := range b.Values {
|
||||||
|
if !combineFirst[v.Op] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// All matched operations have the pointer in arg[0].
|
||||||
|
// All results have the pointer in arg[0] and the index in arg[1].
|
||||||
|
// *Except* for operations which update a register,
|
||||||
|
// which are marked with resultInArg0. Those have
|
||||||
|
// the pointer in arg[1], and the corresponding result op
|
||||||
|
// has the pointer in arg[1] and the index in arg[2].
|
||||||
|
ptrIndex := 0
|
||||||
|
if opcodeTable[v.Op].resultInArg0 {
|
||||||
|
ptrIndex = 1
|
||||||
|
}
|
||||||
|
p := v.Args[ptrIndex]
|
||||||
|
c, ok := combine[[2]Op{v.Op, p.Op}]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// See if we can combine the Aux/AuxInt values.
|
||||||
|
switch [2]auxType{opcodeTable[v.Op].auxType, opcodeTable[p.Op].auxType} {
|
||||||
|
case [2]auxType{auxSymOff, auxInt32}:
|
||||||
|
// TODO: introduce auxSymOff32
|
||||||
|
if !is32Bit(v.AuxInt + p.AuxInt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.AuxInt += p.AuxInt
|
||||||
|
case [2]auxType{auxSymOff, auxSymOff}:
|
||||||
|
if v.Aux != nil && p.Aux != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !is32Bit(v.AuxInt + p.AuxInt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Aux != nil {
|
||||||
|
v.Aux = p.Aux
|
||||||
|
}
|
||||||
|
v.AuxInt += p.AuxInt
|
||||||
|
case [2]auxType{auxSymValAndOff, auxInt32}:
|
||||||
|
vo := ValAndOff(v.AuxInt)
|
||||||
|
if !vo.canAdd(p.AuxInt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.AuxInt = vo.add(p.AuxInt)
|
||||||
|
case [2]auxType{auxSymValAndOff, auxSymOff}:
|
||||||
|
vo := ValAndOff(v.AuxInt)
|
||||||
|
if v.Aux != nil && p.Aux != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !vo.canAdd(p.AuxInt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Aux != nil {
|
||||||
|
v.Aux = p.Aux
|
||||||
|
}
|
||||||
|
v.AuxInt = vo.add(p.AuxInt)
|
||||||
|
case [2]auxType{auxSymOff, auxNone}:
|
||||||
|
// nothing to do
|
||||||
|
case [2]auxType{auxSymValAndOff, auxNone}:
|
||||||
|
// nothing to do
|
||||||
|
default:
|
||||||
|
f.Fatalf("unknown aux combining for %s and %s\n", v.Op, p.Op)
|
||||||
|
}
|
||||||
|
// Combine the operations.
|
||||||
|
tmp = append(tmp[:0], v.Args[:ptrIndex]...)
|
||||||
|
tmp = append(tmp, p.Args...)
|
||||||
|
tmp = append(tmp, v.Args[ptrIndex+1:]...)
|
||||||
|
v.resetArgs()
|
||||||
|
v.Op = c
|
||||||
|
v.AddArgs(tmp...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// combineFirst contains ops which appear in combine as the
|
||||||
|
// first part of the key.
|
||||||
|
var combineFirst = map[Op]bool{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for k := range combine {
|
||||||
|
combineFirst[k[0]] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each entry k, v in this map, if we have a value x with:
|
||||||
|
// x.Op == k[0]
|
||||||
|
// x.Args[0].Op == k[1]
|
||||||
|
// then we can set x.Op to v and set x.Args like this:
|
||||||
|
// x.Args[0].Args + x.Args[1:]
|
||||||
|
// Additionally, the Aux/AuxInt from x.Args[0] is merged into x.
|
||||||
|
var combine = map[[2]Op]Op{
|
||||||
|
// amd64
|
||||||
|
[2]Op{OpAMD64MOVBload, OpAMD64ADDQ}: OpAMD64MOVBloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVWload, OpAMD64ADDQ}: OpAMD64MOVWloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVLload, OpAMD64ADDQ}: OpAMD64MOVLloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVQload, OpAMD64ADDQ}: OpAMD64MOVQloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVSSload, OpAMD64ADDQ}: OpAMD64MOVSSloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVSDload, OpAMD64ADDQ}: OpAMD64MOVSDloadidx1,
|
||||||
|
|
||||||
|
[2]Op{OpAMD64MOVBstore, OpAMD64ADDQ}: OpAMD64MOVBstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstore, OpAMD64ADDQ}: OpAMD64MOVWstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVLstore, OpAMD64ADDQ}: OpAMD64MOVLstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVQstore, OpAMD64ADDQ}: OpAMD64MOVQstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVSSstore, OpAMD64ADDQ}: OpAMD64MOVSSstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVSDstore, OpAMD64ADDQ}: OpAMD64MOVSDstoreidx1,
|
||||||
|
|
||||||
|
[2]Op{OpAMD64MOVBstoreconst, OpAMD64ADDQ}: OpAMD64MOVBstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstoreconst, OpAMD64ADDQ}: OpAMD64MOVWstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVLstoreconst, OpAMD64ADDQ}: OpAMD64MOVLstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVQstoreconst, OpAMD64ADDQ}: OpAMD64MOVQstoreconstidx1,
|
||||||
|
|
||||||
|
[2]Op{OpAMD64MOVBload, OpAMD64LEAQ1}: OpAMD64MOVBloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVWload, OpAMD64LEAQ1}: OpAMD64MOVWloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVWload, OpAMD64LEAQ2}: OpAMD64MOVWloadidx2,
|
||||||
|
[2]Op{OpAMD64MOVLload, OpAMD64LEAQ1}: OpAMD64MOVLloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVLload, OpAMD64LEAQ4}: OpAMD64MOVLloadidx4,
|
||||||
|
[2]Op{OpAMD64MOVLload, OpAMD64LEAQ8}: OpAMD64MOVLloadidx8,
|
||||||
|
[2]Op{OpAMD64MOVQload, OpAMD64LEAQ1}: OpAMD64MOVQloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVQload, OpAMD64LEAQ8}: OpAMD64MOVQloadidx8,
|
||||||
|
[2]Op{OpAMD64MOVSSload, OpAMD64LEAQ1}: OpAMD64MOVSSloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVSSload, OpAMD64LEAQ4}: OpAMD64MOVSSloadidx4,
|
||||||
|
[2]Op{OpAMD64MOVSDload, OpAMD64LEAQ1}: OpAMD64MOVSDloadidx1,
|
||||||
|
[2]Op{OpAMD64MOVSDload, OpAMD64LEAQ8}: OpAMD64MOVSDloadidx8,
|
||||||
|
|
||||||
|
[2]Op{OpAMD64MOVBstore, OpAMD64LEAQ1}: OpAMD64MOVBstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstore, OpAMD64LEAQ1}: OpAMD64MOVWstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstore, OpAMD64LEAQ2}: OpAMD64MOVWstoreidx2,
|
||||||
|
[2]Op{OpAMD64MOVLstore, OpAMD64LEAQ1}: OpAMD64MOVLstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVLstore, OpAMD64LEAQ4}: OpAMD64MOVLstoreidx4,
|
||||||
|
[2]Op{OpAMD64MOVLstore, OpAMD64LEAQ8}: OpAMD64MOVLstoreidx8,
|
||||||
|
[2]Op{OpAMD64MOVQstore, OpAMD64LEAQ1}: OpAMD64MOVQstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVQstore, OpAMD64LEAQ8}: OpAMD64MOVQstoreidx8,
|
||||||
|
[2]Op{OpAMD64MOVSSstore, OpAMD64LEAQ1}: OpAMD64MOVSSstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVSSstore, OpAMD64LEAQ4}: OpAMD64MOVSSstoreidx4,
|
||||||
|
[2]Op{OpAMD64MOVSDstore, OpAMD64LEAQ1}: OpAMD64MOVSDstoreidx1,
|
||||||
|
[2]Op{OpAMD64MOVSDstore, OpAMD64LEAQ8}: OpAMD64MOVSDstoreidx8,
|
||||||
|
|
||||||
|
[2]Op{OpAMD64MOVBstoreconst, OpAMD64LEAQ1}: OpAMD64MOVBstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstoreconst, OpAMD64LEAQ1}: OpAMD64MOVWstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVWstoreconst, OpAMD64LEAQ2}: OpAMD64MOVWstoreconstidx2,
|
||||||
|
[2]Op{OpAMD64MOVLstoreconst, OpAMD64LEAQ1}: OpAMD64MOVLstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVLstoreconst, OpAMD64LEAQ4}: OpAMD64MOVLstoreconstidx4,
|
||||||
|
[2]Op{OpAMD64MOVQstoreconst, OpAMD64LEAQ1}: OpAMD64MOVQstoreconstidx1,
|
||||||
|
[2]Op{OpAMD64MOVQstoreconst, OpAMD64LEAQ8}: OpAMD64MOVQstoreconstidx8,
|
||||||
|
|
||||||
|
// 386
|
||||||
|
[2]Op{Op386MOVBload, Op386ADDL}: Op386MOVBloadidx1,
|
||||||
|
[2]Op{Op386MOVWload, Op386ADDL}: Op386MOVWloadidx1,
|
||||||
|
[2]Op{Op386MOVLload, Op386ADDL}: Op386MOVLloadidx1,
|
||||||
|
[2]Op{Op386MOVSSload, Op386ADDL}: Op386MOVSSloadidx1,
|
||||||
|
[2]Op{Op386MOVSDload, Op386ADDL}: Op386MOVSDloadidx1,
|
||||||
|
|
||||||
|
[2]Op{Op386MOVBstore, Op386ADDL}: Op386MOVBstoreidx1,
|
||||||
|
[2]Op{Op386MOVWstore, Op386ADDL}: Op386MOVWstoreidx1,
|
||||||
|
[2]Op{Op386MOVLstore, Op386ADDL}: Op386MOVLstoreidx1,
|
||||||
|
[2]Op{Op386MOVSSstore, Op386ADDL}: Op386MOVSSstoreidx1,
|
||||||
|
[2]Op{Op386MOVSDstore, Op386ADDL}: Op386MOVSDstoreidx1,
|
||||||
|
|
||||||
|
[2]Op{Op386MOVBstoreconst, Op386ADDL}: Op386MOVBstoreconstidx1,
|
||||||
|
[2]Op{Op386MOVWstoreconst, Op386ADDL}: Op386MOVWstoreconstidx1,
|
||||||
|
[2]Op{Op386MOVLstoreconst, Op386ADDL}: Op386MOVLstoreconstidx1,
|
||||||
|
|
||||||
|
[2]Op{Op386MOVBload, Op386LEAL1}: Op386MOVBloadidx1,
|
||||||
|
[2]Op{Op386MOVWload, Op386LEAL1}: Op386MOVWloadidx1,
|
||||||
|
[2]Op{Op386MOVWload, Op386LEAL2}: Op386MOVWloadidx2,
|
||||||
|
[2]Op{Op386MOVLload, Op386LEAL1}: Op386MOVLloadidx1,
|
||||||
|
[2]Op{Op386MOVLload, Op386LEAL4}: Op386MOVLloadidx4,
|
||||||
|
[2]Op{Op386MOVSSload, Op386LEAL1}: Op386MOVSSloadidx1,
|
||||||
|
[2]Op{Op386MOVSSload, Op386LEAL4}: Op386MOVSSloadidx4,
|
||||||
|
[2]Op{Op386MOVSDload, Op386LEAL1}: Op386MOVSDloadidx1,
|
||||||
|
[2]Op{Op386MOVSDload, Op386LEAL8}: Op386MOVSDloadidx8,
|
||||||
|
|
||||||
|
[2]Op{Op386MOVBstore, Op386LEAL1}: Op386MOVBstoreidx1,
|
||||||
|
[2]Op{Op386MOVWstore, Op386LEAL1}: Op386MOVWstoreidx1,
|
||||||
|
[2]Op{Op386MOVWstore, Op386LEAL2}: Op386MOVWstoreidx2,
|
||||||
|
[2]Op{Op386MOVLstore, Op386LEAL1}: Op386MOVLstoreidx1,
|
||||||
|
[2]Op{Op386MOVLstore, Op386LEAL4}: Op386MOVLstoreidx4,
|
||||||
|
[2]Op{Op386MOVSSstore, Op386LEAL1}: Op386MOVSSstoreidx1,
|
||||||
|
[2]Op{Op386MOVSSstore, Op386LEAL4}: Op386MOVSSstoreidx4,
|
||||||
|
[2]Op{Op386MOVSDstore, Op386LEAL1}: Op386MOVSDstoreidx1,
|
||||||
|
[2]Op{Op386MOVSDstore, Op386LEAL8}: Op386MOVSDstoreidx8,
|
||||||
|
|
||||||
|
[2]Op{Op386MOVBstoreconst, Op386LEAL1}: Op386MOVBstoreconstidx1,
|
||||||
|
[2]Op{Op386MOVWstoreconst, Op386LEAL1}: Op386MOVWstoreconstidx1,
|
||||||
|
[2]Op{Op386MOVWstoreconst, Op386LEAL2}: Op386MOVWstoreconstidx2,
|
||||||
|
[2]Op{Op386MOVLstoreconst, Op386LEAL1}: Op386MOVLstoreconstidx1,
|
||||||
|
[2]Op{Op386MOVLstoreconst, Op386LEAL4}: Op386MOVLstoreconstidx4,
|
||||||
|
|
||||||
|
[2]Op{Op386ADDLload, Op386LEAL4}: Op386ADDLloadidx4,
|
||||||
|
[2]Op{Op386SUBLload, Op386LEAL4}: Op386SUBLloadidx4,
|
||||||
|
[2]Op{Op386MULLload, Op386LEAL4}: Op386MULLloadidx4,
|
||||||
|
[2]Op{Op386ANDLload, Op386LEAL4}: Op386ANDLloadidx4,
|
||||||
|
[2]Op{Op386ORLload, Op386LEAL4}: Op386ORLloadidx4,
|
||||||
|
[2]Op{Op386XORLload, Op386LEAL4}: Op386XORLloadidx4,
|
||||||
|
|
||||||
|
[2]Op{Op386ADDLmodify, Op386LEAL4}: Op386ADDLmodifyidx4,
|
||||||
|
[2]Op{Op386SUBLmodify, Op386LEAL4}: Op386SUBLmodifyidx4,
|
||||||
|
[2]Op{Op386ANDLmodify, Op386LEAL4}: Op386ANDLmodifyidx4,
|
||||||
|
[2]Op{Op386ORLmodify, Op386LEAL4}: Op386ORLmodifyidx4,
|
||||||
|
[2]Op{Op386XORLmodify, Op386LEAL4}: Op386XORLmodifyidx4,
|
||||||
|
|
||||||
|
[2]Op{Op386ADDLconstmodify, Op386LEAL4}: Op386ADDLconstmodifyidx4,
|
||||||
|
[2]Op{Op386ANDLconstmodify, Op386LEAL4}: Op386ANDLconstmodifyidx4,
|
||||||
|
[2]Op{Op386ORLconstmodify, Op386LEAL4}: Op386ORLconstmodifyidx4,
|
||||||
|
[2]Op{Op386XORLconstmodify, Op386LEAL4}: Op386XORLconstmodifyidx4,
|
||||||
|
}
|
@ -101,6 +101,9 @@ func (e Edge) Block() *Block {
|
|||||||
func (e Edge) Index() int {
|
func (e Edge) Index() int {
|
||||||
return e.i
|
return e.i
|
||||||
}
|
}
|
||||||
|
func (e Edge) String() string {
|
||||||
|
return fmt.Sprintf("{%v,%d}", e.b, e.i)
|
||||||
|
}
|
||||||
|
|
||||||
// kind controls successors
|
// kind controls successors
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
|
@ -442,6 +442,7 @@ var passes = [...]pass{
|
|||||||
{name: "insert resched checks", fn: insertLoopReschedChecks,
|
{name: "insert resched checks", fn: insertLoopReschedChecks,
|
||||||
disabled: objabi.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
|
disabled: objabi.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
|
||||||
{name: "lower", fn: lower, required: true},
|
{name: "lower", fn: lower, required: true},
|
||||||
|
{name: "addressing modes", fn: addressingModes, required: false},
|
||||||
{name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
|
{name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
|
||||||
{name: "lowered cse", fn: cse},
|
{name: "lowered cse", fn: cse},
|
||||||
{name: "elim unread autos", fn: elimUnreadAutos},
|
{name: "elim unread autos", fn: elimUnreadAutos},
|
||||||
|
@ -588,10 +588,6 @@
|
|||||||
(MOVWLSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem)
|
(MOVWLSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem)
|
||||||
(MOVWLZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
|
(MOVWLZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
|
||||||
|
|
||||||
(MOVBLZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
|
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
|
||||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
|
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
|
||||||
@ -611,34 +607,22 @@
|
|||||||
|
|
||||||
// fold constants into memory operations
|
// fold constants into memory operations
|
||||||
// Note that this is not always a good idea because if not all the uses of
|
// Note that this is not always a good idea because if not all the uses of
|
||||||
// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
|
// the ADDLconst get eliminated, we still have to compute the ADDLconst and we now
|
||||||
// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
|
// have potentially two live values (ptr and (ADDLconst [off] ptr)) instead of one.
|
||||||
// Nevertheless, let's do it!
|
// Nevertheless, let's do it!
|
||||||
(MOV(L|W|B|SS|SD)load [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)load [off1+off2] {sym} ptr mem)
|
(MOV(L|W|B|SS|SD)load [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)load [off1+off2] {sym} ptr mem)
|
||||||
(MOV(L|W|B|SS|SD)store [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)store [off1+off2] {sym} ptr val mem)
|
(MOV(L|W|B|SS|SD)store [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)store [off1+off2] {sym} ptr val mem)
|
||||||
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem)
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem)
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) && is32Bit(off1+off2) ->
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {sym} val base idx mem)
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) && is32Bit(off1+off2*4) ->
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2*4] {sym} val base idx mem)
|
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem)
|
((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem)
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem)
|
((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) ->
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) ->
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) && is32Bit(off1+off2) ->
|
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {sym} base idx val mem)
|
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) && is32Bit(off1+off2*4) ->
|
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2*4] {sym} base idx val mem)
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) ->
|
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) ->
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem)
|
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem)
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) && ValAndOff(valoff1).canAdd(off2) ->
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) && ValAndOff(valoff1).canAdd(off2*4) ->
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
|
|
||||||
|
|
||||||
// Fold constants into stores.
|
// Fold constants into stores.
|
||||||
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
|
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
|
||||||
@ -652,7 +636,7 @@
|
|||||||
(MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
|
(MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
|
||||||
(MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {s} ptr mem)
|
(MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {s} ptr mem)
|
||||||
|
|
||||||
// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
|
// We need to fold LEAL into the MOVx ops so that the live variable analysis knows
|
||||||
// what variables are being read/written by the ops.
|
// what variables are being read/written by the ops.
|
||||||
// Note: we turn off this merging for operations on globals when building
|
// Note: we turn off this merging for operations on globals when building
|
||||||
// position-independent code (when Flag_shared is set).
|
// position-independent code (when Flag_shared is set).
|
||||||
@ -672,31 +656,9 @@
|
|||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||||
(MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
|
(MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
|
|
||||||
// generating indexed loads and stores
|
|
||||||
(MOV(B|W|L|SS|SD)load [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L|SS|SD)loadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOV(L|SS)load [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|SS)loadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|SS|SD)store [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L|SS|SD)storeidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOV(L|SS)store [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|SS)storeidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
|
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
|
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
@ -706,97 +668,20 @@
|
|||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
|
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
|
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||||
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem)
|
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
|
|
||||||
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|SS|SD)load [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)loadidx1 [off] {sym} ptr idx mem)
|
|
||||||
(MOV(B|W|L|SS|SD)store [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)storeidx1 [off] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L)storeconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L)storeconst [x] {sym} (ADDL ptr idx) mem) -> (MOV(B|W|L)storeconstidx1 [x] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// combine SHLL into indexed loads and stores
|
|
||||||
(MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
|
|
||||||
(MOVLloadidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLloadidx4 [c] {sym} ptr idx mem)
|
|
||||||
(MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem)
|
|
||||||
(MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem) -> (MOVLstoreidx4 [c] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// combine ADDL into indexed loads and stores
|
|
||||||
(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
|
|
||||||
(MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx2 [int64(int32(c+d))] {sym} ptr idx mem)
|
|
||||||
(MOV(L|SS)loadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+d))] {sym} ptr idx mem)
|
|
||||||
(MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx8 [int64(int32(c+d))] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [int64(int32(c+d))] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|SS)storeidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+d))] {sym} ptr idx val mem)
|
|
||||||
(MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [int64(int32(c+d))] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|SS|SD)loadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(B|W|L|SS|SD)loadidx1 [int64(int32(c+d))] {sym} ptr idx mem)
|
|
||||||
(MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx2 [int64(int32(c+2*d))] {sym} ptr idx mem)
|
|
||||||
(MOV(L|SS)loadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOV(L|SS)loadidx4 [int64(int32(c+4*d))] {sym} ptr idx mem)
|
|
||||||
(MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx8 [int64(int32(c+8*d))] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|SS|SD)storeidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(B|W|L|SS|SD)storeidx1 [int64(int32(c+d))] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreidx2 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx2 [int64(int32(c+2*d))] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|SS)storeidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOV(L|SS)storeidx4 [int64(int32(c+4*d))] {sym} ptr idx val mem)
|
|
||||||
(MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
// Merge load/store to op
|
// Merge load/store to op
|
||||||
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
|
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
|
||||||
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLloadidx4 [off] {sym} ptr idx mem)) && canMergeLoadClobber(v, l, x) && clobber(l) ->
|
|
||||||
((ADD|AND|OR|XOR|SUB|MUL)Lloadidx4 x [off] {sym} ptr idx mem)
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL4 [off2] {sym2} ptr idx) mem)
|
|
||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val ptr idx mem)
|
|
||||||
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
|
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
|
||||||
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
|
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
|
||||||
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
|
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
|
||||||
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) ->
|
(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)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
|
||||||
(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lloadidx4 x [off] {sym} ptr idx mem) mem) && y.Uses==1 && clobber(y) ->
|
|
||||||
((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem)
|
|
||||||
(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|SUB|AND|OR|XOR)L l:(MOVLloadidx4 [off] {sym} ptr idx mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) ->
|
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx x mem)
|
|
||||||
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr mem)) mem)
|
(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(c,off) ->
|
&& y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) ->
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem)
|
((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem)
|
||||||
(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
|
|
||||||
&& y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) ->
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
|
|
||||||
((ADD|AND|OR|XOR)Lmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(c,off) ->
|
|
||||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [makeValAndOff(c,off)] {sym} ptr idx mem)
|
|
||||||
(SUBLmodifyidx4 [off] {sym} ptr idx (MOVLconst [c]) mem) && validValAndOff(-c,off) ->
|
|
||||||
(ADDLconstmodifyidx4 [makeValAndOff(-c,off)] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L)storeconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
|
|
||||||
(MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
|
|
||||||
(MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
|
|
||||||
(MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L)storeconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
|
|
||||||
(MOV(B|W|L)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
|
|
||||||
(MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
|
|
||||||
(MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// fold LEALs together
|
// fold LEALs together
|
||||||
(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
@ -826,6 +711,16 @@
|
|||||||
(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
(LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
(LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
|
// LEAL[1248] into LEAL[1248]. Only some such merges are possible.
|
||||||
|
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
|
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||||
|
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
|
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||||
|
(LEAL2 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(off1+2*off2) && sym2 == nil ->
|
||||||
|
(LEAL4 [off1+2*off2] {sym1} x y)
|
||||||
|
(LEAL4 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(off1+4*off2) && sym2 == nil ->
|
||||||
|
(LEAL8 [off1+4*off2] {sym1} x y)
|
||||||
|
|
||||||
// Absorb InvertFlags into branches.
|
// Absorb InvertFlags into branches.
|
||||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||||
(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
|
(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
|
||||||
@ -1039,23 +934,27 @@
|
|||||||
// TEST %reg,%reg is shorter than CMP
|
// TEST %reg,%reg is shorter than CMP
|
||||||
(CMP(L|W|B)const x [0]) -> (TEST(L|W|B) x x)
|
(CMP(L|W|B)const x [0]) -> (TEST(L|W|B) x x)
|
||||||
|
|
||||||
|
// Convert LEAL1 back to ADDL if we can
|
||||||
|
(LEAL1 [0] x y) && v.Aux == nil -> (ADDL x y)
|
||||||
|
|
||||||
// Combining byte loads into larger (unaligned) loads.
|
// Combining byte loads into larger (unaligned) loads.
|
||||||
// There are many ways these combinations could occur. This is
|
// There are many ways these combinations could occur. This is
|
||||||
// designed to match the way encoding/binary.LittleEndian does it.
|
// designed to match the way encoding/binary.LittleEndian does it.
|
||||||
(ORL x0:(MOVBload [i0] {s} p mem)
|
(ORL x0:(MOVBload [i0] {s} p0 mem)
|
||||||
s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
|
s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, s0)
|
&& clobber(x0, x1, s0)
|
||||||
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORL o0:(ORL
|
(ORL o0:(ORL
|
||||||
x0:(MOVWload [i0] {s} p mem)
|
x0:(MOVWload [i0] {s} p0 mem)
|
||||||
s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem)))
|
s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p1 mem)))
|
||||||
s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)))
|
s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p2 mem)))
|
||||||
&& i2 == i0+2
|
&& i2 == i0+2
|
||||||
&& i3 == i0+3
|
&& i3 == i0+3
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
@ -1064,126 +963,84 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& o0.Uses == 1
|
&& o0.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
|
&& same(p1, p2, 1)
|
||||||
&& mergePoint(b,x0,x1,x2) != nil
|
&& mergePoint(b,x0,x1,x2) != nil
|
||||||
&& clobber(x0, x1, x2, s0, s1, o0)
|
&& clobber(x0, x1, x2, s0, s1, o0)
|
||||||
-> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORL x0:(MOVBloadidx1 [i0] {s} p idx mem)
|
|
||||||
s0:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
|
|
||||||
&& i1==i0+1
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, s0)
|
|
||||||
-> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
(ORL o0:(ORL
|
|
||||||
x0:(MOVWloadidx1 [i0] {s} p idx mem)
|
|
||||||
s0:(SHLLconst [16] x1:(MOVBloadidx1 [i2] {s} p idx mem)))
|
|
||||||
s1:(SHLLconst [24] x2:(MOVBloadidx1 [i3] {s} p idx mem)))
|
|
||||||
&& i2 == i0+2
|
|
||||||
&& i3 == i0+3
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& x2.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& o0.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,x2) != nil
|
|
||||||
&& clobber(x0, x1, x2, s0, s1, o0)
|
|
||||||
-> @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
// Combine constant stores into larger (unaligned) stores.
|
// Combine constant stores into larger (unaligned) stores.
|
||||||
(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
|
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
(MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
(MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
|
|
||||||
(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
|
|
||||||
(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
|
|
||||||
|
|
||||||
(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLLconst <i.Type> [1] i) mem)
|
|
||||||
|
|
||||||
// Combine stores into larger (unaligned) stores.
|
// Combine stores into larger (unaligned) stores.
|
||||||
(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
(MOVBstore [i] {s} p1 (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p0 w mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i-1] {s} p w mem)
|
-> (MOVWstore [i-1] {s} p0 w mem)
|
||||||
(MOVBstore [i] {s} p w x:(MOVBstore {s} [i+1] p (SHR(W|L)const [8] w) mem))
|
(MOVBstore [i] {s} p1 w x:(MOVBstore {s} [i+1] p0 (SHR(W|L)const [8] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i] {s} p w mem)
|
-> (MOVWstore [i] {s} p0 w mem)
|
||||||
(MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
|
(MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHRLconst [j-8] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i-1] {s} p w0 mem)
|
-> (MOVWstore [i-1] {s} p0 w0 mem)
|
||||||
(MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
|
(MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p0 w mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstore [i-2] {s} p w mem)
|
-> (MOVLstore [i-2] {s} p0 w mem)
|
||||||
(MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
|
(MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHRLconst [j-16] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstore [i-2] {s} p w0 mem)
|
-> (MOVLstore [i-2] {s} p0 w0 mem)
|
||||||
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx (SHR(L|W)const [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
|
// Move constant offsets from LEALx up into load. This lets the above combining
|
||||||
&& x.Uses == 1
|
// rules discover indexed load-combining instances.
|
||||||
&& clobber(x)
|
(MOV(B|W|L)load [i0] {s0} l:(LEAL1 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
-> (MOVWstoreidx1 [i-1] {s} p idx w mem)
|
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL1 <l.Type> [0] {s1} x y) mem)
|
||||||
(MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHR(L|W)const [8] w) mem))
|
(MOV(B|W|L)load [i0] {s0} l:(LEAL2 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x.Uses == 1
|
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL2 <l.Type> [0] {s1} x y) mem)
|
||||||
&& clobber(x)
|
(MOV(B|W|L)load [i0] {s0} l:(LEAL4 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
-> (MOVWstoreidx1 [i] {s} p idx w mem)
|
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL4 <l.Type> [0] {s1} x y) mem)
|
||||||
(MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
|
(MOV(B|W|L)load [i0] {s0} l:(LEAL8 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x.Uses == 1
|
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL8 <l.Type> [0] {s1} x y) mem)
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
|
|
||||||
(MOVWstoreidx1 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p idx w mem)
|
|
||||||
(MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
|
|
||||||
|
|
||||||
(MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
|
(MOV(B|W|L)store [i0] {s0} l:(LEAL1 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x.Uses == 1
|
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL1 <l.Type> [0] {s1} x y) val mem)
|
||||||
&& clobber(x)
|
(MOV(B|W|L)store [i0] {s0} l:(LEAL2 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem)
|
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL2 <l.Type> [0] {s1} x y) val mem)
|
||||||
(MOVWstoreidx2 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
|
(MOV(B|W|L)store [i0] {s0} l:(LEAL4 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x.Uses == 1
|
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL4 <l.Type> [0] {s1} x y) val mem)
|
||||||
&& clobber(x)
|
(MOV(B|W|L)store [i0] {s0} l:(LEAL8 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem)
|
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL8 <l.Type> [0] {s1} x y) val mem)
|
||||||
|
|
||||||
// For PIC, break floating-point constant loading into two instructions so we have
|
// For PIC, break floating-point constant loading into two instructions so we have
|
||||||
// a register to use for holding the address of the constant pool entry.
|
// a register to use for holding the address of the constant pool entry.
|
||||||
|
@ -1043,12 +1043,6 @@
|
|||||||
(MOVWQZX x) && zeroUpper48Bits(x,3) -> x
|
(MOVWQZX x) && zeroUpper48Bits(x,3) -> x
|
||||||
(MOVBQZX x) && zeroUpper56Bits(x,3) -> x
|
(MOVBQZX x) && zeroUpper56Bits(x,3) -> x
|
||||||
|
|
||||||
(MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
|
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
|
||||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
|
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
|
||||||
@ -1166,86 +1160,6 @@
|
|||||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
|
|
||||||
// generating indexed loads and stores
|
|
||||||
(MOV(B|W|L|Q|SS|SD)load [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L|Q|SS|SD)loadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVWload [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOV(L|SS)load [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|SS)loadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOV(L|Q|SD)load [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|Q|SD)loadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q|SS|SD)store [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L|Q|SS|SD)storeidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOV(L|SS)store [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|SS)storeidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
(MOV(L|Q|SD)store [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(L|Q|SD)storeidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q|SS|SD)load [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB ->
|
|
||||||
(MOV(B|W|L|Q|SS|SD)loadidx1 [off] {sym} ptr idx mem)
|
|
||||||
(MOV(B|W|L|Q|SS|SD)store [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB ->
|
|
||||||
(MOV(B|W|L|Q|SS|SD)storeidx1 [off] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q)storeconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOV(B|W|L|Q)storeconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVWstoreconst [x] {sym1} (LEAQ2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVLstoreconst [x] {sym1} (LEAQ4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
(MOVQstoreconst [x] {sym1} (LEAQ8 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
|
|
||||||
(MOVQstoreconstidx8 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q)storeconst [x] {sym} (ADDQ ptr idx) mem) -> (MOV(B|W|L|Q)storeconstidx1 [x] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// combine SHLQ into indexed loads and stores
|
|
||||||
(MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
|
|
||||||
(MOV(L|SS)loadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOV(L|SS)loadidx4 [c] {sym} ptr idx mem)
|
|
||||||
(MOV(L|Q|SD)loadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOV(L|Q|SD)loadidx8 [c] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|SS)storeidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem) -> (MOV(L|SS)storeidx4 [c] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|Q|SD)storeidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem) -> (MOV(L|Q|SD)storeidx8 [c] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
|
|
||||||
(MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// combine ADDQ into pointer of indexed loads and stores
|
|
||||||
(MOV(B|W|L|Q|SS|SD)loadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) && is32Bit(c+d) -> (MOV(B|W|L|Q|SS|SD)loadidx1 [c+d] {sym} ptr idx mem)
|
|
||||||
(MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem) && is32Bit(c+d) -> (MOVWloadidx2 [c+d] {sym} ptr idx mem)
|
|
||||||
(MOV(L|SS)loadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem) && is32Bit(c+d) -> (MOV(L|SS)loadidx4 [c+d] {sym} ptr idx mem)
|
|
||||||
(MOV(L|Q|SD)loadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem) && is32Bit(c+d) -> (MOV(L|Q|SD)loadidx8 [c+d] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q|SS|SD)storeidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) && is32Bit(c+d) -> (MOV(B|W|L|Q|SS|SD)storeidx1 [c+d] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreidx2 [c] {sym} (ADDQconst [d] ptr) idx val mem) && is32Bit(c+d) -> (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|SS)storeidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem) && is32Bit(c+d) -> (MOV(L|SS)storeidx4 [c+d] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|Q|SD)storeidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem) && is32Bit(c+d) -> (MOV(L|Q|SD)storeidx8 [c+d] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
|
|
||||||
// combine ADDQ into index of indexed loads and stores
|
|
||||||
(MOV(B|W|L|Q|SS|SD)loadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) && is32Bit(c+d) -> (MOV(B|W|L|Q|SS|SD)loadidx1 [c+d] {sym} ptr idx mem)
|
|
||||||
(MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem) && is32Bit(c+2*d) -> (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
|
|
||||||
(MOV(L|SS)loadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem) && is32Bit(c+4*d) -> (MOV(L|SS)loadidx4 [c+4*d] {sym} ptr idx mem)
|
|
||||||
(MOV(L|Q|SD)loadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem) && is32Bit(c+8*d) -> (MOV(L|Q|SD)loadidx8 [c+8*d] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q|SS|SD)storeidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) && is32Bit(c+d) -> (MOV(B|W|L|Q|SS|SD)storeidx1 [c+d] {sym} ptr idx val mem)
|
|
||||||
(MOVWstoreidx2 [c] {sym} ptr (ADDQconst [d] idx) val mem) && is32Bit(c+2*d) -> (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|SS)storeidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem) && is32Bit(c+4*d) -> (MOV(L|SS)storeidx4 [c+4*d] {sym} ptr idx val mem)
|
|
||||||
(MOV(L|Q|SD)storeidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem) && is32Bit(c+8*d) -> (MOV(L|Q|SD)storeidx8 [c+8*d] {sym} ptr idx val mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q)storeconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem) && ValAndOff(x).canAdd(c) -> (MOV(B|W|L|Q)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVWstoreconstidx2 [x] {sym} (ADDQconst [c] ptr) idx mem) && ValAndOff(x).canAdd(c) -> (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx4 [x] {sym} (ADDQconst [c] ptr) idx mem) && ValAndOff(x).canAdd(c) -> (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVQstoreconstidx8 [x] {sym} (ADDQconst [c] ptr) idx mem) && ValAndOff(x).canAdd(c) -> (MOVQstoreconstidx8 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
(MOV(B|W|L|Q)storeconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem) && ValAndOff(x).canAdd(c) -> (MOV(B|W|L|Q)storeconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
|
|
||||||
(MOVWstoreconstidx2 [x] {sym} ptr (ADDQconst [c] idx) mem) && ValAndOff(x).canAdd(2*c) -> (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
|
|
||||||
(MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem) && ValAndOff(x).canAdd(4*c) -> (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
|
|
||||||
(MOVQstoreconstidx8 [x] {sym} ptr (ADDQconst [c] idx) mem) && ValAndOff(x).canAdd(8*c) -> (MOVQstoreconstidx8 [ValAndOff(x).add(8*c)] {sym} ptr idx mem)
|
|
||||||
|
|
||||||
// fold LEAQs together
|
// fold LEAQs together
|
||||||
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
(LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
|
(LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
|
||||||
@ -1274,6 +1188,17 @@
|
|||||||
(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
(LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
(LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
|
// LEAQ[1248] into LEAQ[1248]. Only some such merges are possible.
|
||||||
|
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
|
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||||
|
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||||
|
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||||
|
(LEAQ2 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(off1+2*off2) && sym2 == nil ->
|
||||||
|
(LEAQ4 [off1+2*off2] {sym1} x y)
|
||||||
|
(LEAQ4 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(off1+4*off2) && sym2 == nil ->
|
||||||
|
(LEAQ8 [off1+4*off2] {sym1} x y)
|
||||||
|
// TODO: more?
|
||||||
|
|
||||||
// Absorb InvertFlags into branches.
|
// Absorb InvertFlags into branches.
|
||||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||||
(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
|
(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
|
||||||
@ -1329,7 +1254,10 @@
|
|||||||
(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
|
(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
|
||||||
(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
|
(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
|
||||||
|
|
||||||
(TEST(Q|L)const [c] (MOV(Q|L)const [c])) -> (FlagEQ)
|
// TESTQ c c sets flags like CMPQ c 0.
|
||||||
|
(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c == 0 -> (FlagEQ)
|
||||||
|
(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c < 0 -> (FlagLT_UGT)
|
||||||
|
(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c > 0 -> (FlagGT_UGT)
|
||||||
|
|
||||||
// TODO: DIVxU also.
|
// TODO: DIVxU also.
|
||||||
|
|
||||||
@ -1552,60 +1480,65 @@
|
|||||||
|
|
||||||
// Little-endian loads
|
// Little-endian loads
|
||||||
|
|
||||||
(ORL x0:(MOVBload [i0] {s} p mem)
|
(ORL x0:(MOVBload [i0] {s} p0 mem)
|
||||||
sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
|
sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORQ x0:(MOVBload [i0] {s} p mem)
|
(ORQ x0:(MOVBload [i0] {s} p0 mem)
|
||||||
sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem)))
|
sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVWload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORL x0:(MOVWload [i0] {s} p mem)
|
(ORL x0:(MOVWload [i0] {s} p0 mem)
|
||||||
sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem)))
|
sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORQ x0:(MOVWload [i0] {s} p mem)
|
(ORQ x0:(MOVWload [i0] {s} p0 mem)
|
||||||
sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem)))
|
sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVLload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORQ x0:(MOVLload [i0] {s} p mem)
|
(ORQ x0:(MOVLload [i0] {s} p0 mem)
|
||||||
sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem)))
|
sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p1 mem)))
|
||||||
&& i1 == i0+4
|
&& i1 == i0+4
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem)
|
-> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p0 mem)
|
||||||
|
|
||||||
(ORL
|
(ORL
|
||||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
|
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p0 mem))
|
||||||
or:(ORL
|
or:(ORL
|
||||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
|
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p1 mem))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& j1 == j0+8
|
&& j1 == j0+8
|
||||||
@ -1615,14 +1548,15 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
&& clobber(x0, x1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
|
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y)
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
|
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p0 mem))
|
||||||
or:(ORQ
|
or:(ORQ
|
||||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
|
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p1 mem))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& j1 == j0+8
|
&& j1 == j0+8
|
||||||
@ -1632,14 +1566,15 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
&& clobber(x0, x1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p mem)) y)
|
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWload [i0] {s} p0 mem)) y)
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem))
|
s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p0 mem))
|
||||||
or:(ORQ
|
or:(ORQ
|
||||||
s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem))
|
s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p1 mem))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& j1 == j0+16
|
&& j1 == j0+16
|
||||||
@ -1649,180 +1584,105 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
&& clobber(x0, x1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p mem)) y)
|
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLload [i0] {s} p0 mem)) y)
|
||||||
|
|
||||||
// Little-endian indexed loads
|
// Little-endian indexed loads
|
||||||
|
|
||||||
(ORL x0:(MOVBloadidx1 [i0] {s} p idx mem)
|
// Move constants offsets from LEAQx up into load. This lets the above combining
|
||||||
sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
|
// rules discover indexed load-combining instances.
|
||||||
&& i1 == i0+1
|
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x0.Uses == 1
|
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem)
|
||||||
&& x1.Uses == 1
|
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& sh.Uses == 1
|
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& clobber(x0, x1, sh)
|
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) mem)
|
||||||
-> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
|
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ8 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
|
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) mem)
|
||||||
|
|
||||||
(ORQ x0:(MOVBloadidx1 [i0] {s} p idx mem)
|
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {s} p idx mem)))
|
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem)
|
||||||
&& i1 == i0+1
|
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& x0.Uses == 1
|
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem)
|
||||||
&& x1.Uses == 1
|
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& sh.Uses == 1
|
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||||
&& clobber(x0, x1, sh)
|
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem)
|
||||||
-> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
(ORL x0:(MOVWloadidx1 [i0] {s} p idx mem)
|
|
||||||
sh:(SHLLconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
(ORQ x0:(MOVWloadidx1 [i0] {s} p idx mem)
|
|
||||||
sh:(SHLQconst [16] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (MOVLloadidx1 [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
(ORQ x0:(MOVLloadidx1 [i0] {s} p idx mem)
|
|
||||||
sh:(SHLQconst [32] x1:(MOVLloadidx1 [i1] {s} p idx mem)))
|
|
||||||
&& i1 == i0+4
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (MOVQloadidx1 [i0] {s} p idx mem)
|
|
||||||
|
|
||||||
(ORL
|
|
||||||
s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
|
|
||||||
or:(ORL
|
|
||||||
s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& j1 == j0+8
|
|
||||||
&& j0 % 16 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
|
|
||||||
or:(ORQ
|
|
||||||
s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& j1 == j0+8
|
|
||||||
&& j0 % 16 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVWloadidx1 [i0] {s} p idx mem)) y)
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
s1:(SHLQconst [j1] x1:(MOVWloadidx1 [i1] {s} p idx mem))
|
|
||||||
or:(ORQ
|
|
||||||
s0:(SHLQconst [j0] x0:(MOVWloadidx1 [i0] {s} p idx mem))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& j1 == j0+16
|
|
||||||
&& j0 % 32 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j0] (MOVLloadidx1 [i0] {s} p idx mem)) y)
|
|
||||||
|
|
||||||
// Big-endian loads
|
// Big-endian loads
|
||||||
|
|
||||||
(ORL
|
(ORL
|
||||||
x1:(MOVBload [i1] {s} p mem)
|
x1:(MOVBload [i1] {s} p0 mem)
|
||||||
sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p mem)))
|
sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p1 mem)))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
|
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem))
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
x1:(MOVBload [i1] {s} p mem)
|
x1:(MOVBload [i1] {s} p0 mem)
|
||||||
sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p mem)))
|
sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p1 mem)))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, sh)
|
&& clobber(x0, x1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p mem))
|
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWload [i0] {s} p0 mem))
|
||||||
|
|
||||||
(ORL
|
(ORL
|
||||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
|
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem))
|
||||||
sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
|
sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem))))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& r0.Uses == 1
|
&& r0.Uses == 1
|
||||||
&& r1.Uses == 1
|
&& r1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
&& clobber(x0, x1, r0, r1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
|
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem))
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
|
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem))
|
||||||
sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
|
sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem))))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& r0.Uses == 1
|
&& r0.Uses == 1
|
||||||
&& r1.Uses == 1
|
&& r1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
&& clobber(x0, x1, r0, r1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p mem))
|
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLload [i0] {s} p0 mem))
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
r1:(BSWAPL x1:(MOVLload [i1] {s} p mem))
|
r1:(BSWAPL x1:(MOVLload [i1] {s} p0 mem))
|
||||||
sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem))))
|
sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p1 mem))))
|
||||||
&& i1 == i0+4
|
&& i1 == i0+4
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& r0.Uses == 1
|
&& r0.Uses == 1
|
||||||
&& r1.Uses == 1
|
&& r1.Uses == 1
|
||||||
&& sh.Uses == 1
|
&& sh.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1) != nil
|
&& mergePoint(b,x0,x1) != nil
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
&& clobber(x0, x1, r0, r1, sh)
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p mem))
|
-> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQload [i0] {s} p0 mem))
|
||||||
|
|
||||||
(ORL
|
(ORL
|
||||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
|
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p0 mem))
|
||||||
or:(ORL
|
or:(ORL
|
||||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
|
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p1 mem))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& j1 == j0-8
|
&& j1 == j0-8
|
||||||
@ -1832,14 +1692,15 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
&& clobber(x0, x1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
|
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y)
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
|
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p0 mem))
|
||||||
or:(ORQ
|
or:(ORQ
|
||||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
|
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p1 mem))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+1
|
&& i1 == i0+1
|
||||||
&& j1 == j0-8
|
&& j1 == j0-8
|
||||||
@ -1849,14 +1710,15 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
&& clobber(x0, x1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p mem))) y)
|
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWload [i0] {s} p0 mem))) y)
|
||||||
|
|
||||||
(ORQ
|
(ORQ
|
||||||
s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem)))
|
s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p0 mem)))
|
||||||
or:(ORQ
|
or:(ORQ
|
||||||
s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem)))
|
s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p1 mem)))
|
||||||
y))
|
y))
|
||||||
&& i1 == i0+2
|
&& i1 == i0+2
|
||||||
&& j1 == j0-16
|
&& j1 == j0-16
|
||||||
@ -1868,168 +1730,41 @@
|
|||||||
&& s0.Uses == 1
|
&& s0.Uses == 1
|
||||||
&& s1.Uses == 1
|
&& s1.Uses == 1
|
||||||
&& or.Uses == 1
|
&& or.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
&& mergePoint(b,x0,x1,y) != nil
|
||||||
&& clobber(x0, x1, r0, r1, s0, s1, or)
|
&& clobber(x0, x1, r0, r1, s0, s1, or)
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p mem))) y)
|
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p0 mem))) y)
|
||||||
|
|
||||||
// Big-endian indexed loads
|
|
||||||
|
|
||||||
(ORL
|
|
||||||
x1:(MOVBloadidx1 [i1] {s} p idx mem)
|
|
||||||
sh:(SHLLconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
x1:(MOVBloadidx1 [i1] {s} p idx mem)
|
|
||||||
sh:(SHLQconst [8] x0:(MOVBloadidx1 [i0] {s} p idx mem)))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (ROLWconst <v.Type> [8] (MOVWloadidx1 [i0] {s} p idx mem))
|
|
||||||
|
|
||||||
(ORL
|
|
||||||
r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))
|
|
||||||
sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& r0.Uses == 1
|
|
||||||
&& r1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem))
|
|
||||||
sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem))))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& r0.Uses == 1
|
|
||||||
&& r1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPL <v.Type> (MOVLloadidx1 [i0] {s} p idx mem))
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
r1:(BSWAPL x1:(MOVLloadidx1 [i1] {s} p idx mem))
|
|
||||||
sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLloadidx1 [i0] {s} p idx mem))))
|
|
||||||
&& i1 == i0+4
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& r0.Uses == 1
|
|
||||||
&& r1.Uses == 1
|
|
||||||
&& sh.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1) != nil
|
|
||||||
&& clobber(x0, x1, r0, r1, sh)
|
|
||||||
-> @mergePoint(b,x0,x1) (BSWAPQ <v.Type> (MOVQloadidx1 [i0] {s} p idx mem))
|
|
||||||
|
|
||||||
(ORL
|
|
||||||
s0:(SHLLconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
|
|
||||||
or:(ORL
|
|
||||||
s1:(SHLLconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& j1 == j0-8
|
|
||||||
&& j1 % 16 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORL <v.Type> (SHLLconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
s0:(SHLQconst [j0] x0:(MOVBloadidx1 [i0] {s} p idx mem))
|
|
||||||
or:(ORQ
|
|
||||||
s1:(SHLQconst [j1] x1:(MOVBloadidx1 [i1] {s} p idx mem))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+1
|
|
||||||
&& j1 == j0-8
|
|
||||||
&& j1 % 16 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (ROLWconst <typ.UInt16> [8] (MOVWloadidx1 [i0] {s} p idx mem))) y)
|
|
||||||
|
|
||||||
(ORQ
|
|
||||||
s0:(SHLQconst [j0] r0:(ROLWconst [8] x0:(MOVWloadidx1 [i0] {s} p idx mem)))
|
|
||||||
or:(ORQ
|
|
||||||
s1:(SHLQconst [j1] r1:(ROLWconst [8] x1:(MOVWloadidx1 [i1] {s} p idx mem)))
|
|
||||||
y))
|
|
||||||
&& i1 == i0+2
|
|
||||||
&& j1 == j0-16
|
|
||||||
&& j1 % 32 == 0
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& r0.Uses == 1
|
|
||||||
&& r1.Uses == 1
|
|
||||||
&& s0.Uses == 1
|
|
||||||
&& s1.Uses == 1
|
|
||||||
&& or.Uses == 1
|
|
||||||
&& mergePoint(b,x0,x1,y) != nil
|
|
||||||
&& clobber(x0, x1, r0, r1, s0, s1, or)
|
|
||||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLloadidx1 [i0] {s} p idx mem))) y)
|
|
||||||
|
|
||||||
// Combine 2 byte stores + shift into rolw 8 + word store
|
// Combine 2 byte stores + shift into rolw 8 + word store
|
||||||
(MOVBstore [i] {s} p w
|
(MOVBstore [i] {s} p1 w
|
||||||
x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
x0:(MOVBstore [i-1] {s} p0 (SHRWconst [8] w) mem))
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x0)
|
&& clobber(x0)
|
||||||
-> (MOVWstore [i-1] {s} p (ROLWconst <w.Type> [8] w) mem)
|
-> (MOVWstore [i-1] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||||
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx w
|
|
||||||
x0:(MOVBstoreidx1 [i-1] {s} p idx (SHRWconst [8] w) mem))
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& clobber(x0)
|
|
||||||
-> (MOVWstoreidx1 [i-1] {s} p idx (ROLWconst <w.Type> [8] w) mem)
|
|
||||||
|
|
||||||
// Combine stores + shifts into bswap and larger (unaligned) stores
|
// Combine stores + shifts into bswap and larger (unaligned) stores
|
||||||
(MOVBstore [i] {s} p w
|
(MOVBstore [i] {s} p3 w
|
||||||
x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w)
|
x2:(MOVBstore [i-1] {s} p2 (SHRLconst [8] w)
|
||||||
x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w)
|
x1:(MOVBstore [i-2] {s} p1 (SHRLconst [16] w)
|
||||||
x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
|
x0:(MOVBstore [i-3] {s} p0 (SHRLconst [24] w) mem))))
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& x2.Uses == 1
|
&& x2.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
|
&& same(p1, p2, 1)
|
||||||
|
&& same(p2, p3, 1)
|
||||||
&& clobber(x0, x1, x2)
|
&& clobber(x0, x1, x2)
|
||||||
-> (MOVLstore [i-3] {s} p (BSWAPL <w.Type> w) mem)
|
-> (MOVLstore [i-3] {s} p0 (BSWAPL <w.Type> w) mem)
|
||||||
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx w
|
(MOVBstore [i] {s} p7 w
|
||||||
x2:(MOVBstoreidx1 [i-1] {s} p idx (SHRLconst [8] w)
|
x6:(MOVBstore [i-1] {s} p6 (SHRQconst [8] w)
|
||||||
x1:(MOVBstoreidx1 [i-2] {s} p idx (SHRLconst [16] w)
|
x5:(MOVBstore [i-2] {s} p5 (SHRQconst [16] w)
|
||||||
x0:(MOVBstoreidx1 [i-3] {s} p idx (SHRLconst [24] w) mem))))
|
x4:(MOVBstore [i-3] {s} p4 (SHRQconst [24] w)
|
||||||
&& x0.Uses == 1
|
x3:(MOVBstore [i-4] {s} p3 (SHRQconst [32] w)
|
||||||
&& x1.Uses == 1
|
x2:(MOVBstore [i-5] {s} p2 (SHRQconst [40] w)
|
||||||
&& x2.Uses == 1
|
x1:(MOVBstore [i-6] {s} p1 (SHRQconst [48] w)
|
||||||
&& clobber(x0, x1, x2)
|
x0:(MOVBstore [i-7] {s} p0 (SHRQconst [56] w) mem))))))))
|
||||||
-> (MOVLstoreidx1 [i-3] {s} p idx (BSWAPL <w.Type> w) mem)
|
|
||||||
|
|
||||||
(MOVBstore [i] {s} p w
|
|
||||||
x6:(MOVBstore [i-1] {s} p (SHRQconst [8] w)
|
|
||||||
x5:(MOVBstore [i-2] {s} p (SHRQconst [16] w)
|
|
||||||
x4:(MOVBstore [i-3] {s} p (SHRQconst [24] w)
|
|
||||||
x3:(MOVBstore [i-4] {s} p (SHRQconst [32] w)
|
|
||||||
x2:(MOVBstore [i-5] {s} p (SHRQconst [40] w)
|
|
||||||
x1:(MOVBstore [i-6] {s} p (SHRQconst [48] w)
|
|
||||||
x0:(MOVBstore [i-7] {s} p (SHRQconst [56] w) mem))))))))
|
|
||||||
&& x0.Uses == 1
|
&& x0.Uses == 1
|
||||||
&& x1.Uses == 1
|
&& x1.Uses == 1
|
||||||
&& x2.Uses == 1
|
&& x2.Uses == 1
|
||||||
@ -2037,165 +1772,99 @@
|
|||||||
&& x4.Uses == 1
|
&& x4.Uses == 1
|
||||||
&& x5.Uses == 1
|
&& x5.Uses == 1
|
||||||
&& x6.Uses == 1
|
&& x6.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
|
&& same(p1, p2, 1)
|
||||||
|
&& same(p2, p3, 1)
|
||||||
|
&& same(p3, p4, 1)
|
||||||
|
&& same(p4, p5, 1)
|
||||||
|
&& same(p5, p6, 1)
|
||||||
|
&& same(p6, p7, 1)
|
||||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
||||||
-> (MOVQstore [i-7] {s} p (BSWAPQ <w.Type> w) mem)
|
-> (MOVQstore [i-7] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||||
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx w
|
|
||||||
x6:(MOVBstoreidx1 [i-1] {s} p idx (SHRQconst [8] w)
|
|
||||||
x5:(MOVBstoreidx1 [i-2] {s} p idx (SHRQconst [16] w)
|
|
||||||
x4:(MOVBstoreidx1 [i-3] {s} p idx (SHRQconst [24] w)
|
|
||||||
x3:(MOVBstoreidx1 [i-4] {s} p idx (SHRQconst [32] w)
|
|
||||||
x2:(MOVBstoreidx1 [i-5] {s} p idx (SHRQconst [40] w)
|
|
||||||
x1:(MOVBstoreidx1 [i-6] {s} p idx (SHRQconst [48] w)
|
|
||||||
x0:(MOVBstoreidx1 [i-7] {s} p idx (SHRQconst [56] w) mem))))))))
|
|
||||||
&& x0.Uses == 1
|
|
||||||
&& x1.Uses == 1
|
|
||||||
&& x2.Uses == 1
|
|
||||||
&& x3.Uses == 1
|
|
||||||
&& x4.Uses == 1
|
|
||||||
&& x5.Uses == 1
|
|
||||||
&& x6.Uses == 1
|
|
||||||
&& clobber(x0, x1, x2, x3, x4, x5, x6)
|
|
||||||
-> (MOVQstoreidx1 [i-7] {s} p idx (BSWAPQ <w.Type> w) mem)
|
|
||||||
|
|
||||||
// Combine constant stores into larger (unaligned) stores.
|
// Combine constant stores into larger (unaligned) stores.
|
||||||
(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
|
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
(MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
(MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||||
(MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
|
(MOVLstoreconst [c] {s} p1 x:(MOVLstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
-> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||||
(MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem))
|
(MOVLstoreconst [a] {s} p1 x:(MOVLstoreconst [c] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
-> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||||
(MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem))
|
(MOVQstoreconst [c] {s} p1 x:(MOVQstoreconst [c2] {s} p0 mem))
|
||||||
&& config.useSSE
|
&& config.useSSE
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& ValAndOff(c2).Off() + 8 == ValAndOff(c).Off()
|
&& ValAndOff(c2).Off() + 8 == ValAndOff(c).Off()
|
||||||
&& ValAndOff(c).Val() == 0
|
&& ValAndOff(c).Val() == 0
|
||||||
&& ValAndOff(c2).Val() == 0
|
&& ValAndOff(c2).Val() == 0
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVOstore [ValAndOff(c2).Off()] {s} p (MOVOconst [0]) mem)
|
-> (MOVOstore [ValAndOff(c2).Off()] {s} p0 (MOVOconst [0]) mem)
|
||||||
|
|
||||||
(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
|
|
||||||
(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
|
|
||||||
(MOVLstoreconstidx1 [c] {s} p i x:(MOVLstoreconstidx1 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p i (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
|
||||||
|
|
||||||
(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLQconst <i.Type> [1] i) mem)
|
|
||||||
(MOVLstoreconstidx4 [c] {s} p i x:(MOVLstoreconstidx4 [a] {s} p i mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p (SHLQconst <i.Type> [2] i) (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
|
||||||
|
|
||||||
// Combine stores into larger (unaligned) stores.
|
// Combine stores into larger (unaligned) stores.
|
||||||
(MOVBstore [i] {s} p (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
(MOVBstore [i] {s} p1 (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p0 w mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i-1] {s} p w mem)
|
-> (MOVWstore [i-1] {s} p0 w mem)
|
||||||
(MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHR(W|L|Q)const [8] w) mem))
|
(MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHR(W|L|Q)const [8] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i] {s} p w mem)
|
-> (MOVWstore [i] {s} p0 w mem)
|
||||||
(MOVBstore [i] {s} p (SHR(L|Q)const [j] w) x:(MOVBstore [i-1] {s} p w0:(SHR(L|Q)const [j-8] w) mem))
|
(MOVBstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHR(L|Q)const [j-8] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVWstore [i-1] {s} p w0 mem)
|
-> (MOVWstore [i-1] {s} p0 w0 mem)
|
||||||
(MOVWstore [i] {s} p (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p w mem))
|
(MOVWstore [i] {s} p1 (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p0 w mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstore [i-2] {s} p w mem)
|
-> (MOVLstore [i-2] {s} p0 w mem)
|
||||||
(MOVWstore [i] {s} p (SHR(L|Q)const [j] w) x:(MOVWstore [i-2] {s} p w0:(SHR(L|Q)const [j-16] w) mem))
|
(MOVWstore [i] {s} p1 (SHR(L|Q)const [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHR(L|Q)const [j-16] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVLstore [i-2] {s} p w0 mem)
|
-> (MOVLstore [i-2] {s} p0 w0 mem)
|
||||||
(MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
|
(MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p0 w mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVQstore [i-4] {s} p w mem)
|
-> (MOVQstore [i-4] {s} p0 w mem)
|
||||||
(MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
|
(MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p0 w0:(SHRQconst [j-32] w) mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
|
&& same(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
-> (MOVQstore [i-4] {s} p w0 mem)
|
-> (MOVQstore [i-4] {s} p0 w0 mem)
|
||||||
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx (SHR(W|L|Q)const [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVWstoreidx1 [i-1] {s} p idx w mem)
|
|
||||||
(MOVBstoreidx1 [i] {s} p idx (SHR(L|Q)const [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHR(L|Q)const [j-8] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
|
|
||||||
(MOVWstoreidx1 [i] {s} p idx (SHR(L|Q)const [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p idx w mem)
|
|
||||||
(MOVWstoreidx1 [i] {s} p idx (SHR(L|Q)const [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHR(L|Q)const [j-16] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
|
|
||||||
(MOVLstoreidx1 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx1 [i-4] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [i-4] {s} p idx w mem)
|
|
||||||
(MOVLstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx1 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [i-4] {s} p idx w0 mem)
|
|
||||||
|
|
||||||
(MOVWstoreidx2 [i] {s} p idx (SHR(L|Q)const [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
|
|
||||||
(MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
|
|
||||||
(MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
|
|
||||||
(MOVLstoreidx4 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx4 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
|
|
||||||
&& x.Uses == 1
|
|
||||||
&& clobber(x)
|
|
||||||
-> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
|
|
||||||
|
|
||||||
(MOVBstore [i] {s} p
|
(MOVBstore [i] {s} p
|
||||||
x1:(MOVBload [j] {s2} p2 mem)
|
x1:(MOVBload [j] {s2} p2 mem)
|
||||||
@ -2320,41 +1989,6 @@
|
|||||||
(BSFQ (ORQconst <t> [1<<8] (MOVBQZX x))) -> (BSFQ (ORQconst <t> [1<<8] x))
|
(BSFQ (ORQconst <t> [1<<8] (MOVBQZX x))) -> (BSFQ (ORQconst <t> [1<<8] x))
|
||||||
(BSFQ (ORQconst <t> [1<<16] (MOVWQZX x))) -> (BSFQ (ORQconst <t> [1<<16] x))
|
(BSFQ (ORQconst <t> [1<<16] (MOVWQZX x))) -> (BSFQ (ORQconst <t> [1<<16] x))
|
||||||
|
|
||||||
// Simplify indexed loads/stores
|
|
||||||
(MOVBstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVBstore [i+c] {s} p w mem)
|
|
||||||
(MOVWstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVWstore [i+c] {s} p w mem)
|
|
||||||
(MOVLstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVLstore [i+c] {s} p w mem)
|
|
||||||
(MOVQstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVQstore [i+c] {s} p w mem)
|
|
||||||
(MOVWstoreidx2 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+2*c) -> (MOVWstore [i+2*c] {s} p w mem)
|
|
||||||
(MOVLstoreidx4 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+4*c) -> (MOVLstore [i+4*c] {s} p w mem)
|
|
||||||
(MOVLstoreidx8 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+8*c) -> (MOVLstore [i+8*c] {s} p w mem)
|
|
||||||
(MOVQstoreidx8 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+8*c) -> (MOVQstore [i+8*c] {s} p w mem)
|
|
||||||
(MOVSSstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVSSstore [i+c] {s} p w mem)
|
|
||||||
(MOVSSstoreidx4 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+4*c) -> (MOVSSstore [i+4*c] {s} p w mem)
|
|
||||||
(MOVSDstoreidx1 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+c) -> (MOVSDstore [i+c] {s} p w mem)
|
|
||||||
(MOVSDstoreidx8 [i] {s} p (MOVQconst [c]) w mem) && is32Bit(i+8*c) -> (MOVSDstore [i+8*c] {s} p w mem)
|
|
||||||
(MOVBloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVBload [i+c] {s} p mem)
|
|
||||||
(MOVWloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVWload [i+c] {s} p mem)
|
|
||||||
(MOVLloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVLload [i+c] {s} p mem)
|
|
||||||
(MOVQloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVQload [i+c] {s} p mem)
|
|
||||||
(MOVWloadidx2 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+2*c) -> (MOVWload [i+2*c] {s} p mem)
|
|
||||||
(MOVLloadidx4 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+4*c) -> (MOVLload [i+4*c] {s} p mem)
|
|
||||||
(MOVLloadidx8 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+8*c) -> (MOVLload [i+8*c] {s} p mem)
|
|
||||||
(MOVQloadidx8 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+8*c) -> (MOVQload [i+8*c] {s} p mem)
|
|
||||||
(MOVSSloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVSSload [i+c] {s} p mem)
|
|
||||||
(MOVSSloadidx4 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+4*c) -> (MOVSSload [i+4*c] {s} p mem)
|
|
||||||
(MOVSDloadidx1 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+c) -> (MOVSDload [i+c] {s} p mem)
|
|
||||||
(MOVSDloadidx8 [i] {s} p (MOVQconst [c]) mem) && is32Bit(i+8*c) -> (MOVSDload [i+8*c] {s} p mem)
|
|
||||||
|
|
||||||
// Combine consts into storeidx.
|
|
||||||
// Note that when c == 0, it takes more bytes to encode
|
|
||||||
// the immediate $0 than to zero a register and use it.
|
|
||||||
// We do the rewrite anyway, to minimize register pressure.
|
|
||||||
(MOVBstoreidx1 [off] {s} ptr idx (MOVLconst [c]) mem) && validValAndOff(int64(int8(c)), off) -> (MOVBstoreconstidx1 [makeValAndOff(int64(int8(c)), off)] {s} ptr idx mem)
|
|
||||||
(MOVWstoreidx(1|2) [off] {s} ptr idx (MOVLconst [c]) mem) && validValAndOff(int64(int16(c)), off) -> (MOVWstoreconstidx(1|2) [makeValAndOff(int64(int16(c)), off)] {s} ptr idx mem)
|
|
||||||
(MOVLstoreidx(1|4) [off] {s} ptr idx (MOVQconst [c]) mem) && validValAndOff(int64(int32(c)), off) -> (MOVLstoreconstidx(1|4) [makeValAndOff(int64(int32(c)), off)] {s} ptr idx mem)
|
|
||||||
(MOVQstoreidx(1|8) [off] {s} ptr idx (MOVQconst [c]) mem) && validValAndOff(c, off) -> (MOVQstoreconstidx(1|8) [makeValAndOff(c, off)] {s} ptr idx mem)
|
|
||||||
|
|
||||||
// Redundant sign/zero extensions
|
// Redundant sign/zero extensions
|
||||||
// Note: see issue 21963. We have to make sure we use the right type on
|
// Note: see issue 21963. We have to make sure we use the right type on
|
||||||
// the resulting extension (the outer type, not the inner type).
|
// the resulting extension (the outer type, not the inner type).
|
||||||
|
@ -245,6 +245,7 @@ dd.ssa-prog {
|
|||||||
svg {
|
svg {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
outline: 1px solid #eee;
|
outline: 1px solid #eee;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.darkmode {
|
body.darkmode {
|
||||||
@ -975,7 +976,7 @@ func (d *dotWriter) writeFuncSVG(w io.Writer, phase string, f *Func) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprint(pipe, `digraph "" { margin=0; size="4,40"; ranksep=.2; `)
|
fmt.Fprint(pipe, `digraph "" { margin=0; ranksep=.2; `)
|
||||||
id := strings.Replace(phase, " ", "-", -1)
|
id := strings.Replace(phase, " ", "-", -1)
|
||||||
fmt.Fprintf(pipe, `id="g_graph_%s";`, id)
|
fmt.Fprintf(pipe, `id="g_graph_%s";`, id)
|
||||||
fmt.Fprintf(pipe, `node [style=filled,fillcolor=white,fontsize=16,fontname="Menlo,Times,serif",margin="0.01,0.03"];`)
|
fmt.Fprintf(pipe, `node [style=filled,fillcolor=white,fontsize=16,fontname="Menlo,Times,serif",margin="0.01,0.03"];`)
|
||||||
|
@ -1305,9 +1305,9 @@ func isNonNegative(v *Value) bool {
|
|||||||
if !v.Type.IsInteger() {
|
if !v.Type.IsInteger() {
|
||||||
panic("isNonNegative bad type")
|
panic("isNonNegative bad type")
|
||||||
}
|
}
|
||||||
if !v.Type.IsSigned() {
|
// TODO: return true if !v.Type.IsSigned()
|
||||||
return true
|
// SSA isn't type-safe enough to do that now (issue 37753).
|
||||||
}
|
// The checks below depend only on the pattern of bits.
|
||||||
|
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpConst64:
|
case OpConst64:
|
||||||
|
@ -1247,3 +1247,43 @@ func read64(sym interface{}, off int64, byteorder binary.ByteOrder) uint64 {
|
|||||||
copy(buf, src)
|
copy(buf, src)
|
||||||
return byteorder.Uint64(buf)
|
return byteorder.Uint64(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same reports whether x and y are the same value.
|
||||||
|
// It checks to a maximum depth of d, so it may report
|
||||||
|
// a false negative.
|
||||||
|
func same(x, y *Value, depth int) bool {
|
||||||
|
if x == y {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if depth <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if x.Op != y.Op || x.Aux != y.Aux || x.AuxInt != y.AuxInt {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(x.Args) != len(y.Args) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if opcodeTable[x.Op].commutative {
|
||||||
|
// Check exchanged ordering first.
|
||||||
|
for i, a := range x.Args {
|
||||||
|
j := i
|
||||||
|
if j < 2 {
|
||||||
|
j ^= 1
|
||||||
|
}
|
||||||
|
b := y.Args[j]
|
||||||
|
if !same(a, b, depth-1) {
|
||||||
|
goto checkNormalOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
checkNormalOrder:
|
||||||
|
}
|
||||||
|
for i, a := range x.Args {
|
||||||
|
b := y.Args[i]
|
||||||
|
if !same(a, b, depth-1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -50,16 +50,23 @@ func (s *scanner) init(src io.Reader, errh func(line, col uint, msg string), mod
|
|||||||
|
|
||||||
// errorf reports an error at the most recently read character position.
|
// errorf reports an error at the most recently read character position.
|
||||||
func (s *scanner) errorf(format string, args ...interface{}) {
|
func (s *scanner) errorf(format string, args ...interface{}) {
|
||||||
s.bad = true
|
|
||||||
s.error(fmt.Sprintf(format, args...))
|
s.error(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorAtf reports an error at a byte column offset relative to the current token start.
|
// errorAtf reports an error at a byte column offset relative to the current token start.
|
||||||
func (s *scanner) errorAtf(offset int, format string, args ...interface{}) {
|
func (s *scanner) errorAtf(offset int, format string, args ...interface{}) {
|
||||||
s.bad = true
|
|
||||||
s.errh(s.line, s.col+uint(offset), fmt.Sprintf(format, args...))
|
s.errh(s.line, s.col+uint(offset), fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setLit sets the scanner state for a recognized _Literal token.
|
||||||
|
func (s *scanner) setLit(kind LitKind, ok bool) {
|
||||||
|
s.nlsemi = true
|
||||||
|
s.tok = _Literal
|
||||||
|
s.lit = string(s.segment())
|
||||||
|
s.bad = !ok
|
||||||
|
s.kind = kind
|
||||||
|
}
|
||||||
|
|
||||||
// next advances the scanner by reading the next token.
|
// next advances the scanner by reading the next token.
|
||||||
//
|
//
|
||||||
// If a read, source encoding, or lexical error occurs, next calls
|
// If a read, source encoding, or lexical error occurs, next calls
|
||||||
@ -461,8 +468,8 @@ func (s *scanner) digits(base int, invalid *int) (digsep int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) number(seenPoint bool) {
|
func (s *scanner) number(seenPoint bool) {
|
||||||
s.bad = false
|
ok := true
|
||||||
|
kind := IntLit
|
||||||
base := 10 // number base
|
base := 10 // number base
|
||||||
prefix := rune(0) // one of 0 (decimal), '0' (0-octal), 'x', 'o', or 'b'
|
prefix := rune(0) // one of 0 (decimal), '0' (0-octal), 'x', 'o', or 'b'
|
||||||
digsep := 0 // bit 0: digit present, bit 1: '_' present
|
digsep := 0 // bit 0: digit present, bit 1: '_' present
|
||||||
@ -470,7 +477,6 @@ func (s *scanner) number(seenPoint bool) {
|
|||||||
|
|
||||||
// integer part
|
// integer part
|
||||||
if !seenPoint {
|
if !seenPoint {
|
||||||
s.kind = IntLit
|
|
||||||
if s.ch == '0' {
|
if s.ch == '0' {
|
||||||
s.nextch()
|
s.nextch()
|
||||||
switch lower(s.ch) {
|
switch lower(s.ch) {
|
||||||
@ -491,7 +497,8 @@ func (s *scanner) number(seenPoint bool) {
|
|||||||
digsep |= s.digits(base, &invalid)
|
digsep |= s.digits(base, &invalid)
|
||||||
if s.ch == '.' {
|
if s.ch == '.' {
|
||||||
if prefix == 'o' || prefix == 'b' {
|
if prefix == 'o' || prefix == 'b' {
|
||||||
s.errorf("invalid radix point in %s", litname(prefix))
|
s.errorf("invalid radix point in %s literal", baseName(base))
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
seenPoint = true
|
seenPoint = true
|
||||||
@ -500,68 +507,77 @@ func (s *scanner) number(seenPoint bool) {
|
|||||||
|
|
||||||
// fractional part
|
// fractional part
|
||||||
if seenPoint {
|
if seenPoint {
|
||||||
s.kind = FloatLit
|
kind = FloatLit
|
||||||
digsep |= s.digits(base, &invalid)
|
digsep |= s.digits(base, &invalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if digsep&1 == 0 && !s.bad {
|
if digsep&1 == 0 && ok {
|
||||||
s.errorf("%s has no digits", litname(prefix))
|
s.errorf("%s literal has no digits", baseName(base))
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// exponent
|
// exponent
|
||||||
if e := lower(s.ch); e == 'e' || e == 'p' {
|
if e := lower(s.ch); e == 'e' || e == 'p' {
|
||||||
if !s.bad {
|
if ok {
|
||||||
switch {
|
switch {
|
||||||
case e == 'e' && prefix != 0 && prefix != '0':
|
case e == 'e' && prefix != 0 && prefix != '0':
|
||||||
s.errorf("%q exponent requires decimal mantissa", s.ch)
|
s.errorf("%q exponent requires decimal mantissa", s.ch)
|
||||||
|
ok = false
|
||||||
case e == 'p' && prefix != 'x':
|
case e == 'p' && prefix != 'x':
|
||||||
s.errorf("%q exponent requires hexadecimal mantissa", s.ch)
|
s.errorf("%q exponent requires hexadecimal mantissa", s.ch)
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
s.kind = FloatLit
|
kind = FloatLit
|
||||||
if s.ch == '+' || s.ch == '-' {
|
if s.ch == '+' || s.ch == '-' {
|
||||||
s.nextch()
|
s.nextch()
|
||||||
}
|
}
|
||||||
digsep = s.digits(10, nil) | digsep&2 // don't lose sep bit
|
digsep = s.digits(10, nil) | digsep&2 // don't lose sep bit
|
||||||
if digsep&1 == 0 && !s.bad {
|
if digsep&1 == 0 && ok {
|
||||||
s.errorf("exponent has no digits")
|
s.errorf("exponent has no digits")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
} else if prefix == 'x' && s.kind == FloatLit && !s.bad {
|
} else if prefix == 'x' && kind == FloatLit && ok {
|
||||||
s.errorf("hexadecimal mantissa requires a 'p' exponent")
|
s.errorf("hexadecimal mantissa requires a 'p' exponent")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// suffix 'i'
|
// suffix 'i'
|
||||||
if s.ch == 'i' {
|
if s.ch == 'i' {
|
||||||
s.kind = ImagLit
|
kind = ImagLit
|
||||||
s.nextch()
|
s.nextch()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.nlsemi = true
|
s.setLit(kind, ok) // do this now so we can use s.lit below
|
||||||
s.lit = string(s.segment())
|
|
||||||
s.tok = _Literal
|
|
||||||
|
|
||||||
if s.kind == IntLit && invalid >= 0 && !s.bad {
|
if kind == IntLit && invalid >= 0 && ok {
|
||||||
s.errorAtf(invalid, "invalid digit %q in %s", s.lit[invalid], litname(prefix))
|
s.errorAtf(invalid, "invalid digit %q in %s literal", s.lit[invalid], baseName(base))
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if digsep&2 != 0 && !s.bad {
|
if digsep&2 != 0 && ok {
|
||||||
if i := invalidSep(s.lit); i >= 0 {
|
if i := invalidSep(s.lit); i >= 0 {
|
||||||
s.errorAtf(i, "'_' must separate successive digits")
|
s.errorAtf(i, "'_' must separate successive digits")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.bad = !ok // correct s.bad
|
||||||
}
|
}
|
||||||
|
|
||||||
func litname(prefix rune) string {
|
func baseName(base int) string {
|
||||||
switch prefix {
|
switch base {
|
||||||
case 'x':
|
case 2:
|
||||||
return "hexadecimal literal"
|
return "binary"
|
||||||
case 'o', '0':
|
case 8:
|
||||||
return "octal literal"
|
return "octal"
|
||||||
case 'b':
|
case 10:
|
||||||
return "binary literal"
|
return "decimal"
|
||||||
|
case 16:
|
||||||
|
return "hexadecimal"
|
||||||
}
|
}
|
||||||
return "decimal literal"
|
panic("invalid base")
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidSep returns the index of the first invalid separator in x, or -1.
|
// invalidSep returns the index of the first invalid separator in x, or -1.
|
||||||
@ -605,17 +621,19 @@ func invalidSep(x string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) rune() {
|
func (s *scanner) rune() {
|
||||||
s.bad = false
|
ok := true
|
||||||
s.nextch()
|
s.nextch()
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
for ; ; n++ {
|
for ; ; n++ {
|
||||||
if s.ch == '\'' {
|
if s.ch == '\'' {
|
||||||
if !s.bad {
|
if ok {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
s.errorf("empty rune literal or unescaped '")
|
s.errorf("empty rune literal or unescaped '")
|
||||||
|
ok = false
|
||||||
} else if n != 1 {
|
} else if n != 1 {
|
||||||
s.errorAtf(0, "more than one character in rune literal")
|
s.errorAtf(0, "more than one character in rune literal")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
@ -623,32 +641,33 @@ func (s *scanner) rune() {
|
|||||||
}
|
}
|
||||||
if s.ch == '\\' {
|
if s.ch == '\\' {
|
||||||
s.nextch()
|
s.nextch()
|
||||||
s.escape('\'')
|
if !s.escape('\'') {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s.ch == '\n' {
|
if s.ch == '\n' {
|
||||||
if !s.bad {
|
if ok {
|
||||||
s.errorf("newline in rune literal")
|
s.errorf("newline in rune literal")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if s.ch < 0 {
|
if s.ch < 0 {
|
||||||
if !s.bad {
|
if ok {
|
||||||
s.errorAtf(0, "rune literal not terminated")
|
s.errorAtf(0, "rune literal not terminated")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.nlsemi = true
|
s.setLit(RuneLit, ok)
|
||||||
s.lit = string(s.segment())
|
|
||||||
s.kind = RuneLit
|
|
||||||
s.tok = _Literal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) stdString() {
|
func (s *scanner) stdString() {
|
||||||
s.bad = false
|
ok := true
|
||||||
s.nextch()
|
s.nextch()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -658,28 +677,29 @@ func (s *scanner) stdString() {
|
|||||||
}
|
}
|
||||||
if s.ch == '\\' {
|
if s.ch == '\\' {
|
||||||
s.nextch()
|
s.nextch()
|
||||||
s.escape('"')
|
if !s.escape('"') {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s.ch == '\n' {
|
if s.ch == '\n' {
|
||||||
s.errorf("newline in string")
|
s.errorf("newline in string")
|
||||||
|
ok = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if s.ch < 0 {
|
if s.ch < 0 {
|
||||||
s.errorAtf(0, "string not terminated")
|
s.errorAtf(0, "string not terminated")
|
||||||
|
ok = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.nlsemi = true
|
s.setLit(StringLit, ok)
|
||||||
s.lit = string(s.segment())
|
|
||||||
s.kind = StringLit
|
|
||||||
s.tok = _Literal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) rawString() {
|
func (s *scanner) rawString() {
|
||||||
s.bad = false
|
ok := true
|
||||||
s.nextch()
|
s.nextch()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -689,6 +709,7 @@ func (s *scanner) rawString() {
|
|||||||
}
|
}
|
||||||
if s.ch < 0 {
|
if s.ch < 0 {
|
||||||
s.errorAtf(0, "string not terminated")
|
s.errorAtf(0, "string not terminated")
|
||||||
|
ok = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.nextch()
|
s.nextch()
|
||||||
@ -697,10 +718,7 @@ func (s *scanner) rawString() {
|
|||||||
// literal (even though they are not part of the literal
|
// literal (even though they are not part of the literal
|
||||||
// value).
|
// value).
|
||||||
|
|
||||||
s.nlsemi = true
|
s.setLit(StringLit, ok)
|
||||||
s.lit = string(s.segment())
|
|
||||||
s.kind = StringLit
|
|
||||||
s.tok = _Literal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) comment(text string) {
|
func (s *scanner) comment(text string) {
|
||||||
@ -797,14 +815,14 @@ func (s *scanner) fullComment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) escape(quote rune) {
|
func (s *scanner) escape(quote rune) bool {
|
||||||
var n int
|
var n int
|
||||||
var base, max uint32
|
var base, max uint32
|
||||||
|
|
||||||
switch s.ch {
|
switch s.ch {
|
||||||
case quote, 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
|
case quote, 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
|
||||||
s.nextch()
|
s.nextch()
|
||||||
return
|
return true
|
||||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||||
n, base, max = 3, 8, 255
|
n, base, max = 3, 8, 255
|
||||||
case 'x':
|
case 'x':
|
||||||
@ -818,16 +836,16 @@ func (s *scanner) escape(quote rune) {
|
|||||||
n, base, max = 8, 16, unicode.MaxRune
|
n, base, max = 8, 16, unicode.MaxRune
|
||||||
default:
|
default:
|
||||||
if s.ch < 0 {
|
if s.ch < 0 {
|
||||||
return // complain in caller about EOF
|
return true // complain in caller about EOF
|
||||||
}
|
}
|
||||||
s.errorf("unknown escape")
|
s.errorf("unknown escape")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var x uint32
|
var x uint32
|
||||||
for i := n; i > 0; i-- {
|
for i := n; i > 0; i-- {
|
||||||
if s.ch < 0 {
|
if s.ch < 0 {
|
||||||
return // complain in caller about EOF
|
return true // complain in caller about EOF
|
||||||
}
|
}
|
||||||
d := base
|
d := base
|
||||||
if isDecimal(s.ch) {
|
if isDecimal(s.ch) {
|
||||||
@ -836,12 +854,8 @@ func (s *scanner) escape(quote rune) {
|
|||||||
d = uint32(lower(s.ch)) - 'a' + 10
|
d = uint32(lower(s.ch)) - 'a' + 10
|
||||||
}
|
}
|
||||||
if d >= base {
|
if d >= base {
|
||||||
kind := "hex"
|
s.errorf("invalid character %q in %s escape", s.ch, baseName(int(base)))
|
||||||
if base == 8 {
|
return false
|
||||||
kind = "octal"
|
|
||||||
}
|
|
||||||
s.errorf("invalid character %q in %s escape", s.ch, kind)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
// d < base
|
// d < base
|
||||||
x = x*base + d
|
x = x*base + d
|
||||||
@ -850,10 +864,13 @@ func (s *scanner) escape(quote rune) {
|
|||||||
|
|
||||||
if x > max && base == 8 {
|
if x > max && base == 8 {
|
||||||
s.errorf("octal escape value %d > 255", x)
|
s.errorf("octal escape value %d > 255", x)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if x > max || 0xD800 <= x && x < 0xE000 /* surrogate range */ {
|
if x > max || 0xD800 <= x && x < 0xE000 /* surrogate range */ {
|
||||||
s.errorf("escape is invalid Unicode code point %#U", x)
|
s.errorf("escape is invalid Unicode code point %#U", x)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
@ -613,9 +613,9 @@ func TestScanErrors(t *testing.T) {
|
|||||||
{`'\`, "rune literal not terminated", 0, 0},
|
{`'\`, "rune literal not terminated", 0, 0},
|
||||||
{`'\'`, "rune literal not terminated", 0, 0},
|
{`'\'`, "rune literal not terminated", 0, 0},
|
||||||
{`'\x`, "rune literal not terminated", 0, 0},
|
{`'\x`, "rune literal not terminated", 0, 0},
|
||||||
{`'\x'`, "invalid character '\\'' in hex escape", 0, 3},
|
{`'\x'`, "invalid character '\\'' in hexadecimal escape", 0, 3},
|
||||||
{`'\y'`, "unknown escape", 0, 2},
|
{`'\y'`, "unknown escape", 0, 2},
|
||||||
{`'\x0'`, "invalid character '\\'' in hex escape", 0, 4},
|
{`'\x0'`, "invalid character '\\'' in hexadecimal escape", 0, 4},
|
||||||
{`'\00'`, "invalid character '\\'' in octal escape", 0, 4},
|
{`'\00'`, "invalid character '\\'' in octal escape", 0, 4},
|
||||||
{`'\377' /*`, "comment not terminated", 0, 7}, // valid octal escape
|
{`'\377' /*`, "comment not terminated", 0, 7}, // valid octal escape
|
||||||
{`'\378`, "invalid character '8' in octal escape", 0, 4},
|
{`'\378`, "invalid character '8' in octal escape", 0, 4},
|
||||||
@ -633,9 +633,9 @@ func TestScanErrors(t *testing.T) {
|
|||||||
{`"\`, "string not terminated", 0, 0},
|
{`"\`, "string not terminated", 0, 0},
|
||||||
{`"\"`, "string not terminated", 0, 0},
|
{`"\"`, "string not terminated", 0, 0},
|
||||||
{`"\x`, "string not terminated", 0, 0},
|
{`"\x`, "string not terminated", 0, 0},
|
||||||
{`"\x"`, "invalid character '\"' in hex escape", 0, 3},
|
{`"\x"`, "invalid character '\"' in hexadecimal escape", 0, 3},
|
||||||
{`"\y"`, "unknown escape", 0, 2},
|
{`"\y"`, "unknown escape", 0, 2},
|
||||||
{`"\x0"`, "invalid character '\"' in hex escape", 0, 4},
|
{`"\x0"`, "invalid character '\"' in hexadecimal escape", 0, 4},
|
||||||
{`"\00"`, "invalid character '\"' in octal escape", 0, 4},
|
{`"\00"`, "invalid character '\"' in octal escape", 0, 4},
|
||||||
{`"\377" /*`, "comment not terminated", 0, 7}, // valid octal escape
|
{`"\377" /*`, "comment not terminated", 0, 7}, // valid octal escape
|
||||||
{`"\378"`, "invalid character '8' in octal escape", 0, 4},
|
{`"\378"`, "invalid character '8' in octal escape", 0, 4},
|
||||||
@ -644,8 +644,8 @@ func TestScanErrors(t *testing.T) {
|
|||||||
{`s := "foo\z"`, "unknown escape", 0, 10},
|
{`s := "foo\z"`, "unknown escape", 0, 10},
|
||||||
{`s := "foo\z00\nbar"`, "unknown escape", 0, 10},
|
{`s := "foo\z00\nbar"`, "unknown escape", 0, 10},
|
||||||
{`"\x`, "string not terminated", 0, 0},
|
{`"\x`, "string not terminated", 0, 0},
|
||||||
{`"\x"`, "invalid character '\"' in hex escape", 0, 3},
|
{`"\x"`, "invalid character '\"' in hexadecimal escape", 0, 3},
|
||||||
{`var s string = "\x"`, "invalid character '\"' in hex escape", 0, 18},
|
{`var s string = "\x"`, "invalid character '\"' in hexadecimal escape", 0, 18},
|
||||||
{`return "\Uffffffff"`, "escape is invalid Unicode code point U+FFFFFFFF", 0, 18},
|
{`return "\Uffffffff"`, "escape is invalid Unicode code point U+FFFFFFFF", 0, 18},
|
||||||
|
|
||||||
{"0b.0", "invalid radix point in binary literal", 0, 2},
|
{"0b.0", "invalid radix point in binary literal", 0, 2},
|
||||||
@ -687,6 +687,48 @@ func TestScanErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDirectives(t *testing.T) {
|
||||||
|
for _, src := range []string{
|
||||||
|
"line",
|
||||||
|
"// line",
|
||||||
|
"//line",
|
||||||
|
"//line foo",
|
||||||
|
"//line foo%bar",
|
||||||
|
|
||||||
|
"go",
|
||||||
|
"// go:",
|
||||||
|
"//go:",
|
||||||
|
"//go :foo",
|
||||||
|
"//go:foo",
|
||||||
|
"//go:foo%bar",
|
||||||
|
} {
|
||||||
|
got := ""
|
||||||
|
var s scanner
|
||||||
|
s.init(strings.NewReader(src), func(_, col uint, msg string) {
|
||||||
|
if col != colbase {
|
||||||
|
t.Errorf("%s: got col = %d; want %d", src, col, colbase)
|
||||||
|
}
|
||||||
|
if msg == "" {
|
||||||
|
t.Errorf("%s: handler called with empty msg", src)
|
||||||
|
}
|
||||||
|
got = msg
|
||||||
|
}, directives)
|
||||||
|
|
||||||
|
s.next()
|
||||||
|
if strings.HasPrefix(src, "//line ") || strings.HasPrefix(src, "//go:") {
|
||||||
|
// handler should have been called
|
||||||
|
if got != src {
|
||||||
|
t.Errorf("got %s; want %s", got, src)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// handler should not have been called
|
||||||
|
if got != "" {
|
||||||
|
t.Errorf("got %s for %s", got, src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssue21938(t *testing.T) {
|
func TestIssue21938(t *testing.T) {
|
||||||
s := "/*" + strings.Repeat(" ", 4089) + "*/ .5"
|
s := "/*" + strings.Repeat(" ", 4089) + "*/ .5"
|
||||||
|
|
||||||
|
@ -293,6 +293,11 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
|
|||||||
ast.Walk(f, n.Assign)
|
ast.Walk(f, n.Assign)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
// Don't annotate functions with blank names - they cannot be executed.
|
||||||
|
if n.Name.Name == "_" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
6
src/cmd/dist/test.go
vendored
6
src/cmd/dist/test.go
vendored
@ -98,9 +98,11 @@ func (t *tester) run() {
|
|||||||
os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH")))
|
os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH")))
|
||||||
}
|
}
|
||||||
|
|
||||||
slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
|
cmd := exec.Command("go", "env", "CGO_ENABLED")
|
||||||
|
cmd.Stderr = new(bytes.Buffer)
|
||||||
|
slurp, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("Error running go env CGO_ENABLED: %v", err)
|
fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr)
|
||||||
}
|
}
|
||||||
t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
|
t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
|
||||||
if flag.NArg() > 0 && t.runRxStr != "" {
|
if flag.NArg() > 0 && t.runRxStr != "" {
|
||||||
|
@ -3,11 +3,10 @@ module cmd
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
|
||||||
golang.org/x/arch v0.0.0-20191126211547-368ea8f32fff
|
golang.org/x/arch v0.0.0-20191126211547-368ea8f32fff
|
||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||||
golang.org/x/mod v0.2.0
|
golang.org/x/mod v0.2.0
|
||||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
||||||
golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d
|
golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
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/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12 h1:TgXhFz35pKlZuUz1pNlOKk1UCSXPpuUIc144Wd7SxCA=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3 h1:SRgJV+IoxM5MKyFdlSUeNy6/ycRUF2yBAKdAQswoHUk=
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
golang.org/x/arch v0.0.0-20191126211547-368ea8f32fff h1:k/MrR0lKiCokRu1JUDDAWhWZinfBAOZRzz3LkPOkFMs=
|
golang.org/x/arch v0.0.0-20191126211547-368ea8f32fff h1:k/MrR0lKiCokRu1JUDDAWhWZinfBAOZRzz3LkPOkFMs=
|
||||||
@ -12,12 +13,13 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-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-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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -27,8 +29,8 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d h1:ZQ18He7VORO2x4IEBuwfdp56K+ftEzRjvL0cFuCGCcM=
|
golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca h1:cFQHQhDv9N1vc+64dtXDAyd3exHDGfRTtveOnD0IsLI=
|
||||||
golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -1044,6 +1044,7 @@ func TestGetGitDefaultBranch(t *testing.T) {
|
|||||||
func TestAccidentalGitCheckout(t *testing.T) {
|
func TestAccidentalGitCheckout(t *testing.T) {
|
||||||
testenv.MustHaveExternalNetwork(t)
|
testenv.MustHaveExternalNetwork(t)
|
||||||
testenv.MustHaveExecPath(t, "git")
|
testenv.MustHaveExecPath(t, "git")
|
||||||
|
testenv.MustHaveExecPath(t, "svn")
|
||||||
|
|
||||||
tg := testgo(t)
|
tg := testgo(t)
|
||||||
defer tg.cleanup()
|
defer tg.cleanup()
|
||||||
@ -2208,15 +2209,10 @@ func testBuildmodePIE(t *testing.T, useCgo bool) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
const (
|
|
||||||
IMAGE_FILE_RELOCS_STRIPPED = 0x0001
|
|
||||||
IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
|
|
||||||
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040
|
|
||||||
)
|
|
||||||
if f.Section(".reloc") == nil {
|
if f.Section(".reloc") == nil {
|
||||||
t.Error(".reloc section is not present")
|
t.Error(".reloc section is not present")
|
||||||
}
|
}
|
||||||
if (f.FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0 {
|
if (f.FileHeader.Characteristics & pe.IMAGE_FILE_RELOCS_STRIPPED) != 0 {
|
||||||
t.Error("IMAGE_FILE_RELOCS_STRIPPED flag is set")
|
t.Error("IMAGE_FILE_RELOCS_STRIPPED flag is set")
|
||||||
}
|
}
|
||||||
var dc uint16
|
var dc uint16
|
||||||
@ -2225,13 +2221,13 @@ func testBuildmodePIE(t *testing.T, useCgo bool) {
|
|||||||
dc = oh.DllCharacteristics
|
dc = oh.DllCharacteristics
|
||||||
case *pe.OptionalHeader64:
|
case *pe.OptionalHeader64:
|
||||||
dc = oh.DllCharacteristics
|
dc = oh.DllCharacteristics
|
||||||
if (dc & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == 0 {
|
if (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == 0 {
|
||||||
t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
|
t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
|
t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
|
||||||
}
|
}
|
||||||
if (dc & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 {
|
if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 {
|
||||||
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
|
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -10,10 +10,12 @@ import "net/http"
|
|||||||
// AddCredentials fills in the user's credentials for req, if any.
|
// AddCredentials fills in the user's credentials for req, if any.
|
||||||
// The return value reports whether any matching credentials were found.
|
// The return value reports whether any matching credentials were found.
|
||||||
func AddCredentials(req *http.Request) (added bool) {
|
func AddCredentials(req *http.Request) (added bool) {
|
||||||
|
host := req.URL.Hostname()
|
||||||
|
|
||||||
// TODO(golang.org/issue/26232): Support arbitrary user-provided credentials.
|
// TODO(golang.org/issue/26232): Support arbitrary user-provided credentials.
|
||||||
netrcOnce.Do(readNetrc)
|
netrcOnce.Do(readNetrc)
|
||||||
for _, l := range netrc {
|
for _, l := range netrc {
|
||||||
if l.machine == req.URL.Host {
|
if l.machine == host {
|
||||||
req.SetBasicAuth(l.login, l.password)
|
req.SetBasicAuth(l.login, l.password)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -13,19 +13,19 @@
|
|||||||
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
||||||
// does not require per-inode bookkeeping in the application.
|
// does not require per-inode bookkeeping in the application.
|
||||||
//
|
//
|
||||||
// TODO(bcmills): If we add a build tag for Illumos (see golang.org/issue/20603)
|
// TODO(golang.org/issue/35618): add a syscall.Flock binding for Illumos and
|
||||||
// then Illumos should use F_OFD_SETLK, and the resulting code would be as
|
// switch it over to use filelock_unix.go.
|
||||||
// simple as filelock_unix.go. We will still need the code in this file for AIX
|
|
||||||
// or as long as Oracle Solaris provides only F_SETLK.
|
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type lockType int16
|
type lockType int16
|
||||||
@ -91,7 +91,67 @@ func lock(f File, lt lockType) (err error) {
|
|||||||
wait <- f
|
wait <- f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spurious EDEADLK errors arise on platforms that compute deadlock graphs at
|
||||||
|
// the process, rather than thread, level. Consider processes P and Q, with
|
||||||
|
// threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be
|
||||||
|
// reported as a deadlock on systems that consider only process granularity:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 blocks on file B. (This is erroneously reported as a deadlock.)
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 unblocks and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// These spurious errors were observed in practice on AIX and Solaris in
|
||||||
|
// cmd/go: see https://golang.org/issue/32817.
|
||||||
|
//
|
||||||
|
// We work around this bug by treating EDEADLK as always spurious. If there
|
||||||
|
// really is a lock-ordering bug between the interacting processes, it will
|
||||||
|
// become a livelock instead, but that's not appreciably worse than if we had
|
||||||
|
// a proper flock implementation (which generally does not even attempt to
|
||||||
|
// diagnose deadlocks).
|
||||||
|
//
|
||||||
|
// In the above example, that changes the trace to:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 spuriously fails to lock file B and goes to sleep.
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 wakes up and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// We know that the retry loop will not introduce a *spurious* livelock
|
||||||
|
// because, according to the POSIX specification, EDEADLK is only to be
|
||||||
|
// returned when “the lock is blocked by a lock from another process”.
|
||||||
|
// If that process is blocked on some lock that we are holding, then the
|
||||||
|
// resulting livelock is due to a real deadlock (and would manifest as such
|
||||||
|
// when using, for example, the flock implementation of this package).
|
||||||
|
// If the other process is *not* blocked on some other lock that we are
|
||||||
|
// holding, then it will eventually release the requested lock.
|
||||||
|
|
||||||
|
nextSleep := 1 * time.Millisecond
|
||||||
|
const maxSleep = 500 * time.Millisecond
|
||||||
|
for {
|
||||||
err = setlkw(f.Fd(), lt)
|
err = setlkw(f.Fd(), lt)
|
||||||
|
if err != syscall.EDEADLK {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(nextSleep)
|
||||||
|
|
||||||
|
nextSleep += nextSleep
|
||||||
|
if nextSleep > maxSleep {
|
||||||
|
nextSleep = maxSleep
|
||||||
|
}
|
||||||
|
// Apply 10% jitter to avoid synchronizing collisions when we finally unblock.
|
||||||
|
nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
unlock(f)
|
unlock(f)
|
||||||
|
@ -8,8 +8,11 @@
|
|||||||
package lockedfile_test
|
package lockedfile_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"internal/testenv"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -172,3 +175,98 @@ func TestCanLockExistingFile(t *testing.T) {
|
|||||||
f.Close()
|
f.Close()
|
||||||
wait(t)
|
wait(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSpuriousEDEADLK verifies that the spurious EDEADLK reported in
|
||||||
|
// https://golang.org/issue/32817 no longer occurs.
|
||||||
|
func TestSpuriousEDEADLK(t *testing.T) {
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 blocks on file B. (Spurious EDEADLK occurs here.)
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 unblocks and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
|
||||||
|
testenv.MustHaveExec(t)
|
||||||
|
|
||||||
|
dirVar := t.Name() + "DIR"
|
||||||
|
|
||||||
|
if dir := os.Getenv(dirVar); dir != "" {
|
||||||
|
// Q.3 locks file B.
|
||||||
|
b, err := lockedfile.Edit(filepath.Join(dir, "B"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(dir, "locked"), []byte("ok"), 0666); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
a, err := lockedfile.Edit(filepath.Join(dir, "A"))
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer a.Close()
|
||||||
|
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, remove := mustTempDir(t)
|
||||||
|
defer remove()
|
||||||
|
|
||||||
|
// P.1 locks file A.
|
||||||
|
a, err := lockedfile.Edit(filepath.Join(dir, "A"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(os.Args[0], "-test.run="+t.Name())
|
||||||
|
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", dirVar, dir))
|
||||||
|
|
||||||
|
qDone := make(chan struct{})
|
||||||
|
waitQ := mustBlock(t, "Edit A and B in subprocess", func() {
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v:\n%s", err, out)
|
||||||
|
}
|
||||||
|
close(qDone)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait until process Q has either failed or locked file B.
|
||||||
|
// Otherwise, P.2 might not block on file B as intended.
|
||||||
|
locked:
|
||||||
|
for {
|
||||||
|
if _, err := os.Stat(filepath.Join(dir, "locked")); !os.IsNotExist(err) {
|
||||||
|
break locked
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-qDone:
|
||||||
|
break locked
|
||||||
|
case <-time.After(1 * time.Millisecond):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitP2 := mustBlock(t, "Edit B", func() {
|
||||||
|
// P.2 blocks on file B. (Spurious EDEADLK occurs here.)
|
||||||
|
b, err := lockedfile.Edit(filepath.Join(dir, "B"))
|
||||||
|
// P.2 unblocks and locks file B.
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
b.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
a.Close()
|
||||||
|
|
||||||
|
waitQ(t)
|
||||||
|
waitP2(t)
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ package modcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -67,12 +68,10 @@ func verifyMod(mod module.Version) bool {
|
|||||||
_, zipErr = os.Stat(zip)
|
_, zipErr = os.Stat(zip)
|
||||||
}
|
}
|
||||||
dir, dirErr := modfetch.DownloadDir(mod)
|
dir, dirErr := modfetch.DownloadDir(mod)
|
||||||
if dirErr == nil {
|
|
||||||
_, dirErr = os.Stat(dir)
|
|
||||||
}
|
|
||||||
data, err := ioutil.ReadFile(zip + "hash")
|
data, err := ioutil.ReadFile(zip + "hash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) {
|
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) &&
|
||||||
|
dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
||||||
// Nothing downloaded yet. Nothing to verify.
|
// Nothing downloaded yet. Nothing to verify.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -81,7 +80,7 @@ func verifyMod(mod module.Version) bool {
|
|||||||
}
|
}
|
||||||
h := string(bytes.TrimSpace(data))
|
h := string(bytes.TrimSpace(data))
|
||||||
|
|
||||||
if zipErr != nil && os.IsNotExist(zipErr) {
|
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
||||||
@ -93,7 +92,7 @@ func verifyMod(mod module.Version) bool {
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dirErr != nil && os.IsNotExist(dirErr) {
|
if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
||||||
|
@ -7,6 +7,7 @@ package modfetch
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -56,8 +57,11 @@ func CachePath(m module.Version, suffix string) (string, error) {
|
|||||||
return filepath.Join(dir, encVer+"."+suffix), nil
|
return filepath.Join(dir, encVer+"."+suffix), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadDir returns the directory to which m should be downloaded.
|
// DownloadDir returns the directory to which m should have been downloaded.
|
||||||
// Note that the directory may not yet exist.
|
// An error will be returned if the module path or version cannot be escaped.
|
||||||
|
// An error satisfying errors.Is(err, os.ErrNotExist) will be returned
|
||||||
|
// 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) {
|
func DownloadDir(m module.Version) (string, error) {
|
||||||
if PkgMod == "" {
|
if PkgMod == "" {
|
||||||
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
|
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
|
||||||
@ -76,9 +80,39 @@ func DownloadDir(m module.Version) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(PkgMod, enc+"@"+encVer), nil
|
|
||||||
|
dir := filepath.Join(PkgMod, enc+"@"+encVer)
|
||||||
|
if fi, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
return dir, err
|
||||||
|
} else if err != nil {
|
||||||
|
return dir, &DownloadDirPartialError{dir, err}
|
||||||
|
} else if !fi.IsDir() {
|
||||||
|
return dir, &DownloadDirPartialError{dir, errors.New("not a directory")}
|
||||||
|
}
|
||||||
|
partialPath, err := CachePath(m, "partial")
|
||||||
|
if err != nil {
|
||||||
|
return dir, err
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(partialPath); err == nil {
|
||||||
|
return dir, &DownloadDirPartialError{dir, errors.New("not completely extracted")}
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return dir, err
|
||||||
|
}
|
||||||
|
return dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DownloadDirPartialError is returned by DownloadDir if a module directory
|
||||||
|
// exists but was not completely populated.
|
||||||
|
//
|
||||||
|
// DownloadDirPartialError is equivalent to os.ErrNotExist.
|
||||||
|
type DownloadDirPartialError struct {
|
||||||
|
Dir string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) }
|
||||||
|
func (e *DownloadDirPartialError) Is(err error) bool { return err == os.ErrNotExist }
|
||||||
|
|
||||||
// lockVersion locks a file within the module cache that guards the downloading
|
// lockVersion locks a file within the module cache that guards the downloading
|
||||||
// and extraction of the zipfile for the given module version.
|
// and extraction of the zipfile for the given module version.
|
||||||
func lockVersion(mod module.Version) (unlock func(), err error) {
|
func lockVersion(mod module.Version) (unlock func(), err error) {
|
||||||
|
@ -563,7 +563,7 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !t.Equal(info.Time.Truncate(time.Second)) {
|
if !t.Equal(info.Time.Truncate(time.Second)) {
|
||||||
return fmt.Errorf("does not match version-control timestamp (%s)", info.Time.UTC().Format(time.RFC3339))
|
return fmt.Errorf("does not match version-control timestamp (expected %s)", info.Time.UTC().Format(pseudoVersionTimestampFormat))
|
||||||
}
|
}
|
||||||
|
|
||||||
tagPrefix := ""
|
tagPrefix := ""
|
||||||
|
@ -46,24 +46,26 @@ func Download(mod module.Version) (dir string, err error) {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
c := downloadCache.Do(mod, func() interface{} {
|
c := downloadCache.Do(mod, func() interface{} {
|
||||||
dir, err := DownloadDir(mod)
|
dir, err := download(mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cached{"", err}
|
return cached{"", err}
|
||||||
}
|
}
|
||||||
if err := download(mod, dir); err != nil {
|
|
||||||
return cached{"", err}
|
|
||||||
}
|
|
||||||
checkMod(mod)
|
checkMod(mod)
|
||||||
return cached{dir, nil}
|
return cached{dir, nil}
|
||||||
}).(cached)
|
}).(cached)
|
||||||
return c.dir, c.err
|
return c.dir, c.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func download(mod module.Version, dir string) (err error) {
|
func download(mod module.Version) (dir string, err error) {
|
||||||
// If the directory exists, the module has already been extracted.
|
// If the directory exists, and no .partial file exists, the module has
|
||||||
fi, err := os.Stat(dir)
|
// already been completely extracted. .partial files may be created when a
|
||||||
if err == nil && fi.IsDir() {
|
// module zip directory is extracted in place instead of being extracted to a
|
||||||
return nil
|
// temporary directory and renamed.
|
||||||
|
dir, err = DownloadDir(mod)
|
||||||
|
if err == nil {
|
||||||
|
return dir, nil
|
||||||
|
} else if dir == "" || !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// To avoid cluttering the cache with extraneous files,
|
// To avoid cluttering the cache with extraneous files,
|
||||||
@ -71,22 +73,24 @@ func download(mod module.Version, dir string) (err error) {
|
|||||||
// Invoke DownloadZip before locking the file.
|
// Invoke DownloadZip before locking the file.
|
||||||
zipfile, err := DownloadZip(mod)
|
zipfile, err := DownloadZip(mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock, err := lockVersion(mod)
|
unlock, err := lockVersion(mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
// Check whether the directory was populated while we were waiting on the lock.
|
// Check whether the directory was populated while we were waiting on the lock.
|
||||||
fi, err = os.Stat(dir)
|
_, dirErr := DownloadDir(mod)
|
||||||
if err == nil && fi.IsDir() {
|
if dirErr == nil {
|
||||||
return nil
|
return dir, nil
|
||||||
}
|
}
|
||||||
|
_, dirExists := dirErr.(*DownloadDirPartialError)
|
||||||
|
|
||||||
// Clean up any remaining temporary directories from previous runs.
|
// Clean up any remaining temporary directories from previous runs, as well
|
||||||
|
// as partially extracted diectories created by future versions of cmd/go.
|
||||||
// This is only safe to do because the lock file ensures that their writers
|
// This is only safe to do because the lock file ensures that their writers
|
||||||
// are no longer active.
|
// are no longer active.
|
||||||
parentDir := filepath.Dir(dir)
|
parentDir := filepath.Dir(dir)
|
||||||
@ -96,35 +100,75 @@ func download(mod module.Version, dir string) (err error) {
|
|||||||
RemoveAll(path) // best effort
|
RemoveAll(path) // best effort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if dirExists {
|
||||||
// Extract the zip file to a temporary directory, then rename it to the
|
if err := RemoveAll(dir); err != nil {
|
||||||
// final path. That way, we can use the existence of the source directory to
|
return "", err
|
||||||
// signal that it has been extracted successfully, and if someone deletes
|
|
||||||
// the entire directory (e.g. as an attempt to prune out file corruption)
|
|
||||||
// the module cache will still be left in a recoverable state.
|
|
||||||
// We retry failed renames using robustio.Rename on Windows. Programs that
|
|
||||||
// open files in the temporary directory (antivirus, search indexers, etc.)
|
|
||||||
// can cause os.Rename to fail with ERROR_ACCESS_DENIED.
|
|
||||||
if err := os.MkdirAll(parentDir, 0777); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partialPath, err := CachePath(mod, "partial")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := os.Remove(partialPath); err != nil && !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the module zip directory.
|
||||||
|
//
|
||||||
|
// By default, we extract to a temporary directory, then atomically rename to
|
||||||
|
// its final location. We use the existence of the source directory to signal
|
||||||
|
// that it has been extracted successfully (see DownloadDir). If someone
|
||||||
|
// deletes the entire directory (e.g., as an attempt to prune out file
|
||||||
|
// corruption), the module cache will still be left in a recoverable
|
||||||
|
// state.
|
||||||
|
//
|
||||||
|
// Unfortunately, os.Rename may fail with ERROR_ACCESS_DENIED on Windows if
|
||||||
|
// another process opens files in the temporary directory. This is partially
|
||||||
|
// mitigated by using robustio.Rename, which retries os.Rename for a short
|
||||||
|
// time.
|
||||||
|
//
|
||||||
|
// To avoid this error completely, if unzipInPlace is set, we instead create a
|
||||||
|
// .partial file (indicating the directory isn't fully extracted), then we
|
||||||
|
// extract the directory at its final location, then we delete the .partial
|
||||||
|
// file. This is not the default behavior because older versions of Go may
|
||||||
|
// simply stat the directory to check whether it exists without looking for a
|
||||||
|
// .partial file. If multiple versions run concurrently, the older version may
|
||||||
|
// assume a partially extracted directory is complete.
|
||||||
|
// TODO(golang.org/issue/36568): when these older versions are no longer
|
||||||
|
// supported, remove the old default behavior and the unzipInPlace flag.
|
||||||
|
if err := os.MkdirAll(parentDir, 0777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if unzipInPlace {
|
||||||
|
if err := ioutil.WriteFile(partialPath, nil, 0666); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := modzip.Unzip(dir, mod, zipfile); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "-> %s\n", err)
|
||||||
|
if rmErr := RemoveAll(dir); rmErr == nil {
|
||||||
|
os.Remove(partialPath)
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := os.Remove(partialPath); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
|
tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
RemoveAll(tmpDir)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
|
if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "-> %s\n", err)
|
fmt.Fprintf(os.Stderr, "-> %s\n", err)
|
||||||
return err
|
RemoveAll(tmpDir)
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := robustio.Rename(tmpDir, dir); err != nil {
|
if err := robustio.Rename(tmpDir, dir); err != nil {
|
||||||
return err
|
RemoveAll(tmpDir)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.ModCacheRW {
|
if !cfg.ModCacheRW {
|
||||||
@ -132,7 +176,18 @@ func download(mod module.Version, dir string) (err error) {
|
|||||||
// os.Rename was observed to fail for read-only directories on macOS.
|
// os.Rename was observed to fail for read-only directories on macOS.
|
||||||
makeDirsReadOnly(dir)
|
makeDirsReadOnly(dir)
|
||||||
}
|
}
|
||||||
return nil
|
return dir, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var unzipInPlace bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, f := range strings.Split(os.Getenv("GODEBUG"), ",") {
|
||||||
|
if f == "modcacheunzipinplace=1" {
|
||||||
|
unzipInPlace = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadZipCache par.Cache
|
var downloadZipCache par.Cache
|
||||||
@ -306,7 +361,7 @@ func RemoveAll(dir string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return os.RemoveAll(dir)
|
return robustio.RemoveAll(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
var GoSumFile string // path to go.sum; set by package modload
|
var GoSumFile string // path to go.sum; set by package modload
|
||||||
|
@ -48,6 +48,8 @@ import (
|
|||||||
|
|
||||||
var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`)
|
var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`)
|
||||||
|
|
||||||
|
const pseudoVersionTimestampFormat = "20060102150405"
|
||||||
|
|
||||||
// PseudoVersion returns a pseudo-version for the given major version ("v1")
|
// PseudoVersion returns a pseudo-version for the given major version ("v1")
|
||||||
// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time,
|
// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time,
|
||||||
// and revision identifier (usually a 12-byte commit hash prefix).
|
// and revision identifier (usually a 12-byte commit hash prefix).
|
||||||
@ -55,7 +57,7 @@ func PseudoVersion(major, older string, t time.Time, rev string) string {
|
|||||||
if major == "" {
|
if major == "" {
|
||||||
major = "v0"
|
major = "v0"
|
||||||
}
|
}
|
||||||
segment := fmt.Sprintf("%s-%s", t.UTC().Format("20060102150405"), rev)
|
segment := fmt.Sprintf("%s-%s", t.UTC().Format(pseudoVersionTimestampFormat), rev)
|
||||||
build := semver.Build(older)
|
build := semver.Build(older)
|
||||||
older = semver.Canonical(older)
|
older = semver.Canonical(older)
|
||||||
if older == "" {
|
if older == "" {
|
||||||
|
@ -148,12 +148,10 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
|
|||||||
}
|
}
|
||||||
dir, err := modfetch.DownloadDir(mod)
|
dir, err := modfetch.DownloadDir(mod)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if info, err := os.Stat(dir); err == nil && info.IsDir() {
|
|
||||||
m.Dir = dir
|
m.Dir = dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !fromBuildList {
|
if !fromBuildList {
|
||||||
completeFromModCache(info) // Will set m.Error in vendor mode.
|
completeFromModCache(info) // Will set m.Error in vendor mode.
|
||||||
|
@ -59,27 +59,6 @@ var (
|
|||||||
allowMissingModuleImports bool
|
allowMissingModuleImports bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var modFile *modfile.File
|
|
||||||
|
|
||||||
// A modFileIndex is an index of data corresponding to a modFile
|
|
||||||
// at a specific point in time.
|
|
||||||
type modFileIndex struct {
|
|
||||||
data []byte
|
|
||||||
dataNeedsFix bool // true if fixVersion applied a change while parsing data
|
|
||||||
module module.Version
|
|
||||||
goVersion string
|
|
||||||
require map[module.Version]requireMeta
|
|
||||||
replace map[module.Version]module.Version
|
|
||||||
exclude map[module.Version]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// index is the index of the go.mod file as of when it was last read or written.
|
|
||||||
var index *modFileIndex
|
|
||||||
|
|
||||||
type requireMeta struct {
|
|
||||||
indirect bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModFile returns the parsed go.mod file.
|
// ModFile returns the parsed go.mod file.
|
||||||
//
|
//
|
||||||
// Note that after calling ImportPaths or LoadBuildList,
|
// Note that after calling ImportPaths or LoadBuildList,
|
||||||
@ -555,101 +534,6 @@ func setDefaultBuildMod() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkVendorConsistency verifies that the vendor/modules.txt file matches (if
|
|
||||||
// go 1.14) or at least does not contradict (go 1.13 or earlier) the
|
|
||||||
// requirements and replacements listed in the main module's go.mod file.
|
|
||||||
func checkVendorConsistency() {
|
|
||||||
readVendorList()
|
|
||||||
|
|
||||||
pre114 := false
|
|
||||||
if modFile.Go == nil || semver.Compare("v"+modFile.Go.Version, "v1.14") < 0 {
|
|
||||||
// Go versions before 1.14 did not include enough information in
|
|
||||||
// vendor/modules.txt to check for consistency.
|
|
||||||
// If we know that we're on an earlier version, relax the consistency check.
|
|
||||||
pre114 = true
|
|
||||||
}
|
|
||||||
|
|
||||||
vendErrors := new(strings.Builder)
|
|
||||||
vendErrorf := func(mod module.Version, format string, args ...interface{}) {
|
|
||||||
detail := fmt.Sprintf(format, args...)
|
|
||||||
if mod.Version == "" {
|
|
||||||
fmt.Fprintf(vendErrors, "\n\t%s: %s", mod.Path, detail)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(vendErrors, "\n\t%s@%s: %s", mod.Path, mod.Version, detail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range modFile.Require {
|
|
||||||
if !vendorMeta[r.Mod].Explicit {
|
|
||||||
if pre114 {
|
|
||||||
// Before 1.14, modules.txt did not indicate whether modules were listed
|
|
||||||
// explicitly in the main module's go.mod file.
|
|
||||||
// However, we can at least detect a version mismatch if packages were
|
|
||||||
// vendored from a non-matching version.
|
|
||||||
if vv, ok := vendorVersion[r.Mod.Path]; ok && vv != r.Mod.Version {
|
|
||||||
vendErrorf(r.Mod, fmt.Sprintf("is explicitly required in go.mod, but vendor/modules.txt indicates %s@%s", r.Mod.Path, vv))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vendErrorf(r.Mod, "is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe := func(m module.Version) string {
|
|
||||||
if m.Version == "" {
|
|
||||||
return m.Path
|
|
||||||
}
|
|
||||||
return m.Path + "@" + m.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to verify *all* replacements that occur in modfile: even if they
|
|
||||||
// don't directly apply to any module in the vendor list, the replacement
|
|
||||||
// go.mod file can affect the selected versions of other (transitive)
|
|
||||||
// dependencies
|
|
||||||
for _, r := range modFile.Replace {
|
|
||||||
vr := vendorMeta[r.Old].Replacement
|
|
||||||
if vr == (module.Version{}) {
|
|
||||||
if pre114 && (r.Old.Version == "" || vendorVersion[r.Old.Path] != r.Old.Version) {
|
|
||||||
// Before 1.14, modules.txt omitted wildcard replacements and
|
|
||||||
// replacements for modules that did not have any packages to vendor.
|
|
||||||
} else {
|
|
||||||
vendErrorf(r.Old, "is replaced in go.mod, but not marked as replaced in vendor/modules.txt")
|
|
||||||
}
|
|
||||||
} else if vr != r.New {
|
|
||||||
vendErrorf(r.Old, "is replaced by %s in go.mod, but marked as replaced by %s in vendor/modules.txt", describe(r.New), describe(vr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mod := range vendorList {
|
|
||||||
meta := vendorMeta[mod]
|
|
||||||
if meta.Explicit {
|
|
||||||
if _, inGoMod := index.require[mod]; !inGoMod {
|
|
||||||
vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in go.mod")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mod := range vendorReplaced {
|
|
||||||
r := Replacement(mod)
|
|
||||||
if r == (module.Version{}) {
|
|
||||||
vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if meta := vendorMeta[mod]; r != meta.Replacement {
|
|
||||||
vendErrorf(mod, "is marked as replaced by %s in vendor/modules.txt, but replaced by %s in go.mod", describe(meta.Replacement), describe(r))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if vendErrors.Len() > 0 {
|
|
||||||
base.Fatalf("go: inconsistent vendoring in %s:%s\n\nrun 'go mod vendor' to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory", modRoot, vendErrors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
|
|
||||||
func Allowed(m module.Version) bool {
|
|
||||||
return index == nil || !index.exclude[m]
|
|
||||||
}
|
|
||||||
|
|
||||||
func legacyModInit() {
|
func legacyModInit() {
|
||||||
if modFile == nil {
|
if modFile == nil {
|
||||||
path, err := findModulePath(modRoot)
|
path, err := findModulePath(modRoot)
|
||||||
@ -983,113 +867,3 @@ func WriteGoMod() {
|
|||||||
base.Fatalf("go: updating go.mod: %v", err)
|
base.Fatalf("go: updating go.mod: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexModFile rebuilds the index of modFile.
|
|
||||||
// If modFile has been changed since it was first read,
|
|
||||||
// modFile.Cleanup must be called before indexModFile.
|
|
||||||
func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
|
|
||||||
i := new(modFileIndex)
|
|
||||||
i.data = data
|
|
||||||
i.dataNeedsFix = needsFix
|
|
||||||
|
|
||||||
i.module = module.Version{}
|
|
||||||
if modFile.Module != nil {
|
|
||||||
i.module = modFile.Module.Mod
|
|
||||||
}
|
|
||||||
|
|
||||||
i.goVersion = ""
|
|
||||||
if modFile.Go != nil {
|
|
||||||
i.goVersion = modFile.Go.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
|
||||||
for _, r := range modFile.Require {
|
|
||||||
i.require[r.Mod] = requireMeta{indirect: r.Indirect}
|
|
||||||
}
|
|
||||||
|
|
||||||
i.replace = make(map[module.Version]module.Version, len(modFile.Replace))
|
|
||||||
for _, r := range modFile.Replace {
|
|
||||||
if prev, dup := i.replace[r.Old]; dup && prev != r.New {
|
|
||||||
base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
|
|
||||||
}
|
|
||||||
i.replace[r.Old] = r.New
|
|
||||||
}
|
|
||||||
|
|
||||||
i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
|
|
||||||
for _, x := range modFile.Exclude {
|
|
||||||
i.exclude[x.Mod] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// modFileIsDirty reports whether the go.mod file differs meaningfully
|
|
||||||
// from what was indexed.
|
|
||||||
// If modFile has been changed (even cosmetically) since it was first read,
|
|
||||||
// modFile.Cleanup must be called before modFileIsDirty.
|
|
||||||
func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
|
|
||||||
if i == nil {
|
|
||||||
return modFile != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if i.dataNeedsFix {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if modFile.Module == nil {
|
|
||||||
if i.module != (module.Version{}) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if modFile.Module.Mod != i.module {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if modFile.Go == nil {
|
|
||||||
if i.goVersion != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if modFile.Go.Version != i.goVersion {
|
|
||||||
if i.goVersion == "" && cfg.BuildMod == "readonly" {
|
|
||||||
// go.mod files did not always require a 'go' version, so do not error out
|
|
||||||
// if one is missing — we may be inside an older module in the module
|
|
||||||
// cache, and should bias toward providing useful behavior.
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(modFile.Require) != len(i.require) ||
|
|
||||||
len(modFile.Replace) != len(i.replace) ||
|
|
||||||
len(modFile.Exclude) != len(i.exclude) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range modFile.Require {
|
|
||||||
if meta, ok := i.require[r.Mod]; !ok {
|
|
||||||
return true
|
|
||||||
} else if r.Indirect != meta.indirect {
|
|
||||||
if cfg.BuildMod == "readonly" {
|
|
||||||
// The module's requirements are consistent; only the "// indirect"
|
|
||||||
// comments that are wrong. But those are only guaranteed to be accurate
|
|
||||||
// after a "go mod tidy" — it's a good idea to run those before
|
|
||||||
// committing a change, but it's certainly not mandatory.
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range modFile.Replace {
|
|
||||||
if r.New != i.replace[r.Old] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, x := range modFile.Exclude {
|
|
||||||
if !i.exclude[x.Mod] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -9,14 +9,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
@ -27,9 +25,7 @@ import (
|
|||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
|
|
||||||
"golang.org/x/mod/modfile"
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
"golang.org/x/mod/semver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// buildList is the list of modules to use for building packages.
|
// buildList is the list of modules to use for building packages.
|
||||||
@ -1033,354 +1029,3 @@ func WhyDepth(path string) int {
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replacement returns the replacement for mod, if any, from go.mod.
|
|
||||||
// If there is no replacement for mod, Replacement returns
|
|
||||||
// a module.Version with Path == "".
|
|
||||||
func Replacement(mod module.Version) module.Version {
|
|
||||||
if index != nil {
|
|
||||||
if r, ok := index.replace[mod]; ok {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return module.Version{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mvsReqs implements mvs.Reqs for module semantic versions,
|
|
||||||
// with any exclusions or replacements applied internally.
|
|
||||||
type mvsReqs struct {
|
|
||||||
buildList []module.Version
|
|
||||||
cache par.Cache
|
|
||||||
versions sync.Map
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reqs returns the current module requirement graph.
|
|
||||||
// Future calls to SetBuildList do not affect the operation
|
|
||||||
// of the returned Reqs.
|
|
||||||
func Reqs() mvs.Reqs {
|
|
||||||
r := &mvsReqs{
|
|
||||||
buildList: buildList,
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
|
||||||
type cached struct {
|
|
||||||
list []module.Version
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
c := r.cache.Do(mod, func() interface{} {
|
|
||||||
list, err := r.required(mod)
|
|
||||||
if err != nil {
|
|
||||||
return cached{nil, err}
|
|
||||||
}
|
|
||||||
for i, mv := range list {
|
|
||||||
if index != nil {
|
|
||||||
for index.exclude[mv] {
|
|
||||||
mv1, err := r.next(mv)
|
|
||||||
if err != nil {
|
|
||||||
return cached{nil, err}
|
|
||||||
}
|
|
||||||
if mv1.Version == "none" {
|
|
||||||
return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)}
|
|
||||||
}
|
|
||||||
mv = mv1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list[i] = mv
|
|
||||||
}
|
|
||||||
|
|
||||||
return cached{list, nil}
|
|
||||||
}).(cached)
|
|
||||||
|
|
||||||
return c.list, c.err
|
|
||||||
}
|
|
||||||
|
|
||||||
var vendorOnce sync.Once
|
|
||||||
|
|
||||||
type vendorMetadata struct {
|
|
||||||
Explicit bool
|
|
||||||
Replacement module.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
vendorList []module.Version // modules that contribute packages to the build, in order of appearance
|
|
||||||
vendorReplaced []module.Version // all replaced modules; may or may not also contribute packages
|
|
||||||
vendorVersion map[string]string // module path → selected version (if known)
|
|
||||||
vendorPkgModule map[string]module.Version // package → containing module
|
|
||||||
vendorMeta map[module.Version]vendorMetadata
|
|
||||||
)
|
|
||||||
|
|
||||||
// readVendorList reads the list of vendored modules from vendor/modules.txt.
|
|
||||||
func readVendorList() {
|
|
||||||
vendorOnce.Do(func() {
|
|
||||||
vendorList = nil
|
|
||||||
vendorPkgModule = make(map[string]module.Version)
|
|
||||||
vendorVersion = make(map[string]string)
|
|
||||||
vendorMeta = make(map[module.Version]vendorMetadata)
|
|
||||||
data, err := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
base.Fatalf("go: %s", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var mod module.Version
|
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
|
||||||
if strings.HasPrefix(line, "# ") {
|
|
||||||
f := strings.Fields(line)
|
|
||||||
|
|
||||||
if len(f) < 3 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if semver.IsValid(f[2]) {
|
|
||||||
// A module, but we don't yet know whether it is in the build list or
|
|
||||||
// only included to indicate a replacement.
|
|
||||||
mod = module.Version{Path: f[1], Version: f[2]}
|
|
||||||
f = f[3:]
|
|
||||||
} else if f[2] == "=>" {
|
|
||||||
// A wildcard replacement found in the main module's go.mod file.
|
|
||||||
mod = module.Version{Path: f[1]}
|
|
||||||
f = f[2:]
|
|
||||||
} else {
|
|
||||||
// Not a version or a wildcard replacement.
|
|
||||||
// We don't know how to interpret this module line, so ignore it.
|
|
||||||
mod = module.Version{}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(f) >= 2 && f[0] == "=>" {
|
|
||||||
meta := vendorMeta[mod]
|
|
||||||
if len(f) == 2 {
|
|
||||||
// File replacement.
|
|
||||||
meta.Replacement = module.Version{Path: f[1]}
|
|
||||||
vendorReplaced = append(vendorReplaced, mod)
|
|
||||||
} else if len(f) == 3 && semver.IsValid(f[2]) {
|
|
||||||
// Path and version replacement.
|
|
||||||
meta.Replacement = module.Version{Path: f[1], Version: f[2]}
|
|
||||||
vendorReplaced = append(vendorReplaced, mod)
|
|
||||||
} else {
|
|
||||||
// We don't understand this replacement. Ignore it.
|
|
||||||
}
|
|
||||||
vendorMeta[mod] = meta
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not a module line. Must be a package within a module or a metadata
|
|
||||||
// directive, either of which requires a preceding module line.
|
|
||||||
if mod.Path == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, "## ") {
|
|
||||||
// Metadata. Take the union of annotations across multiple lines, if present.
|
|
||||||
meta := vendorMeta[mod]
|
|
||||||
for _, entry := range strings.Split(strings.TrimPrefix(line, "## "), ";") {
|
|
||||||
entry = strings.TrimSpace(entry)
|
|
||||||
if entry == "explicit" {
|
|
||||||
meta.Explicit = true
|
|
||||||
}
|
|
||||||
// All other tokens are reserved for future use.
|
|
||||||
}
|
|
||||||
vendorMeta[mod] = meta
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if f := strings.Fields(line); len(f) == 1 && module.CheckImportPath(f[0]) == nil {
|
|
||||||
// A package within the current module.
|
|
||||||
vendorPkgModule[f[0]] = mod
|
|
||||||
|
|
||||||
// Since this module provides a package for the build, we know that it
|
|
||||||
// is in the build list and is the selected version of its path.
|
|
||||||
// If this information is new, record it.
|
|
||||||
if v, ok := vendorVersion[mod.Path]; !ok || semver.Compare(v, mod.Version) < 0 {
|
|
||||||
vendorList = append(vendorList, mod)
|
|
||||||
vendorVersion[mod.Path] = mod.Version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
|
|
||||||
list := make([]module.Version, 0, len(f.Require))
|
|
||||||
for _, r := range f.Require {
|
|
||||||
list = append(list, r.Mod)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// required returns a unique copy of the requirements of mod.
|
|
||||||
func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
|
|
||||||
if mod == Target {
|
|
||||||
if modFile != nil && modFile.Go != nil {
|
|
||||||
r.versions.LoadOrStore(mod, modFile.Go.Version)
|
|
||||||
}
|
|
||||||
return append([]module.Version(nil), r.buildList[1:]...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.BuildMod == "vendor" {
|
|
||||||
// For every module other than the target,
|
|
||||||
// return the full list of modules from modules.txt.
|
|
||||||
readVendorList()
|
|
||||||
return append([]module.Version(nil), vendorList...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
origPath := mod.Path
|
|
||||||
if repl := Replacement(mod); repl.Path != "" {
|
|
||||||
if repl.Version == "" {
|
|
||||||
// TODO: need to slip the new version into the tags list etc.
|
|
||||||
dir := repl.Path
|
|
||||||
if !filepath.IsAbs(dir) {
|
|
||||||
dir = filepath.Join(ModRoot(), dir)
|
|
||||||
}
|
|
||||||
gomod := filepath.Join(dir, "go.mod")
|
|
||||||
data, err := ioutil.ReadFile(gomod)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
|
||||||
}
|
|
||||||
f, err := modfile.ParseLax(gomod, data, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
|
||||||
}
|
|
||||||
if f.Go != nil {
|
|
||||||
r.versions.LoadOrStore(mod, f.Go.Version)
|
|
||||||
}
|
|
||||||
return r.modFileToList(f), nil
|
|
||||||
}
|
|
||||||
mod = repl
|
|
||||||
}
|
|
||||||
|
|
||||||
if mod.Version == "none" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !semver.IsValid(mod.Version) {
|
|
||||||
// Disallow the broader queries supported by fetch.Lookup.
|
|
||||||
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := modfetch.GoMod(mod.Path, mod.Version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f, err := modfile.ParseLax("go.mod", data, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, module.VersionError(mod, fmt.Errorf("parsing go.mod: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Module == nil {
|
|
||||||
return nil, module.VersionError(mod, errors.New("parsing go.mod: missing module line"))
|
|
||||||
}
|
|
||||||
if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
|
|
||||||
return nil, module.VersionError(mod, fmt.Errorf(`parsing go.mod:
|
|
||||||
module declares its path as: %s
|
|
||||||
but was required as: %s`, mpath, mod.Path))
|
|
||||||
}
|
|
||||||
if f.Go != nil {
|
|
||||||
r.versions.LoadOrStore(mod, f.Go.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.modFileToList(f), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*mvsReqs) Max(v1, v2 string) string {
|
|
||||||
if v1 != "" && semver.Compare(v1, v2) == -1 {
|
|
||||||
return v2
|
|
||||||
}
|
|
||||||
return v1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade is a no-op, here to implement mvs.Reqs.
|
|
||||||
// The upgrade logic for go get -u is in ../modget/get.go.
|
|
||||||
func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func versions(path string) ([]string, error) {
|
|
||||||
// Note: modfetch.Lookup and repo.Versions are cached,
|
|
||||||
// so there's no need for us to add extra caching here.
|
|
||||||
var versions []string
|
|
||||||
err := modfetch.TryProxies(func(proxy string) error {
|
|
||||||
repo, err := modfetch.Lookup(proxy, path)
|
|
||||||
if err == nil {
|
|
||||||
versions, err = repo.Versions("")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return versions, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Previous returns the tagged version of m.Path immediately prior to
|
|
||||||
// m.Version, or version "none" if no prior version is tagged.
|
|
||||||
func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
|
||||||
list, err := versions(m.Path)
|
|
||||||
if err != nil {
|
|
||||||
return module.Version{}, err
|
|
||||||
}
|
|
||||||
i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
|
|
||||||
if i > 0 {
|
|
||||||
return module.Version{Path: m.Path, Version: list[i-1]}, nil
|
|
||||||
}
|
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns the next version of m.Path after m.Version.
|
|
||||||
// It is only used by the exclusion processing in the Required method,
|
|
||||||
// not called directly by MVS.
|
|
||||||
func (*mvsReqs) next(m module.Version) (module.Version, error) {
|
|
||||||
list, err := versions(m.Path)
|
|
||||||
if err != nil {
|
|
||||||
return module.Version{}, err
|
|
||||||
}
|
|
||||||
i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
|
|
||||||
if i < len(list) {
|
|
||||||
return module.Version{Path: m.Path, Version: list[i]}, nil
|
|
||||||
}
|
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch downloads the given module (or its replacement)
|
|
||||||
// and returns its location.
|
|
||||||
//
|
|
||||||
// The isLocal return value reports whether the replacement,
|
|
||||||
// if any, is local to the filesystem.
|
|
||||||
func fetch(mod module.Version) (dir string, isLocal bool, err error) {
|
|
||||||
if mod == Target {
|
|
||||||
return ModRoot(), true, nil
|
|
||||||
}
|
|
||||||
if r := Replacement(mod); r.Path != "" {
|
|
||||||
if r.Version == "" {
|
|
||||||
dir = r.Path
|
|
||||||
if !filepath.IsAbs(dir) {
|
|
||||||
dir = filepath.Join(ModRoot(), dir)
|
|
||||||
}
|
|
||||||
// Ensure that the replacement directory actually exists:
|
|
||||||
// dirInModule does not report errors for missing modules,
|
|
||||||
// so if we don't report the error now, later failures will be
|
|
||||||
// very mysterious.
|
|
||||||
if _, err := os.Stat(dir); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// Semantically the module version itself “exists” — we just don't
|
|
||||||
// have its source code. Remove the equivalence to os.ErrNotExist,
|
|
||||||
// and make the message more concise while we're at it.
|
|
||||||
err = fmt.Errorf("replacement directory %s does not exist", r.Path)
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("replacement directory %s: %w", r.Path, err)
|
|
||||||
}
|
|
||||||
return dir, true, module.VersionError(mod, err)
|
|
||||||
}
|
|
||||||
return dir, true, nil
|
|
||||||
}
|
|
||||||
mod = r
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err = modfetch.Download(mod)
|
|
||||||
return dir, false, err
|
|
||||||
}
|
|
||||||
|
164
src/cmd/go/internal/modload/modfile.go
Normal file
164
src/cmd/go/internal/modload/modfile.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// 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 modload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/cfg"
|
||||||
|
|
||||||
|
"golang.org/x/mod/modfile"
|
||||||
|
"golang.org/x/mod/module"
|
||||||
|
)
|
||||||
|
|
||||||
|
var modFile *modfile.File
|
||||||
|
|
||||||
|
// A modFileIndex is an index of data corresponding to a modFile
|
||||||
|
// at a specific point in time.
|
||||||
|
type modFileIndex struct {
|
||||||
|
data []byte
|
||||||
|
dataNeedsFix bool // true if fixVersion applied a change while parsing data
|
||||||
|
module module.Version
|
||||||
|
goVersion string
|
||||||
|
require map[module.Version]requireMeta
|
||||||
|
replace map[module.Version]module.Version
|
||||||
|
exclude map[module.Version]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// index is the index of the go.mod file as of when it was last read or written.
|
||||||
|
var index *modFileIndex
|
||||||
|
|
||||||
|
type requireMeta struct {
|
||||||
|
indirect bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
|
||||||
|
func Allowed(m module.Version) bool {
|
||||||
|
return index == nil || !index.exclude[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replacement returns the replacement for mod, if any, from go.mod.
|
||||||
|
// If there is no replacement for mod, Replacement returns
|
||||||
|
// a module.Version with Path == "".
|
||||||
|
func Replacement(mod module.Version) module.Version {
|
||||||
|
if index != nil {
|
||||||
|
if r, ok := index.replace[mod]; ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return module.Version{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// indexModFile rebuilds the index of modFile.
|
||||||
|
// If modFile has been changed since it was first read,
|
||||||
|
// modFile.Cleanup must be called before indexModFile.
|
||||||
|
func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
|
||||||
|
i := new(modFileIndex)
|
||||||
|
i.data = data
|
||||||
|
i.dataNeedsFix = needsFix
|
||||||
|
|
||||||
|
i.module = module.Version{}
|
||||||
|
if modFile.Module != nil {
|
||||||
|
i.module = modFile.Module.Mod
|
||||||
|
}
|
||||||
|
|
||||||
|
i.goVersion = ""
|
||||||
|
if modFile.Go != nil {
|
||||||
|
i.goVersion = modFile.Go.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
||||||
|
for _, r := range modFile.Require {
|
||||||
|
i.require[r.Mod] = requireMeta{indirect: r.Indirect}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.replace = make(map[module.Version]module.Version, len(modFile.Replace))
|
||||||
|
for _, r := range modFile.Replace {
|
||||||
|
if prev, dup := i.replace[r.Old]; dup && prev != r.New {
|
||||||
|
base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
|
||||||
|
}
|
||||||
|
i.replace[r.Old] = r.New
|
||||||
|
}
|
||||||
|
|
||||||
|
i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
|
||||||
|
for _, x := range modFile.Exclude {
|
||||||
|
i.exclude[x.Mod] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// modFileIsDirty reports whether the go.mod file differs meaningfully
|
||||||
|
// from what was indexed.
|
||||||
|
// If modFile has been changed (even cosmetically) since it was first read,
|
||||||
|
// modFile.Cleanup must be called before modFileIsDirty.
|
||||||
|
func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
|
||||||
|
if i == nil {
|
||||||
|
return modFile != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.dataNeedsFix {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if modFile.Module == nil {
|
||||||
|
if i.module != (module.Version{}) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if modFile.Module.Mod != i.module {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if modFile.Go == nil {
|
||||||
|
if i.goVersion != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if modFile.Go.Version != i.goVersion {
|
||||||
|
if i.goVersion == "" && cfg.BuildMod == "readonly" {
|
||||||
|
// go.mod files did not always require a 'go' version, so do not error out
|
||||||
|
// if one is missing — we may be inside an older module in the module
|
||||||
|
// cache, and should bias toward providing useful behavior.
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(modFile.Require) != len(i.require) ||
|
||||||
|
len(modFile.Replace) != len(i.replace) ||
|
||||||
|
len(modFile.Exclude) != len(i.exclude) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range modFile.Require {
|
||||||
|
if meta, ok := i.require[r.Mod]; !ok {
|
||||||
|
return true
|
||||||
|
} else if r.Indirect != meta.indirect {
|
||||||
|
if cfg.BuildMod == "readonly" {
|
||||||
|
// The module's requirements are consistent; only the "// indirect"
|
||||||
|
// comments that are wrong. But those are only guaranteed to be accurate
|
||||||
|
// after a "go mod tidy" — it's a good idea to run those before
|
||||||
|
// committing a change, but it's certainly not mandatory.
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range modFile.Replace {
|
||||||
|
if r.New != i.replace[r.Old] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, x := range modFile.Exclude {
|
||||||
|
if !i.exclude[x.Mod] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
253
src/cmd/go/internal/modload/mvs.go
Normal file
253
src/cmd/go/internal/modload/mvs.go
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
// 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 modload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/modfetch"
|
||||||
|
"cmd/go/internal/mvs"
|
||||||
|
"cmd/go/internal/par"
|
||||||
|
|
||||||
|
"golang.org/x/mod/modfile"
|
||||||
|
"golang.org/x/mod/module"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mvsReqs implements mvs.Reqs for module semantic versions,
|
||||||
|
// with any exclusions or replacements applied internally.
|
||||||
|
type mvsReqs struct {
|
||||||
|
buildList []module.Version
|
||||||
|
cache par.Cache
|
||||||
|
versions sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reqs returns the current module requirement graph.
|
||||||
|
// Future calls to SetBuildList do not affect the operation
|
||||||
|
// of the returned Reqs.
|
||||||
|
func Reqs() mvs.Reqs {
|
||||||
|
r := &mvsReqs{
|
||||||
|
buildList: buildList,
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||||
|
type cached struct {
|
||||||
|
list []module.Version
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
c := r.cache.Do(mod, func() interface{} {
|
||||||
|
list, err := r.required(mod)
|
||||||
|
if err != nil {
|
||||||
|
return cached{nil, err}
|
||||||
|
}
|
||||||
|
for i, mv := range list {
|
||||||
|
if index != nil {
|
||||||
|
for index.exclude[mv] {
|
||||||
|
mv1, err := r.next(mv)
|
||||||
|
if err != nil {
|
||||||
|
return cached{nil, err}
|
||||||
|
}
|
||||||
|
if mv1.Version == "none" {
|
||||||
|
return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)}
|
||||||
|
}
|
||||||
|
mv = mv1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list[i] = mv
|
||||||
|
}
|
||||||
|
|
||||||
|
return cached{list, nil}
|
||||||
|
}).(cached)
|
||||||
|
|
||||||
|
return c.list, c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
|
||||||
|
list := make([]module.Version, 0, len(f.Require))
|
||||||
|
for _, r := range f.Require {
|
||||||
|
list = append(list, r.Mod)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// required returns a unique copy of the requirements of mod.
|
||||||
|
func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
|
||||||
|
if mod == Target {
|
||||||
|
if modFile != nil && modFile.Go != nil {
|
||||||
|
r.versions.LoadOrStore(mod, modFile.Go.Version)
|
||||||
|
}
|
||||||
|
return append([]module.Version(nil), r.buildList[1:]...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.BuildMod == "vendor" {
|
||||||
|
// For every module other than the target,
|
||||||
|
// return the full list of modules from modules.txt.
|
||||||
|
readVendorList()
|
||||||
|
return append([]module.Version(nil), vendorList...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
origPath := mod.Path
|
||||||
|
if repl := Replacement(mod); repl.Path != "" {
|
||||||
|
if repl.Version == "" {
|
||||||
|
// TODO: need to slip the new version into the tags list etc.
|
||||||
|
dir := repl.Path
|
||||||
|
if !filepath.IsAbs(dir) {
|
||||||
|
dir = filepath.Join(ModRoot(), dir)
|
||||||
|
}
|
||||||
|
gomod := filepath.Join(dir, "go.mod")
|
||||||
|
data, err := ioutil.ReadFile(gomod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
||||||
|
}
|
||||||
|
f, err := modfile.ParseLax(gomod, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
|
||||||
|
}
|
||||||
|
if f.Go != nil {
|
||||||
|
r.versions.LoadOrStore(mod, f.Go.Version)
|
||||||
|
}
|
||||||
|
return r.modFileToList(f), nil
|
||||||
|
}
|
||||||
|
mod = repl
|
||||||
|
}
|
||||||
|
|
||||||
|
if mod.Version == "none" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !semver.IsValid(mod.Version) {
|
||||||
|
// Disallow the broader queries supported by fetch.Lookup.
|
||||||
|
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := modfetch.GoMod(mod.Path, mod.Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f, err := modfile.ParseLax("go.mod", data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, module.VersionError(mod, fmt.Errorf("parsing go.mod: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Module == nil {
|
||||||
|
return nil, module.VersionError(mod, errors.New("parsing go.mod: missing module line"))
|
||||||
|
}
|
||||||
|
if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
|
||||||
|
return nil, module.VersionError(mod, fmt.Errorf(`parsing go.mod:
|
||||||
|
module declares its path as: %s
|
||||||
|
but was required as: %s`, mpath, mod.Path))
|
||||||
|
}
|
||||||
|
if f.Go != nil {
|
||||||
|
r.versions.LoadOrStore(mod, f.Go.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.modFileToList(f), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*mvsReqs) Max(v1, v2 string) string {
|
||||||
|
if v1 != "" && semver.Compare(v1, v2) == -1 {
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade is a no-op, here to implement mvs.Reqs.
|
||||||
|
// The upgrade logic for go get -u is in ../modget/get.go.
|
||||||
|
func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func versions(path string) ([]string, error) {
|
||||||
|
// Note: modfetch.Lookup and repo.Versions are cached,
|
||||||
|
// so there's no need for us to add extra caching here.
|
||||||
|
var versions []string
|
||||||
|
err := modfetch.TryProxies(func(proxy string) error {
|
||||||
|
repo, err := modfetch.Lookup(proxy, path)
|
||||||
|
if err == nil {
|
||||||
|
versions, err = repo.Versions("")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return versions, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous returns the tagged version of m.Path immediately prior to
|
||||||
|
// m.Version, or version "none" if no prior version is tagged.
|
||||||
|
func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
||||||
|
list, err := versions(m.Path)
|
||||||
|
if err != nil {
|
||||||
|
return module.Version{}, err
|
||||||
|
}
|
||||||
|
i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
|
||||||
|
if i > 0 {
|
||||||
|
return module.Version{Path: m.Path, Version: list[i-1]}, nil
|
||||||
|
}
|
||||||
|
return module.Version{Path: m.Path, Version: "none"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns the next version of m.Path after m.Version.
|
||||||
|
// It is only used by the exclusion processing in the Required method,
|
||||||
|
// not called directly by MVS.
|
||||||
|
func (*mvsReqs) next(m module.Version) (module.Version, error) {
|
||||||
|
list, err := versions(m.Path)
|
||||||
|
if err != nil {
|
||||||
|
return module.Version{}, err
|
||||||
|
}
|
||||||
|
i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
|
||||||
|
if i < len(list) {
|
||||||
|
return module.Version{Path: m.Path, Version: list[i]}, nil
|
||||||
|
}
|
||||||
|
return module.Version{Path: m.Path, Version: "none"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch downloads the given module (or its replacement)
|
||||||
|
// and returns its location.
|
||||||
|
//
|
||||||
|
// The isLocal return value reports whether the replacement,
|
||||||
|
// if any, is local to the filesystem.
|
||||||
|
func fetch(mod module.Version) (dir string, isLocal bool, err error) {
|
||||||
|
if mod == Target {
|
||||||
|
return ModRoot(), true, nil
|
||||||
|
}
|
||||||
|
if r := Replacement(mod); r.Path != "" {
|
||||||
|
if r.Version == "" {
|
||||||
|
dir = r.Path
|
||||||
|
if !filepath.IsAbs(dir) {
|
||||||
|
dir = filepath.Join(ModRoot(), dir)
|
||||||
|
}
|
||||||
|
// Ensure that the replacement directory actually exists:
|
||||||
|
// dirInModule does not report errors for missing modules,
|
||||||
|
// so if we don't report the error now, later failures will be
|
||||||
|
// very mysterious.
|
||||||
|
if _, err := os.Stat(dir); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// Semantically the module version itself “exists” — we just don't
|
||||||
|
// have its source code. Remove the equivalence to os.ErrNotExist,
|
||||||
|
// and make the message more concise while we're at it.
|
||||||
|
err = fmt.Errorf("replacement directory %s does not exist", r.Path)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("replacement directory %s: %w", r.Path, err)
|
||||||
|
}
|
||||||
|
return dir, true, module.VersionError(mod, err)
|
||||||
|
}
|
||||||
|
return dir, true, nil
|
||||||
|
}
|
||||||
|
mod = r
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err = modfetch.Download(mod)
|
||||||
|
return dir, false, err
|
||||||
|
}
|
217
src/cmd/go/internal/modload/vendor.go
Normal file
217
src/cmd/go/internal/modload/vendor.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// 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 modload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"cmd/go/internal/base"
|
||||||
|
|
||||||
|
"golang.org/x/mod/module"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
vendorOnce sync.Once
|
||||||
|
vendorList []module.Version // modules that contribute packages to the build, in order of appearance
|
||||||
|
vendorReplaced []module.Version // all replaced modules; may or may not also contribute packages
|
||||||
|
vendorVersion map[string]string // module path → selected version (if known)
|
||||||
|
vendorPkgModule map[string]module.Version // package → containing module
|
||||||
|
vendorMeta map[module.Version]vendorMetadata
|
||||||
|
)
|
||||||
|
|
||||||
|
type vendorMetadata struct {
|
||||||
|
Explicit bool
|
||||||
|
Replacement module.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// readVendorList reads the list of vendored modules from vendor/modules.txt.
|
||||||
|
func readVendorList() {
|
||||||
|
vendorOnce.Do(func() {
|
||||||
|
vendorList = nil
|
||||||
|
vendorPkgModule = make(map[string]module.Version)
|
||||||
|
vendorVersion = make(map[string]string)
|
||||||
|
vendorMeta = make(map[module.Version]vendorMetadata)
|
||||||
|
data, err := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
|
base.Fatalf("go: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mod module.Version
|
||||||
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
|
if strings.HasPrefix(line, "# ") {
|
||||||
|
f := strings.Fields(line)
|
||||||
|
|
||||||
|
if len(f) < 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if semver.IsValid(f[2]) {
|
||||||
|
// A module, but we don't yet know whether it is in the build list or
|
||||||
|
// only included to indicate a replacement.
|
||||||
|
mod = module.Version{Path: f[1], Version: f[2]}
|
||||||
|
f = f[3:]
|
||||||
|
} else if f[2] == "=>" {
|
||||||
|
// A wildcard replacement found in the main module's go.mod file.
|
||||||
|
mod = module.Version{Path: f[1]}
|
||||||
|
f = f[2:]
|
||||||
|
} else {
|
||||||
|
// Not a version or a wildcard replacement.
|
||||||
|
// We don't know how to interpret this module line, so ignore it.
|
||||||
|
mod = module.Version{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f) >= 2 && f[0] == "=>" {
|
||||||
|
meta := vendorMeta[mod]
|
||||||
|
if len(f) == 2 {
|
||||||
|
// File replacement.
|
||||||
|
meta.Replacement = module.Version{Path: f[1]}
|
||||||
|
vendorReplaced = append(vendorReplaced, mod)
|
||||||
|
} else if len(f) == 3 && semver.IsValid(f[2]) {
|
||||||
|
// Path and version replacement.
|
||||||
|
meta.Replacement = module.Version{Path: f[1], Version: f[2]}
|
||||||
|
vendorReplaced = append(vendorReplaced, mod)
|
||||||
|
} else {
|
||||||
|
// We don't understand this replacement. Ignore it.
|
||||||
|
}
|
||||||
|
vendorMeta[mod] = meta
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a module line. Must be a package within a module or a metadata
|
||||||
|
// directive, either of which requires a preceding module line.
|
||||||
|
if mod.Path == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(line, "## ") {
|
||||||
|
// Metadata. Take the union of annotations across multiple lines, if present.
|
||||||
|
meta := vendorMeta[mod]
|
||||||
|
for _, entry := range strings.Split(strings.TrimPrefix(line, "## "), ";") {
|
||||||
|
entry = strings.TrimSpace(entry)
|
||||||
|
if entry == "explicit" {
|
||||||
|
meta.Explicit = true
|
||||||
|
}
|
||||||
|
// All other tokens are reserved for future use.
|
||||||
|
}
|
||||||
|
vendorMeta[mod] = meta
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f := strings.Fields(line); len(f) == 1 && module.CheckImportPath(f[0]) == nil {
|
||||||
|
// A package within the current module.
|
||||||
|
vendorPkgModule[f[0]] = mod
|
||||||
|
|
||||||
|
// Since this module provides a package for the build, we know that it
|
||||||
|
// is in the build list and is the selected version of its path.
|
||||||
|
// If this information is new, record it.
|
||||||
|
if v, ok := vendorVersion[mod.Path]; !ok || semver.Compare(v, mod.Version) < 0 {
|
||||||
|
vendorList = append(vendorList, mod)
|
||||||
|
vendorVersion[mod.Path] = mod.Version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkVendorConsistency verifies that the vendor/modules.txt file matches (if
|
||||||
|
// go 1.14) or at least does not contradict (go 1.13 or earlier) the
|
||||||
|
// requirements and replacements listed in the main module's go.mod file.
|
||||||
|
func checkVendorConsistency() {
|
||||||
|
readVendorList()
|
||||||
|
|
||||||
|
pre114 := false
|
||||||
|
if modFile.Go == nil || semver.Compare("v"+modFile.Go.Version, "v1.14") < 0 {
|
||||||
|
// Go versions before 1.14 did not include enough information in
|
||||||
|
// vendor/modules.txt to check for consistency.
|
||||||
|
// If we know that we're on an earlier version, relax the consistency check.
|
||||||
|
pre114 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
vendErrors := new(strings.Builder)
|
||||||
|
vendErrorf := func(mod module.Version, format string, args ...interface{}) {
|
||||||
|
detail := fmt.Sprintf(format, args...)
|
||||||
|
if mod.Version == "" {
|
||||||
|
fmt.Fprintf(vendErrors, "\n\t%s: %s", mod.Path, detail)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(vendErrors, "\n\t%s@%s: %s", mod.Path, mod.Version, detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range modFile.Require {
|
||||||
|
if !vendorMeta[r.Mod].Explicit {
|
||||||
|
if pre114 {
|
||||||
|
// Before 1.14, modules.txt did not indicate whether modules were listed
|
||||||
|
// explicitly in the main module's go.mod file.
|
||||||
|
// However, we can at least detect a version mismatch if packages were
|
||||||
|
// vendored from a non-matching version.
|
||||||
|
if vv, ok := vendorVersion[r.Mod.Path]; ok && vv != r.Mod.Version {
|
||||||
|
vendErrorf(r.Mod, fmt.Sprintf("is explicitly required in go.mod, but vendor/modules.txt indicates %s@%s", r.Mod.Path, vv))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vendErrorf(r.Mod, "is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe := func(m module.Version) string {
|
||||||
|
if m.Version == "" {
|
||||||
|
return m.Path
|
||||||
|
}
|
||||||
|
return m.Path + "@" + m.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to verify *all* replacements that occur in modfile: even if they
|
||||||
|
// don't directly apply to any module in the vendor list, the replacement
|
||||||
|
// go.mod file can affect the selected versions of other (transitive)
|
||||||
|
// dependencies
|
||||||
|
for _, r := range modFile.Replace {
|
||||||
|
vr := vendorMeta[r.Old].Replacement
|
||||||
|
if vr == (module.Version{}) {
|
||||||
|
if pre114 && (r.Old.Version == "" || vendorVersion[r.Old.Path] != r.Old.Version) {
|
||||||
|
// Before 1.14, modules.txt omitted wildcard replacements and
|
||||||
|
// replacements for modules that did not have any packages to vendor.
|
||||||
|
} else {
|
||||||
|
vendErrorf(r.Old, "is replaced in go.mod, but not marked as replaced in vendor/modules.txt")
|
||||||
|
}
|
||||||
|
} else if vr != r.New {
|
||||||
|
vendErrorf(r.Old, "is replaced by %s in go.mod, but marked as replaced by %s in vendor/modules.txt", describe(r.New), describe(vr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mod := range vendorList {
|
||||||
|
meta := vendorMeta[mod]
|
||||||
|
if meta.Explicit {
|
||||||
|
if _, inGoMod := index.require[mod]; !inGoMod {
|
||||||
|
vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in go.mod")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mod := range vendorReplaced {
|
||||||
|
r := Replacement(mod)
|
||||||
|
if r == (module.Version{}) {
|
||||||
|
vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if meta := vendorMeta[mod]; r != meta.Replacement {
|
||||||
|
vendErrorf(mod, "is marked as replaced by %s in vendor/modules.txt, but replaced by %s in go.mod", describe(meta.Replacement), describe(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vendErrors.Len() > 0 {
|
||||||
|
base.Fatalf("go: inconsistent vendoring in %s:%s\n\nrun 'go mod vendor' to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory", modRoot, vendErrors)
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const arbitraryTimeout = 500 * time.Millisecond
|
const arbitraryTimeout = 2000 * time.Millisecond
|
||||||
|
|
||||||
// retry retries ephemeral errors from f up to an arbitrary timeout
|
// retry retries ephemeral errors from f up to an arbitrary timeout
|
||||||
// to work around filesystem flakiness on Windows and Darwin.
|
// to work around filesystem flakiness on Windows and Darwin.
|
||||||
|
@ -213,6 +213,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
|
|||||||
} else if cfg.BuildTrimpath && p.Module != nil {
|
} else if cfg.BuildTrimpath && p.Module != nil {
|
||||||
fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version)
|
fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version)
|
||||||
}
|
}
|
||||||
|
if p.Module != nil {
|
||||||
|
fmt.Fprintf(h, "go %s\n", p.Module.GoVersion)
|
||||||
|
}
|
||||||
fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
|
fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
|
||||||
fmt.Fprintf(h, "import %q\n", p.ImportPath)
|
fmt.Fprintf(h, "import %q\n", p.ImportPath)
|
||||||
fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
|
fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
|
||||||
|
@ -109,6 +109,7 @@ func (ts *testScript) setup() {
|
|||||||
"CCACHE_DISABLE=1", // ccache breaks with non-existent HOME
|
"CCACHE_DISABLE=1", // ccache breaks with non-existent HOME
|
||||||
"GOARCH=" + runtime.GOARCH,
|
"GOARCH=" + runtime.GOARCH,
|
||||||
"GOCACHE=" + testGOCACHE,
|
"GOCACHE=" + testGOCACHE,
|
||||||
|
"GODEBUG=" + os.Getenv("GODEBUG"),
|
||||||
"GOEXE=" + cfg.ExeSuffix,
|
"GOEXE=" + cfg.ExeSuffix,
|
||||||
"GOOS=" + runtime.GOOS,
|
"GOOS=" + runtime.GOOS,
|
||||||
"GOPATH=" + filepath.Join(ts.workdir, "gopath"),
|
"GOPATH=" + filepath.Join(ts.workdir, "gopath"),
|
||||||
|
1
src/cmd/go/testdata/script/README
vendored
1
src/cmd/go/testdata/script/README
vendored
@ -36,6 +36,7 @@ Scripts also have access to these other environment variables:
|
|||||||
HOME=/no-home
|
HOME=/no-home
|
||||||
PATH=<actual PATH>
|
PATH=<actual PATH>
|
||||||
TMPDIR=$WORK/tmp
|
TMPDIR=$WORK/tmp
|
||||||
|
GODEBUG=<actual GODEBUG>
|
||||||
devnull=<value of os.DevNull>
|
devnull=<value of os.DevNull>
|
||||||
goversion=<current Go version; for example, 1.12>
|
goversion=<current Go version; for example, 1.12>
|
||||||
:=<OS-specific path list separator>
|
:=<OS-specific path list separator>
|
||||||
|
3
src/cmd/go/testdata/script/build_gcflags.txt
vendored
3
src/cmd/go/testdata/script/build_gcflags.txt
vendored
@ -7,7 +7,8 @@ env GO111MODULE=off
|
|||||||
[!linux] skip # test only works if c-archive implies -shared
|
[!linux] skip # test only works if c-archive implies -shared
|
||||||
[short] skip
|
[short] skip
|
||||||
|
|
||||||
go build -x -buildmode=c-archive -gcflags=all=-shared=false ./override.go
|
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||||
|
go build -x -n -buildmode=c-archive -gcflags=all=-shared=false ./override.go
|
||||||
stderr '^.*/compile (.* )?-shared (.* )?-shared=false'
|
stderr '^.*/compile (.* )?-shared (.* )?-shared=false'
|
||||||
|
|
||||||
-- override.go --
|
-- override.go --
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
[short] skip
|
[short] skip
|
||||||
[!cgo] skip
|
[!cgo] skip
|
||||||
|
|
||||||
go run -x main.go
|
env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache.
|
||||||
|
go build -x -n main.go
|
||||||
stderr '"-I[^"]+c flags"' # find quoted c flags
|
stderr '"-I[^"]+c flags"' # find quoted c flags
|
||||||
! stderr '"-I[^"]+c flags".*"-I[^"]+c flags"' # don't find too many quoted c flags
|
! stderr '"-I[^"]+c flags".*"-I[^"]+c flags"' # don't find too many quoted c flags per line
|
||||||
stderr '"-L[^"]+ld flags"' # find quoted ld flags
|
stderr '"-L[^"]+ld flags"' # find quoted ld flags
|
||||||
! stderr '"-L[^"]+c flags".*"-L[^"]+c flags"' # don't find too many quoted ld flags
|
! stderr '"-L[^"]+c flags".*"-L[^"]+c flags"' # don't find too many quoted ld flags per line
|
||||||
|
|
||||||
-- main.go --
|
-- main.go --
|
||||||
package main
|
package main
|
||||||
|
31
src/cmd/go/testdata/script/cover_blank_func_decl.txt
vendored
Normal file
31
src/cmd/go/testdata/script/cover_blank_func_decl.txt
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[short] skip
|
||||||
|
go test -cover ./coverblank
|
||||||
|
stdout 'coverage: 100.0% of statements'
|
||||||
|
|
||||||
|
|
||||||
|
-- coverblank/a.go --
|
||||||
|
package coverblank
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
println("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
type X int
|
||||||
|
|
||||||
|
func (x X) Print() {
|
||||||
|
println(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x X) _() {
|
||||||
|
println("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
-- coverblank/a_test.go --
|
||||||
|
package coverblank
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestX(t *testing.T) {
|
||||||
|
var x X
|
||||||
|
x.Print()
|
||||||
|
}
|
@ -3,6 +3,8 @@ env GO111MODULE=off
|
|||||||
[!gc] skip 'using -gcflags and -ldflags'
|
[!gc] skip 'using -gcflags and -ldflags'
|
||||||
[short] skip
|
[short] skip
|
||||||
|
|
||||||
|
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||||
|
|
||||||
# -gcflags=-e applies to named packages, not dependencies
|
# -gcflags=-e applies to named packages, not dependencies
|
||||||
go build -n -v -gcflags=-e z1 z2
|
go build -n -v -gcflags=-e z1 z2
|
||||||
stderr 'compile.* -e.* -p z1'
|
stderr 'compile.* -e.* -p z1'
|
||||||
|
17
src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt
vendored
Normal file
17
src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# This tests checks the GODEBUG=modcacheunzipinplace=1 flag, used as part of
|
||||||
|
# a migration in golang.org/issue/36568.
|
||||||
|
#
|
||||||
|
# Concurrent downloads with and without GODEBUG=modcacheunzipinplace=1 should
|
||||||
|
# not conflict. This is meant to simulate an old version and a new version
|
||||||
|
# of Go accessing the cache concurrently.
|
||||||
|
go mod download &
|
||||||
|
env GODEBUG=modcacheunzipinplace=1
|
||||||
|
go mod download
|
||||||
|
wait
|
||||||
|
|
||||||
|
-- go.mod --
|
||||||
|
module golang.org/issue/36568
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require rsc.io/quote v1.5.2
|
120
src/cmd/go/testdata/script/mod_download_concurrent_read.txt
vendored
Normal file
120
src/cmd/go/testdata/script/mod_download_concurrent_read.txt
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# This test simulates a process watching for changes and reading files in
|
||||||
|
# module cache as a module is extracted.
|
||||||
|
#
|
||||||
|
# By default, we unzip a downloaded module into a temporary directory with a
|
||||||
|
# random name, then rename the directory into place. On Windows, this fails
|
||||||
|
# with ERROR_ACCESS_DENIED if another process (e.g., antivirus) opens files
|
||||||
|
# in the directory.
|
||||||
|
#
|
||||||
|
# Setting GODEBUG=modcacheunzipinplace=1 opts into new behavior: a downloaded
|
||||||
|
# module is unzipped in place. A .partial file is created elsewhere to indicate
|
||||||
|
# that the extraction is incomplete.
|
||||||
|
#
|
||||||
|
# Verifies golang.org/issue/36568.
|
||||||
|
|
||||||
|
[!windows] skip
|
||||||
|
[short] skip
|
||||||
|
|
||||||
|
# Control case: check that the default behavior fails.
|
||||||
|
# This is commented out to avoid flakiness. We can't reproduce the failure
|
||||||
|
# 100% of the time.
|
||||||
|
# ! go run downloader.go
|
||||||
|
|
||||||
|
# Experiment: check that the new behavior does not fail.
|
||||||
|
env GODEBUG=modcacheunzipinplace=1
|
||||||
|
go run downloader.go
|
||||||
|
|
||||||
|
-- go.mod --
|
||||||
|
module example.com/m
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
-- downloader.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run repeatedly downloads a module while opening files in the module cache
|
||||||
|
// in a background goroutine.
|
||||||
|
//
|
||||||
|
// run uses a different temporary module cache in each iteration so that we
|
||||||
|
// don't need to clean the cache or synchronize closing files after each
|
||||||
|
// iteration.
|
||||||
|
func run() (err error) {
|
||||||
|
tmpDir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if rmErr := os.RemoveAll(tmpDir); err == nil && rmErr != nil {
|
||||||
|
err = rmErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
gopath := filepath.Join(tmpDir, fmt.Sprintf("gopath%d", i))
|
||||||
|
var err error
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
err = download(gopath)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
readCache(gopath, done)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// download downloads a module into the given cache using 'go mod download'.
|
||||||
|
func download(gopath string) error {
|
||||||
|
cmd := exec.Command("go", "mod", "download", "-modcacherw", "rsc.io/quote@v1.5.2")
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Env = append(os.Environ(), "GOPATH="+gopath)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// readCache repeatedly globs for go.mod files in the given cache, then opens
|
||||||
|
// those files for reading. When the done chan is closed, readCache closes
|
||||||
|
// files and returns.
|
||||||
|
func readCache(gopath string, done <-chan struct{}) {
|
||||||
|
files := make(map[string]*os.File)
|
||||||
|
defer func() {
|
||||||
|
for _, f := range files {
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
pattern := filepath.Join(gopath, "pkg/mod/rsc.io/quote@v1.5.2*/go.mod")
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
names, _ := filepath.Glob(pattern)
|
||||||
|
for _, name := range names {
|
||||||
|
if files[name] != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f, _ := os.Open(name)
|
||||||
|
if f != nil {
|
||||||
|
files[name] = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
src/cmd/go/testdata/script/mod_download_partial.txt
vendored
Normal file
64
src/cmd/go/testdata/script/mod_download_partial.txt
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Download a module
|
||||||
|
go mod download -modcacherw rsc.io/quote
|
||||||
|
exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
|
||||||
|
|
||||||
|
# 'go mod verify' should fail if we delete a file.
|
||||||
|
go mod verify
|
||||||
|
rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
|
||||||
|
! go mod verify
|
||||||
|
|
||||||
|
# Create a .partial file to simulate an failure extracting the zip file.
|
||||||
|
cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
|
||||||
|
|
||||||
|
# 'go mod verify' should not fail, since the module hasn't been completely
|
||||||
|
# ingested into the cache.
|
||||||
|
go mod verify
|
||||||
|
|
||||||
|
# 'go list' should not load packages from the directory.
|
||||||
|
# NOTE: the message "directory $dir outside available modules" is reported
|
||||||
|
# for directories not in the main module, active modules in the module cache,
|
||||||
|
# or local replacements. In this case, the directory is in the right place,
|
||||||
|
# but it's incomplete, so 'go list' acts as if it's not an active module.
|
||||||
|
! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
|
||||||
|
stderr 'outside available modules'
|
||||||
|
|
||||||
|
# 'go list -m' should not print the directory.
|
||||||
|
go list -m -f '{{.Dir}}' rsc.io/quote
|
||||||
|
! stdout .
|
||||||
|
|
||||||
|
# 'go mod download' should re-extract the module and remove the .partial file.
|
||||||
|
go mod download -modcacherw rsc.io/quote
|
||||||
|
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
|
||||||
|
exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
|
||||||
|
|
||||||
|
# 'go list' should succeed.
|
||||||
|
go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
|
||||||
|
stdout '^rsc.io/quote$'
|
||||||
|
|
||||||
|
# 'go list -m' should print the directory.
|
||||||
|
go list -m -f '{{.Dir}}' rsc.io/quote
|
||||||
|
stdout 'pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2'
|
||||||
|
|
||||||
|
# go mod verify should fail if we delete a file.
|
||||||
|
go mod verify
|
||||||
|
rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
|
||||||
|
! go mod verify
|
||||||
|
|
||||||
|
# 'go mod download' should not leave behind a directory or a .partial file
|
||||||
|
# if there is an error extracting the zip file.
|
||||||
|
env GODEBUG=modcacheunzipinplace=1
|
||||||
|
rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
|
||||||
|
cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
|
||||||
|
! go mod download
|
||||||
|
stderr 'not a valid zip file'
|
||||||
|
! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
|
||||||
|
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
|
||||||
|
|
||||||
|
-- go.mod --
|
||||||
|
module m
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require rsc.io/quote v1.5.2
|
||||||
|
|
||||||
|
-- empty --
|
7
src/cmd/go/testdata/script/mod_edit_go.txt
vendored
7
src/cmd/go/testdata/script/mod_edit_go.txt
vendored
@ -7,6 +7,13 @@ go mod edit -go=1.9
|
|||||||
grep 'go 1.9' go.mod
|
grep 'go 1.9' go.mod
|
||||||
go build
|
go build
|
||||||
|
|
||||||
|
# Reverting the version should force a rebuild and error instead of using
|
||||||
|
# the cached 1.9 build. (https://golang.org/issue/37804)
|
||||||
|
go mod edit -go=1.8
|
||||||
|
! go build
|
||||||
|
stderr 'type aliases only supported as of'
|
||||||
|
|
||||||
|
|
||||||
-- go.mod --
|
-- go.mod --
|
||||||
module m
|
module m
|
||||||
go 1.8
|
go 1.8
|
||||||
|
@ -14,6 +14,9 @@ go get -d golang.org/x/text@14c0d48
|
|||||||
|
|
||||||
# dropping -d, we should see a build.
|
# dropping -d, we should see a build.
|
||||||
[short] skip
|
[short] skip
|
||||||
|
|
||||||
|
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||||
|
|
||||||
go get -x golang.org/x/text/language@14c0d48
|
go get -x golang.org/x/text/language@14c0d48
|
||||||
stderr 'compile|cp|gccgo .*language\.a$'
|
stderr 'compile|cp|gccgo .*language\.a$'
|
||||||
|
|
||||||
|
3
src/cmd/go/testdata/script/mod_get_tags.txt
vendored
3
src/cmd/go/testdata/script/mod_get_tags.txt
vendored
@ -14,7 +14,8 @@ stdout 'rsc.io/quote v1.5.2'
|
|||||||
[short] skip
|
[short] skip
|
||||||
|
|
||||||
# Packages that are only imported in excluded files should not be built.
|
# Packages that are only imported in excluded files should not be built.
|
||||||
go get -x .
|
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||||
|
go get -n -x .
|
||||||
stderr 'compile.* -p m '
|
stderr 'compile.* -p m '
|
||||||
! stderr 'compile.* -p example.com/version '
|
! stderr 'compile.* -p example.com/version '
|
||||||
! stderr 'compile.* -p rsc.io/quote '
|
! stderr 'compile.* -p rsc.io/quote '
|
||||||
|
@ -76,17 +76,17 @@ cp go.mod.orig go.mod
|
|||||||
go mod edit -require golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c
|
go mod edit -require golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c
|
||||||
cd outside
|
cd outside
|
||||||
! go list -m golang.org/x/text
|
! go list -m golang.org/x/text
|
||||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(2017-09-15T03:28:32Z\)'
|
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
|
||||||
cd ..
|
cd ..
|
||||||
! go list -m golang.org/x/text
|
! go list -m golang.org/x/text
|
||||||
stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(2017-09-15T03:28:32Z\)'
|
stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
|
||||||
|
|
||||||
# A 'replace' directive in the main module can replace an invalid timestamp
|
# A 'replace' directive in the main module can replace an invalid timestamp
|
||||||
# with a valid one.
|
# with a valid one.
|
||||||
go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c
|
go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c
|
||||||
cd outside
|
cd outside
|
||||||
! go list -m golang.org/x/text
|
! go list -m golang.org/x/text
|
||||||
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(2017-09-15T03:28:32Z\)'
|
stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
|
||||||
cd ..
|
cd ..
|
||||||
go list -m golang.org/x/text
|
go list -m golang.org/x/text
|
||||||
stdout 'golang.org/x/text v0.1.1-0.20190915032832-14c0d48ead0c => golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c'
|
stdout 'golang.org/x/text v0.1.1-0.20190915032832-14c0d48ead0c => golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c'
|
||||||
|
@ -47,6 +47,7 @@ func findGorootModules(t *testing.T) []gorootModule {
|
|||||||
// Use 'go list' to describe the module contained in this directory (but
|
// Use 'go list' to describe the module contained in this directory (but
|
||||||
// not its dependencies).
|
// not its dependencies).
|
||||||
cmd := exec.Command(goBin, "list", "-json", "-m")
|
cmd := exec.Command(goBin, "list", "-json", "-m")
|
||||||
|
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
cmd.Stderr = new(strings.Builder)
|
cmd.Stderr = new(strings.Builder)
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
@ -103,6 +104,7 @@ func TestAllDependenciesVendored(t *testing.T) {
|
|||||||
// dependencies are vendored. If any imported package is missing,
|
// dependencies are vendored. If any imported package is missing,
|
||||||
// 'go list -deps' will fail when attempting to load it.
|
// 'go list -deps' will fail when attempting to load it.
|
||||||
cmd := exec.Command(goBin, "list", "-mod=vendor", "-deps", "./...")
|
cmd := exec.Command(goBin, "list", "-mod=vendor", "-deps", "./...")
|
||||||
|
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||||
cmd.Dir = m.Dir
|
cmd.Dir = m.Dir
|
||||||
cmd.Stderr = new(strings.Builder)
|
cmd.Stderr = new(strings.Builder)
|
||||||
_, err := cmd.Output()
|
_, err := cmd.Output()
|
||||||
@ -115,7 +117,8 @@ func TestAllDependenciesVendored(t *testing.T) {
|
|||||||
|
|
||||||
// There is no vendor directory, so the module must have no dependencies.
|
// There is no vendor directory, so the module must have no dependencies.
|
||||||
// Check that the list of active modules contains only the main module.
|
// Check that the list of active modules contains only the main module.
|
||||||
cmd := exec.Command(goBin, "list", "-m", "all")
|
cmd := exec.Command(goBin, "list", "-mod=mod", "-m", "all")
|
||||||
|
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||||
cmd.Dir = m.Dir
|
cmd.Dir = m.Dir
|
||||||
cmd.Stderr = new(strings.Builder)
|
cmd.Stderr = new(strings.Builder)
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
|
@ -944,22 +944,16 @@ const (
|
|||||||
ASTXVW4X
|
ASTXVW4X
|
||||||
ASTXVH8X
|
ASTXVH8X
|
||||||
ASTXVB16X
|
ASTXVB16X
|
||||||
ALXS
|
|
||||||
ALXSDX
|
ALXSDX
|
||||||
ASTXS
|
|
||||||
ASTXSDX
|
ASTXSDX
|
||||||
ALXSI
|
|
||||||
ALXSIWAX
|
ALXSIWAX
|
||||||
ALXSIWZX
|
ALXSIWZX
|
||||||
ASTXSI
|
|
||||||
ASTXSIWX
|
ASTXSIWX
|
||||||
AMFVSR
|
|
||||||
AMFVSRD
|
AMFVSRD
|
||||||
AMFFPRD
|
AMFFPRD
|
||||||
AMFVRD
|
AMFVRD
|
||||||
AMFVSRWZ
|
AMFVSRWZ
|
||||||
AMFVSRLD
|
AMFVSRLD
|
||||||
AMTVSR
|
|
||||||
AMTVSRD
|
AMTVSRD
|
||||||
AMTFPRD
|
AMTFPRD
|
||||||
AMTVRD
|
AMTVRD
|
||||||
@ -968,7 +962,6 @@ const (
|
|||||||
AMTVSRDD
|
AMTVSRDD
|
||||||
AMTVSRWS
|
AMTVSRWS
|
||||||
AXXLAND
|
AXXLAND
|
||||||
AXXLANDQ
|
|
||||||
AXXLANDC
|
AXXLANDC
|
||||||
AXXLEQV
|
AXXLEQV
|
||||||
AXXLNAND
|
AXXLNAND
|
||||||
@ -978,34 +971,27 @@ const (
|
|||||||
AXXLORQ
|
AXXLORQ
|
||||||
AXXLXOR
|
AXXLXOR
|
||||||
AXXSEL
|
AXXSEL
|
||||||
AXXMRG
|
|
||||||
AXXMRGHW
|
AXXMRGHW
|
||||||
AXXMRGLW
|
AXXMRGLW
|
||||||
AXXSPLT
|
AXXSPLT
|
||||||
AXXSPLTW
|
AXXSPLTW
|
||||||
AXXPERM
|
AXXPERM
|
||||||
AXXPERMDI
|
AXXPERMDI
|
||||||
AXXSI
|
|
||||||
AXXSLDWI
|
AXXSLDWI
|
||||||
AXSCV
|
|
||||||
AXSCVDPSP
|
AXSCVDPSP
|
||||||
AXSCVSPDP
|
AXSCVSPDP
|
||||||
AXSCVDPSPN
|
AXSCVDPSPN
|
||||||
AXSCVSPDPN
|
AXSCVSPDPN
|
||||||
AXVCV
|
|
||||||
AXVCVDPSP
|
AXVCVDPSP
|
||||||
AXVCVSPDP
|
AXVCVSPDP
|
||||||
AXSCVX
|
|
||||||
AXSCVDPSXDS
|
AXSCVDPSXDS
|
||||||
AXSCVDPSXWS
|
AXSCVDPSXWS
|
||||||
AXSCVDPUXDS
|
AXSCVDPUXDS
|
||||||
AXSCVDPUXWS
|
AXSCVDPUXWS
|
||||||
AXSCVXP
|
|
||||||
AXSCVSXDDP
|
AXSCVSXDDP
|
||||||
AXSCVUXDDP
|
AXSCVUXDDP
|
||||||
AXSCVSXDSP
|
AXSCVSXDSP
|
||||||
AXSCVUXDSP
|
AXSCVUXDSP
|
||||||
AXVCVX
|
|
||||||
AXVCVDPSXDS
|
AXVCVDPSXDS
|
||||||
AXVCVDPSXWS
|
AXVCVDPSXWS
|
||||||
AXVCVDPUXDS
|
AXVCVDPUXDS
|
||||||
@ -1014,7 +1000,6 @@ const (
|
|||||||
AXVCVSPSXWS
|
AXVCVSPSXWS
|
||||||
AXVCVSPUXDS
|
AXVCVSPUXDS
|
||||||
AXVCVSPUXWS
|
AXVCVSPUXWS
|
||||||
AXVCVXP
|
|
||||||
AXVCVSXDDP
|
AXVCVSXDDP
|
||||||
AXVCVSXWDP
|
AXVCVSXWDP
|
||||||
AXVCVUXDDP
|
AXVCVUXDDP
|
||||||
|
@ -532,22 +532,16 @@ var Anames = []string{
|
|||||||
"STXVW4X",
|
"STXVW4X",
|
||||||
"STXVH8X",
|
"STXVH8X",
|
||||||
"STXVB16X",
|
"STXVB16X",
|
||||||
"LXS",
|
|
||||||
"LXSDX",
|
"LXSDX",
|
||||||
"STXS",
|
|
||||||
"STXSDX",
|
"STXSDX",
|
||||||
"LXSI",
|
|
||||||
"LXSIWAX",
|
"LXSIWAX",
|
||||||
"LXSIWZX",
|
"LXSIWZX",
|
||||||
"STXSI",
|
|
||||||
"STXSIWX",
|
"STXSIWX",
|
||||||
"MFVSR",
|
|
||||||
"MFVSRD",
|
"MFVSRD",
|
||||||
"MFFPRD",
|
"MFFPRD",
|
||||||
"MFVRD",
|
"MFVRD",
|
||||||
"MFVSRWZ",
|
"MFVSRWZ",
|
||||||
"MFVSRLD",
|
"MFVSRLD",
|
||||||
"MTVSR",
|
|
||||||
"MTVSRD",
|
"MTVSRD",
|
||||||
"MTFPRD",
|
"MTFPRD",
|
||||||
"MTVRD",
|
"MTVRD",
|
||||||
@ -556,7 +550,6 @@ var Anames = []string{
|
|||||||
"MTVSRDD",
|
"MTVSRDD",
|
||||||
"MTVSRWS",
|
"MTVSRWS",
|
||||||
"XXLAND",
|
"XXLAND",
|
||||||
"XXLANDQ",
|
|
||||||
"XXLANDC",
|
"XXLANDC",
|
||||||
"XXLEQV",
|
"XXLEQV",
|
||||||
"XXLNAND",
|
"XXLNAND",
|
||||||
@ -566,34 +559,27 @@ var Anames = []string{
|
|||||||
"XXLORQ",
|
"XXLORQ",
|
||||||
"XXLXOR",
|
"XXLXOR",
|
||||||
"XXSEL",
|
"XXSEL",
|
||||||
"XXMRG",
|
|
||||||
"XXMRGHW",
|
"XXMRGHW",
|
||||||
"XXMRGLW",
|
"XXMRGLW",
|
||||||
"XXSPLT",
|
"XXSPLT",
|
||||||
"XXSPLTW",
|
"XXSPLTW",
|
||||||
"XXPERM",
|
"XXPERM",
|
||||||
"XXPERMDI",
|
"XXPERMDI",
|
||||||
"XXSI",
|
|
||||||
"XXSLDWI",
|
"XXSLDWI",
|
||||||
"XSCV",
|
|
||||||
"XSCVDPSP",
|
"XSCVDPSP",
|
||||||
"XSCVSPDP",
|
"XSCVSPDP",
|
||||||
"XSCVDPSPN",
|
"XSCVDPSPN",
|
||||||
"XSCVSPDPN",
|
"XSCVSPDPN",
|
||||||
"XVCV",
|
|
||||||
"XVCVDPSP",
|
"XVCVDPSP",
|
||||||
"XVCVSPDP",
|
"XVCVSPDP",
|
||||||
"XSCVX",
|
|
||||||
"XSCVDPSXDS",
|
"XSCVDPSXDS",
|
||||||
"XSCVDPSXWS",
|
"XSCVDPSXWS",
|
||||||
"XSCVDPUXDS",
|
"XSCVDPUXDS",
|
||||||
"XSCVDPUXWS",
|
"XSCVDPUXWS",
|
||||||
"XSCVXP",
|
|
||||||
"XSCVSXDDP",
|
"XSCVSXDDP",
|
||||||
"XSCVUXDDP",
|
"XSCVUXDDP",
|
||||||
"XSCVSXDSP",
|
"XSCVSXDSP",
|
||||||
"XSCVUXDSP",
|
"XSCVUXDSP",
|
||||||
"XVCVX",
|
|
||||||
"XVCVDPSXDS",
|
"XVCVDPSXDS",
|
||||||
"XVCVDPSXWS",
|
"XVCVDPSXWS",
|
||||||
"XVCVDPUXDS",
|
"XVCVDPUXDS",
|
||||||
@ -602,7 +588,6 @@ var Anames = []string{
|
|||||||
"XVCVSPSXWS",
|
"XVCVSPSXWS",
|
||||||
"XVCVSPUXDS",
|
"XVCVSPUXDS",
|
||||||
"XVCVSPUXWS",
|
"XVCVSPUXWS",
|
||||||
"XVCVXP",
|
|
||||||
"XVCVSXDDP",
|
"XVCVSXDDP",
|
||||||
"XVCVSXWDP",
|
"XVCVSXWDP",
|
||||||
"XVCVUXDDP",
|
"XVCVUXDDP",
|
||||||
|
@ -462,10 +462,10 @@ var optab = []Optab{
|
|||||||
{AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector select, va-form */
|
{AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector select, va-form */
|
||||||
|
|
||||||
/* Vector splat */
|
/* Vector splat */
|
||||||
{AVSPLT, C_SCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector splat, vx-form */
|
{AVSPLTB, C_SCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector splat, vx-form */
|
||||||
{AVSPLT, C_ADDCON, C_VREG, C_NONE, C_VREG, 82, 4, 0},
|
{AVSPLTB, C_ADDCON, C_VREG, C_NONE, C_VREG, 82, 4, 0},
|
||||||
{AVSPLTI, C_SCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector splat immediate, vx-form */
|
{AVSPLTISB, C_SCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector splat immediate, vx-form */
|
||||||
{AVSPLTI, C_ADDCON, C_NONE, C_NONE, C_VREG, 82, 4, 0},
|
{AVSPLTISB, C_ADDCON, C_NONE, C_NONE, C_VREG, 82, 4, 0},
|
||||||
|
|
||||||
/* Vector AES */
|
/* Vector AES */
|
||||||
{AVCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES cipher, vx-form */
|
{AVCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES cipher, vx-form */
|
||||||
@ -484,27 +484,27 @@ var optab = []Optab{
|
|||||||
{ASTXV, C_VSREG, C_NONE, C_NONE, C_SOREG, 97, 4, 0}, /* vsx vector store, dq-form */
|
{ASTXV, C_VSREG, C_NONE, C_NONE, C_SOREG, 97, 4, 0}, /* vsx vector store, dq-form */
|
||||||
|
|
||||||
/* VSX scalar load */
|
/* VSX scalar load */
|
||||||
{ALXS, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar load, xx1-form */
|
{ALXSDX, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar load, xx1-form */
|
||||||
|
|
||||||
/* VSX scalar store */
|
/* VSX scalar store */
|
||||||
{ASTXS, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar store, xx1-form */
|
{ASTXSDX, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar store, xx1-form */
|
||||||
|
|
||||||
/* VSX scalar as integer load */
|
/* VSX scalar as integer load */
|
||||||
{ALXSI, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar as integer load, xx1-form */
|
{ALXSIWAX, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar as integer load, xx1-form */
|
||||||
|
|
||||||
/* VSX scalar store as integer */
|
/* VSX scalar store as integer */
|
||||||
{ASTXSI, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar as integer store, xx1-form */
|
{ASTXSIWX, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar as integer store, xx1-form */
|
||||||
|
|
||||||
/* VSX move from VSR */
|
/* VSX move from VSR */
|
||||||
{AMFVSR, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */
|
{AMFVSRD, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */
|
||||||
{AMFVSR, C_FREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
{AMFVSRD, C_FREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
||||||
{AMFVSR, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
{AMFVSRD, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
||||||
|
|
||||||
/* VSX move to VSR */
|
/* VSX move to VSR */
|
||||||
{AMTVSR, C_REG, C_NONE, C_NONE, C_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */
|
{AMTVSRD, C_REG, C_NONE, C_NONE, C_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */
|
||||||
{AMTVSR, C_REG, C_REG, C_NONE, C_VSREG, 88, 4, 0},
|
{AMTVSRD, C_REG, C_REG, C_NONE, C_VSREG, 88, 4, 0},
|
||||||
{AMTVSR, C_REG, C_NONE, C_NONE, C_FREG, 88, 4, 0},
|
{AMTVSRD, C_REG, C_NONE, C_NONE, C_FREG, 88, 4, 0},
|
||||||
{AMTVSR, C_REG, C_NONE, C_NONE, C_VREG, 88, 4, 0},
|
{AMTVSRD, C_REG, C_NONE, C_NONE, C_VREG, 88, 4, 0},
|
||||||
|
|
||||||
/* VSX logical */
|
/* VSX logical */
|
||||||
{AXXLAND, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx and, xx3-form */
|
{AXXLAND, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx and, xx3-form */
|
||||||
@ -514,34 +514,34 @@ var optab = []Optab{
|
|||||||
{AXXSEL, C_VSREG, C_VSREG, C_VSREG, C_VSREG, 91, 4, 0}, /* vsx select, xx4-form */
|
{AXXSEL, C_VSREG, C_VSREG, C_VSREG, C_VSREG, 91, 4, 0}, /* vsx select, xx4-form */
|
||||||
|
|
||||||
/* VSX merge */
|
/* VSX merge */
|
||||||
{AXXMRG, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx merge, xx3-form */
|
{AXXMRGHW, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx merge, xx3-form */
|
||||||
|
|
||||||
/* VSX splat */
|
/* VSX splat */
|
||||||
{AXXSPLT, C_VSREG, C_NONE, C_SCON, C_VSREG, 89, 4, 0}, /* vsx splat, xx2-form */
|
{AXXSPLTW, C_VSREG, C_NONE, C_SCON, C_VSREG, 89, 4, 0}, /* vsx splat, xx2-form */
|
||||||
|
|
||||||
/* VSX permute */
|
/* VSX permute */
|
||||||
{AXXPERM, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx permute, xx3-form */
|
{AXXPERM, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx permute, xx3-form */
|
||||||
|
|
||||||
/* VSX shift */
|
/* VSX shift */
|
||||||
{AXXSI, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx shift immediate, xx3-form */
|
{AXXSLDWI, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx shift immediate, xx3-form */
|
||||||
|
|
||||||
/* VSX scalar FP-FP conversion */
|
/* VSX scalar FP-FP conversion */
|
||||||
{AXSCV, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-fp conversion, xx2-form */
|
{AXSCVDPSP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-fp conversion, xx2-form */
|
||||||
|
|
||||||
/* VSX vector FP-FP conversion */
|
/* VSX vector FP-FP conversion */
|
||||||
{AXVCV, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-fp conversion, xx2-form */
|
{AXVCVDPSP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-fp conversion, xx2-form */
|
||||||
|
|
||||||
/* VSX scalar FP-integer conversion */
|
/* VSX scalar FP-integer conversion */
|
||||||
{AXSCVX, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-integer conversion, xx2-form */
|
{AXSCVDPSXDS, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-integer conversion, xx2-form */
|
||||||
|
|
||||||
/* VSX scalar integer-FP conversion */
|
/* VSX scalar integer-FP conversion */
|
||||||
{AXSCVXP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar integer-fp conversion, xx2-form */
|
{AXSCVSXDDP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar integer-fp conversion, xx2-form */
|
||||||
|
|
||||||
/* VSX vector FP-integer conversion */
|
/* VSX vector FP-integer conversion */
|
||||||
{AXVCVX, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-integer conversion, xx2-form */
|
{AXVCVDPSXDS, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-integer conversion, xx2-form */
|
||||||
|
|
||||||
/* VSX vector integer-FP conversion */
|
/* VSX vector integer-FP conversion */
|
||||||
{AXVCVXP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector integer-fp conversion, xx2-form */
|
{AXVCVSXDDP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector integer-fp conversion, xx2-form */
|
||||||
|
|
||||||
/* 64-bit special registers */
|
/* 64-bit special registers */
|
||||||
{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
|
{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
|
||||||
@ -1519,13 +1519,11 @@ func buildop(ctxt *obj.Link) {
|
|||||||
case AVSEL: /* vsel */
|
case AVSEL: /* vsel */
|
||||||
opset(AVSEL, r0)
|
opset(AVSEL, r0)
|
||||||
|
|
||||||
case AVSPLT: /* vspltb, vsplth, vspltw */
|
case AVSPLTB: /* vspltb, vsplth, vspltw */
|
||||||
opset(AVSPLTB, r0)
|
|
||||||
opset(AVSPLTH, r0)
|
opset(AVSPLTH, r0)
|
||||||
opset(AVSPLTW, r0)
|
opset(AVSPLTW, r0)
|
||||||
|
|
||||||
case AVSPLTI: /* vspltisb, vspltish, vspltisw */
|
case AVSPLTISB: /* vspltisb, vspltish, vspltisw */
|
||||||
opset(AVSPLTISB, r0)
|
|
||||||
opset(AVSPLTISH, r0)
|
opset(AVSPLTISH, r0)
|
||||||
opset(AVSPLTISW, r0)
|
opset(AVSPLTISW, r0)
|
||||||
|
|
||||||
@ -1561,28 +1559,25 @@ func buildop(ctxt *obj.Link) {
|
|||||||
case ASTXV: /* stxv */
|
case ASTXV: /* stxv */
|
||||||
opset(ASTXV, r0)
|
opset(ASTXV, r0)
|
||||||
|
|
||||||
case ALXS: /* lxsdx */
|
case ALXSDX: /* lxsdx */
|
||||||
opset(ALXSDX, r0)
|
opset(ALXSDX, r0)
|
||||||
|
|
||||||
case ASTXS: /* stxsdx */
|
case ASTXSDX: /* stxsdx */
|
||||||
opset(ASTXSDX, r0)
|
opset(ASTXSDX, r0)
|
||||||
|
|
||||||
case ALXSI: /* lxsiwax, lxsiwzx */
|
case ALXSIWAX: /* lxsiwax, lxsiwzx */
|
||||||
opset(ALXSIWAX, r0)
|
|
||||||
opset(ALXSIWZX, r0)
|
opset(ALXSIWZX, r0)
|
||||||
|
|
||||||
case ASTXSI: /* stxsiwx */
|
case ASTXSIWX: /* stxsiwx */
|
||||||
opset(ASTXSIWX, r0)
|
opset(ASTXSIWX, r0)
|
||||||
|
|
||||||
case AMFVSR: /* mfvsrd, mfvsrwz (and extended mnemonics), mfvsrld */
|
case AMFVSRD: /* mfvsrd, mfvsrwz (and extended mnemonics), mfvsrld */
|
||||||
opset(AMFVSRD, r0)
|
|
||||||
opset(AMFFPRD, r0)
|
opset(AMFFPRD, r0)
|
||||||
opset(AMFVRD, r0)
|
opset(AMFVRD, r0)
|
||||||
opset(AMFVSRWZ, r0)
|
opset(AMFVSRWZ, r0)
|
||||||
opset(AMFVSRLD, r0)
|
opset(AMFVSRLD, r0)
|
||||||
|
|
||||||
case AMTVSR: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics), mtvsrdd, mtvsrws */
|
case AMTVSRD: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics), mtvsrdd, mtvsrws */
|
||||||
opset(AMTVSRD, r0)
|
|
||||||
opset(AMTFPRD, r0)
|
opset(AMTFPRD, r0)
|
||||||
opset(AMTVRD, r0)
|
opset(AMTVRD, r0)
|
||||||
opset(AMTVSRWA, r0)
|
opset(AMTVSRWA, r0)
|
||||||
@ -1591,7 +1586,6 @@ func buildop(ctxt *obj.Link) {
|
|||||||
opset(AMTVSRWS, r0)
|
opset(AMTVSRWS, r0)
|
||||||
|
|
||||||
case AXXLAND: /* xxland, xxlandc, xxleqv, xxlnand */
|
case AXXLAND: /* xxland, xxlandc, xxleqv, xxlnand */
|
||||||
opset(AXXLANDQ, r0)
|
|
||||||
opset(AXXLANDC, r0)
|
opset(AXXLANDC, r0)
|
||||||
opset(AXXLEQV, r0)
|
opset(AXXLEQV, r0)
|
||||||
opset(AXXLNAND, r0)
|
opset(AXXLNAND, r0)
|
||||||
@ -1605,42 +1599,38 @@ func buildop(ctxt *obj.Link) {
|
|||||||
case AXXSEL: /* xxsel */
|
case AXXSEL: /* xxsel */
|
||||||
opset(AXXSEL, r0)
|
opset(AXXSEL, r0)
|
||||||
|
|
||||||
case AXXMRG: /* xxmrghw, xxmrglw */
|
case AXXMRGHW: /* xxmrghw, xxmrglw */
|
||||||
opset(AXXMRGHW, r0)
|
|
||||||
opset(AXXMRGLW, r0)
|
opset(AXXMRGLW, r0)
|
||||||
|
|
||||||
case AXXSPLT: /* xxspltw */
|
case AXXSPLTW: /* xxspltw */
|
||||||
opset(AXXSPLTW, r0)
|
opset(AXXSPLTW, r0)
|
||||||
|
|
||||||
case AXXPERM: /* xxpermdi */
|
case AXXPERM: /* xxpermdi */
|
||||||
opset(AXXPERMDI, r0)
|
opset(AXXPERM, r0)
|
||||||
|
|
||||||
case AXXSI: /* xxsldwi */
|
case AXXSLDWI: /* xxsldwi */
|
||||||
|
opset(AXXPERMDI, r0)
|
||||||
opset(AXXSLDWI, r0)
|
opset(AXXSLDWI, r0)
|
||||||
|
|
||||||
case AXSCV: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
|
case AXSCVDPSP: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
|
||||||
opset(AXSCVDPSP, r0)
|
|
||||||
opset(AXSCVSPDP, r0)
|
opset(AXSCVSPDP, r0)
|
||||||
opset(AXSCVDPSPN, r0)
|
opset(AXSCVDPSPN, r0)
|
||||||
opset(AXSCVSPDPN, r0)
|
opset(AXSCVSPDPN, r0)
|
||||||
|
|
||||||
case AXVCV: /* xvcvdpsp, xvcvspdp */
|
case AXVCVDPSP: /* xvcvdpsp, xvcvspdp */
|
||||||
opset(AXVCVDPSP, r0)
|
|
||||||
opset(AXVCVSPDP, r0)
|
opset(AXVCVSPDP, r0)
|
||||||
|
|
||||||
case AXSCVX: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
|
case AXSCVDPSXDS: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
|
||||||
opset(AXSCVDPSXDS, r0)
|
|
||||||
opset(AXSCVDPSXWS, r0)
|
opset(AXSCVDPSXWS, r0)
|
||||||
opset(AXSCVDPUXDS, r0)
|
opset(AXSCVDPUXDS, r0)
|
||||||
opset(AXSCVDPUXWS, r0)
|
opset(AXSCVDPUXWS, r0)
|
||||||
|
|
||||||
case AXSCVXP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
|
case AXSCVSXDDP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
|
||||||
opset(AXSCVSXDDP, r0)
|
|
||||||
opset(AXSCVUXDDP, r0)
|
opset(AXSCVUXDDP, r0)
|
||||||
opset(AXSCVSXDSP, r0)
|
opset(AXSCVSXDSP, r0)
|
||||||
opset(AXSCVUXDSP, r0)
|
opset(AXSCVUXDSP, r0)
|
||||||
|
|
||||||
case AXVCVX: /* xvcvdpsxds, xvcvdpsxws, xvcvdpuxds, xvcvdpuxws, xvcvspsxds, xvcvspsxws, xvcvspuxds, xvcvspuxws */
|
case AXVCVDPSXDS: /* xvcvdpsxds, xvcvdpsxws, xvcvdpuxds, xvcvdpuxws, xvcvspsxds, xvcvspsxws, xvcvspuxds, xvcvspuxws */
|
||||||
opset(AXVCVDPSXDS, r0)
|
opset(AXVCVDPSXDS, r0)
|
||||||
opset(AXVCVDPSXWS, r0)
|
opset(AXVCVDPSXWS, r0)
|
||||||
opset(AXVCVDPUXDS, r0)
|
opset(AXVCVDPUXDS, r0)
|
||||||
@ -1650,8 +1640,7 @@ func buildop(ctxt *obj.Link) {
|
|||||||
opset(AXVCVSPUXDS, r0)
|
opset(AXVCVSPUXDS, r0)
|
||||||
opset(AXVCVSPUXWS, r0)
|
opset(AXVCVSPUXWS, r0)
|
||||||
|
|
||||||
case AXVCVXP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
|
case AXVCVSXDDP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
|
||||||
opset(AXVCVSXDDP, r0)
|
|
||||||
opset(AXVCVSXWDP, r0)
|
opset(AXVCVSXWDP, r0)
|
||||||
opset(AXVCVUXDDP, r0)
|
opset(AXVCVUXDDP, r0)
|
||||||
opset(AXVCVUXWDP, r0)
|
opset(AXVCVUXWDP, r0)
|
||||||
@ -4616,7 +4605,7 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
|
|||||||
case AMTVSRWS:
|
case AMTVSRWS:
|
||||||
return OPVXX1(31, 403, 0) /* mtvsrws - v3.00 */
|
return OPVXX1(31, 403, 0) /* mtvsrws - v3.00 */
|
||||||
|
|
||||||
case AXXLANDQ:
|
case AXXLAND:
|
||||||
return OPVXX3(60, 130, 0) /* xxland - v2.06 */
|
return OPVXX3(60, 130, 0) /* xxland - v2.06 */
|
||||||
case AXXLANDC:
|
case AXXLANDC:
|
||||||
return OPVXX3(60, 138, 0) /* xxlandc - v2.06 */
|
return OPVXX3(60, 138, 0) /* xxlandc - v2.06 */
|
||||||
@ -4645,6 +4634,8 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
|
|||||||
case AXXSPLTW:
|
case AXXSPLTW:
|
||||||
return OPVXX2(60, 164, 0) /* xxspltw - v2.06 */
|
return OPVXX2(60, 164, 0) /* xxspltw - v2.06 */
|
||||||
|
|
||||||
|
case AXXPERM:
|
||||||
|
return OPVXX3(60, 26, 0) /* xxperm - v2.06 */
|
||||||
case AXXPERMDI:
|
case AXXPERMDI:
|
||||||
return OPVXX3(60, 10, 0) /* xxpermdi - v2.06 */
|
return OPVXX3(60, 10, 0) /* xxpermdi - v2.06 */
|
||||||
|
|
||||||
|
@ -175,6 +175,11 @@ func (fc *FileCache) Line(filename string, line int) ([]byte, error) {
|
|||||||
fc.files.MoveToFront(e)
|
fc.files.MoveToFront(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// because //line directives can be out-of-range. (#36683)
|
||||||
|
if line-1 >= len(cf.Lines) || line-1 < 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
return cf.Lines[line-1], nil
|
return cf.Lines[line-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1239,6 +1239,7 @@ func TestPackageNameAttr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rdr := d.Reader()
|
rdr := d.Reader()
|
||||||
|
runtimeUnitSeen := false
|
||||||
for {
|
for {
|
||||||
e, err := rdr.Next()
|
e, err := rdr.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1254,11 +1255,25 @@ func TestPackageNameAttr(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_, ok := e.Val(dwarfAttrGoPackageName).(string)
|
pn, ok := e.Val(dwarfAttrGoPackageName).(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
name, _ := e.Val(dwarf.AttrName).(string)
|
name, _ := e.Val(dwarf.AttrName).(string)
|
||||||
t.Errorf("found compile unit without package name: %s", name)
|
t.Errorf("found compile unit without package name: %s", name)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if pn == "" {
|
||||||
|
name, _ := e.Val(dwarf.AttrName).(string)
|
||||||
|
t.Errorf("found compile unit with empty package name: %s", name)
|
||||||
|
} else {
|
||||||
|
if pn == "runtime" {
|
||||||
|
runtimeUnitSeen = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something is wrong if there's no runtime compilation unit.
|
||||||
|
if !runtimeUnitSeen {
|
||||||
|
t.Errorf("no package name for runtime unit")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +58,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IMAGE_FILE_MACHINE_I386 = 0x14c
|
|
||||||
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
|
||||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
|
||||||
IMAGE_FILE_MACHINE_ARMNT = 0x1c4
|
|
||||||
IMAGE_FILE_RELOCS_STRIPPED = 0x0001
|
|
||||||
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002
|
|
||||||
IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004
|
|
||||||
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020
|
|
||||||
IMAGE_FILE_32BIT_MACHINE = 0x0100
|
|
||||||
IMAGE_FILE_DEBUG_STRIPPED = 0x0200
|
|
||||||
IMAGE_SCN_CNT_CODE = 0x00000020
|
IMAGE_SCN_CNT_CODE = 0x00000020
|
||||||
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
|
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
|
||||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
||||||
@ -77,28 +67,6 @@ const (
|
|||||||
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
|
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
|
||||||
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
|
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
|
||||||
IMAGE_SCN_ALIGN_32BYTES = 0x600000
|
IMAGE_SCN_ALIGN_32BYTES = 0x600000
|
||||||
IMAGE_DIRECTORY_ENTRY_EXPORT = 0
|
|
||||||
IMAGE_DIRECTORY_ENTRY_IMPORT = 1
|
|
||||||
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
|
|
||||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
|
|
||||||
IMAGE_DIRECTORY_ENTRY_SECURITY = 4
|
|
||||||
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
|
|
||||||
IMAGE_DIRECTORY_ENTRY_DEBUG = 6
|
|
||||||
IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7
|
|
||||||
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7
|
|
||||||
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
|
|
||||||
IMAGE_DIRECTORY_ENTRY_TLS = 9
|
|
||||||
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
|
|
||||||
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
|
|
||||||
IMAGE_DIRECTORY_ENTRY_IAT = 12
|
|
||||||
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
|
|
||||||
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
|
|
||||||
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
|
||||||
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
|
|
||||||
IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
|
|
||||||
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040
|
|
||||||
IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100
|
|
||||||
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(crawshaw): add these constants to debug/pe.
|
// TODO(crawshaw): add these constants to debug/pe.
|
||||||
@ -762,11 +730,11 @@ func (f *peFile) writeFileHeader(ctxt *Link) {
|
|||||||
default:
|
default:
|
||||||
Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
|
Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
|
||||||
case sys.AMD64:
|
case sys.AMD64:
|
||||||
fh.Machine = IMAGE_FILE_MACHINE_AMD64
|
fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
|
||||||
case sys.I386:
|
case sys.I386:
|
||||||
fh.Machine = IMAGE_FILE_MACHINE_I386
|
fh.Machine = pe.IMAGE_FILE_MACHINE_I386
|
||||||
case sys.ARM:
|
case sys.ARM:
|
||||||
fh.Machine = IMAGE_FILE_MACHINE_ARMNT
|
fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
|
||||||
}
|
}
|
||||||
|
|
||||||
fh.NumberOfSections = uint16(len(f.sections))
|
fh.NumberOfSections = uint16(len(f.sections))
|
||||||
@ -776,24 +744,24 @@ func (f *peFile) writeFileHeader(ctxt *Link) {
|
|||||||
fh.TimeDateStamp = 0
|
fh.TimeDateStamp = 0
|
||||||
|
|
||||||
if ctxt.LinkMode == LinkExternal {
|
if ctxt.LinkMode == LinkExternal {
|
||||||
fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
|
fh.Characteristics = pe.IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||||
} else {
|
} else {
|
||||||
fh.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
|
fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE | pe.IMAGE_FILE_DEBUG_STRIPPED
|
||||||
switch ctxt.Arch.Family {
|
switch ctxt.Arch.Family {
|
||||||
case sys.AMD64, sys.I386:
|
case sys.AMD64, sys.I386:
|
||||||
if ctxt.BuildMode != BuildModePIE {
|
if ctxt.BuildMode != BuildModePIE {
|
||||||
fh.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED
|
fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pe64 != 0 {
|
if pe64 != 0 {
|
||||||
var oh64 pe.OptionalHeader64
|
var oh64 pe.OptionalHeader64
|
||||||
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
|
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
|
||||||
fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
|
fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
|
||||||
} else {
|
} else {
|
||||||
var oh pe.OptionalHeader32
|
var oh pe.OptionalHeader32
|
||||||
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
|
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
|
||||||
fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
|
fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
|
||||||
}
|
}
|
||||||
|
|
||||||
fh.PointerToSymbolTable = uint32(f.symtabOffset)
|
fh.PointerToSymbolTable = uint32(f.symtabOffset)
|
||||||
@ -854,36 +822,36 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
|
|||||||
oh64.SizeOfHeaders = uint32(PEFILEHEADR)
|
oh64.SizeOfHeaders = uint32(PEFILEHEADR)
|
||||||
oh.SizeOfHeaders = uint32(PEFILEHEADR)
|
oh.SizeOfHeaders = uint32(PEFILEHEADR)
|
||||||
if windowsgui {
|
if windowsgui {
|
||||||
oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||||
oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||||
} else {
|
} else {
|
||||||
oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
|
oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||||
oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
|
oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
|
// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
|
||||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||||
|
|
||||||
// Enable DEP
|
// Enable DEP
|
||||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||||
|
|
||||||
// The DLL can be relocated at load time.
|
// The DLL can be relocated at load time.
|
||||||
switch ctxt.Arch.Family {
|
switch ctxt.Arch.Family {
|
||||||
case sys.AMD64, sys.I386:
|
case sys.AMD64, sys.I386:
|
||||||
if ctxt.BuildMode == BuildModePIE {
|
if ctxt.BuildMode == BuildModePIE {
|
||||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||||
}
|
}
|
||||||
case sys.ARM:
|
case sys.ARM:
|
||||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image can handle a high entropy 64-bit virtual address space.
|
// Image can handle a high entropy 64-bit virtual address space.
|
||||||
if ctxt.BuildMode == BuildModePIE {
|
if ctxt.BuildMode == BuildModePIE {
|
||||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
|
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable stack growth as we don't want Windows to
|
// Disable stack growth as we don't want Windows to
|
||||||
@ -1229,10 +1197,10 @@ func addimports(ctxt *Link, datsect *peSection) {
|
|||||||
out.Write32(0)
|
out.Write32(0)
|
||||||
|
|
||||||
// update data directory
|
// update data directory
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
|
||||||
|
|
||||||
out.SeekSet(endoff)
|
out.SeekSet(endoff)
|
||||||
}
|
}
|
||||||
@ -1272,8 +1240,8 @@ func addexports(ctxt *Link) {
|
|||||||
sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
|
sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
|
||||||
sect.checkOffset(ctxt.Out.Offset())
|
sect.checkOffset(ctxt.Out.Offset())
|
||||||
va := int(sect.virtualAddress)
|
va := int(sect.virtualAddress)
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
|
||||||
|
|
||||||
vaName := va + binary.Size(&e) + nexport*4
|
vaName := va + binary.Size(&e) + nexport*4
|
||||||
vaAddr := va + binary.Size(&e)
|
vaAddr := va + binary.Size(&e)
|
||||||
@ -1481,8 +1449,8 @@ func addPEBaseReloc(ctxt *Link) {
|
|||||||
rsect.checkOffset(startoff)
|
rsect.checkOffset(startoff)
|
||||||
rsect.pad(ctxt.Out, uint32(size))
|
rsect.pad(ctxt.Out, uint32(size))
|
||||||
|
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctxt *Link) dope() {
|
func (ctxt *Link) dope() {
|
||||||
@ -1528,9 +1496,9 @@ func addpersrc(ctxt *Link) {
|
|||||||
h.pad(ctxt.Out, uint32(size))
|
h.pad(ctxt.Out, uint32(size))
|
||||||
|
|
||||||
// update data directory
|
// update data directory
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
|
||||||
|
|
||||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
|
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func Asmbpe(ctxt *Link) {
|
func Asmbpe(ctxt *Link) {
|
||||||
|
@ -106,8 +106,11 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
|
|||||||
hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
|
hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
|
||||||
args := []string{"build", "-o", hello}
|
args := []string{"build", "-o", hello}
|
||||||
args = append(args, flags...)
|
args = append(args, flags...)
|
||||||
args = append(args, "testdata/fmthello.go")
|
args = append(args, "fmthello.go")
|
||||||
out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
|
cmd := exec.Command(testenv.GoToolPath(t), args...)
|
||||||
|
cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
|
||||||
|
t.Logf("Running %v", cmd.Args)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("go build fmthello.go: %v\n%s", err, out)
|
t.Fatalf("go build fmthello.go: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
@ -139,7 +142,11 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
|
|||||||
args = append([]string{"-S"}, args...)
|
args = append([]string{"-S"}, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err = exec.Command(exe, args...).CombinedOutput()
|
cmd = exec.Command(exe, args...)
|
||||||
|
cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
t.Logf("Running %v", cmd.Args)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
|
t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
|
2
src/cmd/objdump/testdata/fmthello.go
vendored
2
src/cmd/objdump/testdata/fmthello.go
vendored
@ -5,6 +5,8 @@ import "fmt"
|
|||||||
func main() {
|
func main() {
|
||||||
Println("hello, world")
|
Println("hello, world")
|
||||||
if flag {
|
if flag {
|
||||||
|
//line fmthello.go:999999
|
||||||
|
Println("bad line")
|
||||||
for {
|
for {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/cmd/vendor/github.com/google/pprof/internal/report/report.go
generated
vendored
28
src/cmd/vendor/github.com/google/pprof/internal/report/report.go
generated
vendored
@ -834,10 +834,19 @@ func printTraces(w io.Writer, rpt *Report) error {
|
|||||||
|
|
||||||
_, locations := graph.CreateNodes(prof, &graph.Options{})
|
_, locations := graph.CreateNodes(prof, &graph.Options{})
|
||||||
for _, sample := range prof.Sample {
|
for _, sample := range prof.Sample {
|
||||||
var stack graph.Nodes
|
type stk struct {
|
||||||
|
*graph.NodeInfo
|
||||||
|
inline bool
|
||||||
|
}
|
||||||
|
var stack []stk
|
||||||
for _, loc := range sample.Location {
|
for _, loc := range sample.Location {
|
||||||
id := loc.ID
|
nodes := locations[loc.ID]
|
||||||
stack = append(stack, locations[id]...)
|
for i, n := range nodes {
|
||||||
|
// The inline flag may be inaccurate if 'show' or 'hide' filter is
|
||||||
|
// used. See https://github.com/google/pprof/issues/511.
|
||||||
|
inline := i != len(nodes)-1
|
||||||
|
stack = append(stack, stk{&n.Info, inline})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stack) == 0 {
|
if len(stack) == 0 {
|
||||||
@ -875,10 +884,15 @@ func printTraces(w io.Writer, rpt *Report) error {
|
|||||||
if d != 0 {
|
if d != 0 {
|
||||||
v = v / d
|
v = v / d
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "%10s %s\n",
|
for i, s := range stack {
|
||||||
rpt.formatValue(v), stack[0].Info.PrintableName())
|
var vs, inline string
|
||||||
for _, s := range stack[1:] {
|
if i == 0 {
|
||||||
fmt.Fprintf(w, "%10s %s\n", "", s.Info.PrintableName())
|
vs = rpt.formatValue(v)
|
||||||
|
}
|
||||||
|
if s.inline {
|
||||||
|
inline = " (inline)"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%10s %s%s\n", vs, s.PrintableName(), inline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintln(w, separator)
|
fmt.Fprintln(w, separator)
|
||||||
|
7
src/cmd/vendor/github.com/google/pprof/profile/proto.go
generated
vendored
7
src/cmd/vendor/github.com/google/pprof/profile/proto.go
generated
vendored
@ -33,7 +33,10 @@
|
|||||||
|
|
||||||
package profile
|
package profile
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type buffer struct {
|
type buffer struct {
|
||||||
field int // field tag
|
field int // field tag
|
||||||
@ -235,7 +238,7 @@ func decodeField(b *buffer, data []byte) ([]byte, error) {
|
|||||||
b.u64 = uint64(le32(data[:4]))
|
b.u64 = uint64(le32(data[:4]))
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unknown wire type: " + string(b.typ))
|
return nil, fmt.Errorf("unknown wire type: %d", b.typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
|
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
@ -51,7 +51,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||||||
return // not enough arguments, e.g. called with return values of another function
|
return // not enough arguments, e.g. called with return values of another function
|
||||||
}
|
}
|
||||||
if fn.FullName() == "errors.As" && !pointerToInterfaceOrError(pass, call.Args[1]) {
|
if fn.FullName() == "errors.As" && !pointerToInterfaceOrError(pass, call.Args[1]) {
|
||||||
pass.ReportRangef(call, "second argument to errors.As must be a pointer to an interface or a type implementing error")
|
pass.ReportRangef(call, "second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
101
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
generated
vendored
Normal file
101
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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 ifaceassert defines an Analyzer that flags
|
||||||
|
// impossible interface-interface type assertions.
|
||||||
|
package ifaceassert
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Doc = `detect impossible interface-to-interface type assertions
|
||||||
|
|
||||||
|
This checker flags type assertions v.(T) and corresponding type-switch cases
|
||||||
|
in which the static type V of v is an interface that cannot possibly implement
|
||||||
|
the target interface T. This occurs when V and T contain methods with the same
|
||||||
|
name but different signatures. Example:
|
||||||
|
|
||||||
|
var v interface {
|
||||||
|
Read()
|
||||||
|
}
|
||||||
|
_ = v.(io.Reader)
|
||||||
|
|
||||||
|
The Read method in v has a different signature than the Read method in
|
||||||
|
io.Reader, so this assertion cannot succeed.
|
||||||
|
`
|
||||||
|
|
||||||
|
var Analyzer = &analysis.Analyzer{
|
||||||
|
Name: "ifaceassert",
|
||||||
|
Doc: Doc,
|
||||||
|
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||||
|
Run: run,
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertableTo checks whether interface v can be asserted into t. It returns
|
||||||
|
// nil on success, or the first conflicting method on failure.
|
||||||
|
func assertableTo(v, t types.Type) *types.Func {
|
||||||
|
// ensure that v and t are interfaces
|
||||||
|
V, _ := v.Underlying().(*types.Interface)
|
||||||
|
T, _ := t.Underlying().(*types.Interface)
|
||||||
|
if V == nil || T == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if f, wrongType := types.MissingMethod(V, T, false); wrongType {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||||
|
nodeFilter := []ast.Node{
|
||||||
|
(*ast.TypeAssertExpr)(nil),
|
||||||
|
(*ast.TypeSwitchStmt)(nil),
|
||||||
|
}
|
||||||
|
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||||
|
var (
|
||||||
|
assert *ast.TypeAssertExpr // v.(T) expression
|
||||||
|
targets []ast.Expr // interfaces T in v.(T)
|
||||||
|
)
|
||||||
|
switch n := n.(type) {
|
||||||
|
case *ast.TypeAssertExpr:
|
||||||
|
// take care of v.(type) in *ast.TypeSwitchStmt
|
||||||
|
if n.Type == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert = n
|
||||||
|
targets = append(targets, n.Type)
|
||||||
|
case *ast.TypeSwitchStmt:
|
||||||
|
// retrieve type assertion from type switch's 'assign' field
|
||||||
|
switch t := n.Assign.(type) {
|
||||||
|
case *ast.ExprStmt:
|
||||||
|
assert = t.X.(*ast.TypeAssertExpr)
|
||||||
|
case *ast.AssignStmt:
|
||||||
|
assert = t.Rhs[0].(*ast.TypeAssertExpr)
|
||||||
|
}
|
||||||
|
// gather target types from case clauses
|
||||||
|
for _, c := range n.Body.List {
|
||||||
|
targets = append(targets, c.(*ast.CaseClause).List...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
V := pass.TypesInfo.TypeOf(assert.X)
|
||||||
|
for _, target := range targets {
|
||||||
|
T := pass.TypesInfo.TypeOf(target)
|
||||||
|
if f := assertableTo(V, T); f != nil {
|
||||||
|
pass.Reportf(
|
||||||
|
target.Pos(),
|
||||||
|
"impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)",
|
||||||
|
V, T, f.Name(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil, nil
|
||||||
|
}
|
126
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
Normal file
126
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// 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 stringintconv defines an Analyzer that flags type conversions
|
||||||
|
// from integers to strings.
|
||||||
|
package stringintconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Doc = `check for string(int) conversions
|
||||||
|
|
||||||
|
This checker flags conversions of the form string(x) where x is an integer
|
||||||
|
(but not byte or rune) type. Such conversions are discouraged because they
|
||||||
|
return the UTF-8 representation of the Unicode code point x, and not a decimal
|
||||||
|
string representation of x as one might expect. Furthermore, if x denotes an
|
||||||
|
invalid code point, the conversion cannot be statically rejected.
|
||||||
|
|
||||||
|
For conversions that intend on using the code point, consider replacing them
|
||||||
|
with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the
|
||||||
|
string representation of the value in the desired base.
|
||||||
|
`
|
||||||
|
|
||||||
|
var Analyzer = &analysis.Analyzer{
|
||||||
|
Name: "stringintconv",
|
||||||
|
Doc: Doc,
|
||||||
|
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||||
|
Run: run,
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeName(typ types.Type) string {
|
||||||
|
if v, _ := typ.(interface{ Name() string }); v != nil {
|
||||||
|
return v.Name()
|
||||||
|
}
|
||||||
|
if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil {
|
||||||
|
return v.Obj().Name()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Retrieve target type name.
|
||||||
|
var tname *types.TypeName
|
||||||
|
switch fun := call.Fun.(type) {
|
||||||
|
case *ast.Ident:
|
||||||
|
tname, _ = pass.TypesInfo.Uses[fun].(*types.TypeName)
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
tname, _ = pass.TypesInfo.Uses[fun.Sel].(*types.TypeName)
|
||||||
|
}
|
||||||
|
if tname == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target := tname.Name()
|
||||||
|
|
||||||
|
// Check that target type T in T(v) has an underlying type of string.
|
||||||
|
T, _ := tname.Type().Underlying().(*types.Basic)
|
||||||
|
if T == nil || T.Kind() != types.String {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s := T.Name(); target != s {
|
||||||
|
target += " (" + s + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that type V of v has an underlying integral type that is not byte or rune.
|
||||||
|
if len(call.Args) != 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := call.Args[0]
|
||||||
|
vtyp := pass.TypesInfo.TypeOf(v)
|
||||||
|
V, _ := vtyp.Underlying().(*types.Basic)
|
||||||
|
if V == nil || V.Info()&types.IsInteger == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch V.Kind() {
|
||||||
|
case types.Byte, types.Rune, types.UntypedRune:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve source type name.
|
||||||
|
source := typeName(vtyp)
|
||||||
|
if source == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s := V.Name(); source != s {
|
||||||
|
source += " (" + s + ")"
|
||||||
|
}
|
||||||
|
diag := analysis.Diagnostic{
|
||||||
|
Pos: n.Pos(),
|
||||||
|
Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune", source, target),
|
||||||
|
SuggestedFixes: []analysis.SuggestedFix{
|
||||||
|
{
|
||||||
|
Message: "Did you mean to convert a rune to a string?",
|
||||||
|
TextEdits: []analysis.TextEdit{
|
||||||
|
{
|
||||||
|
Pos: v.Pos(),
|
||||||
|
End: v.Pos(),
|
||||||
|
NewText: []byte("rune("),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Pos: v.End(),
|
||||||
|
End: v.End(),
|
||||||
|
NewText: []byte(")"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pass.Report(diag)
|
||||||
|
})
|
||||||
|
return nil, nil
|
||||||
|
}
|
7
src/cmd/vendor/modules.txt
vendored
7
src/cmd/vendor/modules.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
# github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12
|
# github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
|
||||||
## explicit
|
## explicit
|
||||||
github.com/google/pprof/driver
|
github.com/google/pprof/driver
|
||||||
github.com/google/pprof/internal/binutils
|
github.com/google/pprof/internal/binutils
|
||||||
@ -43,7 +43,7 @@ golang.org/x/mod/zip
|
|||||||
## explicit
|
## explicit
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
# golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d
|
# golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/tools/go/analysis
|
golang.org/x/tools/go/analysis
|
||||||
golang.org/x/tools/go/analysis/internal/analysisflags
|
golang.org/x/tools/go/analysis/internal/analysisflags
|
||||||
@ -59,6 +59,7 @@ golang.org/x/tools/go/analysis/passes/copylock
|
|||||||
golang.org/x/tools/go/analysis/passes/ctrlflow
|
golang.org/x/tools/go/analysis/passes/ctrlflow
|
||||||
golang.org/x/tools/go/analysis/passes/errorsas
|
golang.org/x/tools/go/analysis/passes/errorsas
|
||||||
golang.org/x/tools/go/analysis/passes/httpresponse
|
golang.org/x/tools/go/analysis/passes/httpresponse
|
||||||
|
golang.org/x/tools/go/analysis/passes/ifaceassert
|
||||||
golang.org/x/tools/go/analysis/passes/inspect
|
golang.org/x/tools/go/analysis/passes/inspect
|
||||||
golang.org/x/tools/go/analysis/passes/internal/analysisutil
|
golang.org/x/tools/go/analysis/passes/internal/analysisutil
|
||||||
golang.org/x/tools/go/analysis/passes/loopclosure
|
golang.org/x/tools/go/analysis/passes/loopclosure
|
||||||
@ -67,6 +68,7 @@ golang.org/x/tools/go/analysis/passes/nilfunc
|
|||||||
golang.org/x/tools/go/analysis/passes/printf
|
golang.org/x/tools/go/analysis/passes/printf
|
||||||
golang.org/x/tools/go/analysis/passes/shift
|
golang.org/x/tools/go/analysis/passes/shift
|
||||||
golang.org/x/tools/go/analysis/passes/stdmethods
|
golang.org/x/tools/go/analysis/passes/stdmethods
|
||||||
|
golang.org/x/tools/go/analysis/passes/stringintconv
|
||||||
golang.org/x/tools/go/analysis/passes/structtag
|
golang.org/x/tools/go/analysis/passes/structtag
|
||||||
golang.org/x/tools/go/analysis/passes/tests
|
golang.org/x/tools/go/analysis/passes/tests
|
||||||
golang.org/x/tools/go/analysis/passes/unmarshal
|
golang.org/x/tools/go/analysis/passes/unmarshal
|
||||||
@ -80,6 +82,5 @@ golang.org/x/tools/go/cfg
|
|||||||
golang.org/x/tools/go/types/objectpath
|
golang.org/x/tools/go/types/objectpath
|
||||||
golang.org/x/tools/go/types/typeutil
|
golang.org/x/tools/go/types/typeutil
|
||||||
# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||||
## explicit
|
|
||||||
golang.org/x/xerrors
|
golang.org/x/xerrors
|
||||||
golang.org/x/xerrors/internal
|
golang.org/x/xerrors/internal
|
||||||
|
@ -15,12 +15,14 @@ import (
|
|||||||
"golang.org/x/tools/go/analysis/passes/copylock"
|
"golang.org/x/tools/go/analysis/passes/copylock"
|
||||||
"golang.org/x/tools/go/analysis/passes/errorsas"
|
"golang.org/x/tools/go/analysis/passes/errorsas"
|
||||||
"golang.org/x/tools/go/analysis/passes/httpresponse"
|
"golang.org/x/tools/go/analysis/passes/httpresponse"
|
||||||
|
"golang.org/x/tools/go/analysis/passes/ifaceassert"
|
||||||
"golang.org/x/tools/go/analysis/passes/loopclosure"
|
"golang.org/x/tools/go/analysis/passes/loopclosure"
|
||||||
"golang.org/x/tools/go/analysis/passes/lostcancel"
|
"golang.org/x/tools/go/analysis/passes/lostcancel"
|
||||||
"golang.org/x/tools/go/analysis/passes/nilfunc"
|
"golang.org/x/tools/go/analysis/passes/nilfunc"
|
||||||
"golang.org/x/tools/go/analysis/passes/printf"
|
"golang.org/x/tools/go/analysis/passes/printf"
|
||||||
"golang.org/x/tools/go/analysis/passes/shift"
|
"golang.org/x/tools/go/analysis/passes/shift"
|
||||||
"golang.org/x/tools/go/analysis/passes/stdmethods"
|
"golang.org/x/tools/go/analysis/passes/stdmethods"
|
||||||
|
"golang.org/x/tools/go/analysis/passes/stringintconv"
|
||||||
"golang.org/x/tools/go/analysis/passes/structtag"
|
"golang.org/x/tools/go/analysis/passes/structtag"
|
||||||
"golang.org/x/tools/go/analysis/passes/tests"
|
"golang.org/x/tools/go/analysis/passes/tests"
|
||||||
"golang.org/x/tools/go/analysis/passes/unmarshal"
|
"golang.org/x/tools/go/analysis/passes/unmarshal"
|
||||||
@ -43,12 +45,14 @@ func main() {
|
|||||||
copylock.Analyzer,
|
copylock.Analyzer,
|
||||||
errorsas.Analyzer,
|
errorsas.Analyzer,
|
||||||
httpresponse.Analyzer,
|
httpresponse.Analyzer,
|
||||||
|
ifaceassert.Analyzer,
|
||||||
loopclosure.Analyzer,
|
loopclosure.Analyzer,
|
||||||
lostcancel.Analyzer,
|
lostcancel.Analyzer,
|
||||||
nilfunc.Analyzer,
|
nilfunc.Analyzer,
|
||||||
printf.Analyzer,
|
printf.Analyzer,
|
||||||
shift.Analyzer,
|
shift.Analyzer,
|
||||||
stdmethods.Analyzer,
|
stdmethods.Analyzer,
|
||||||
|
stringintconv.Analyzer,
|
||||||
structtag.Analyzer,
|
structtag.Analyzer,
|
||||||
tests.Analyzer,
|
tests.Analyzer,
|
||||||
unmarshal.Analyzer,
|
unmarshal.Analyzer,
|
||||||
|
@ -106,7 +106,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
|
|||||||
case Ed25519:
|
case Ed25519:
|
||||||
sigType = signatureEd25519
|
sigType = signatureEd25519
|
||||||
default:
|
default:
|
||||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
|
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
|
||||||
}
|
}
|
||||||
switch signatureAlgorithm {
|
switch signatureAlgorithm {
|
||||||
case PKCS1WithSHA1, ECDSAWithSHA1:
|
case PKCS1WithSHA1, ECDSAWithSHA1:
|
||||||
@ -120,7 +120,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
|
|||||||
case Ed25519:
|
case Ed25519:
|
||||||
hash = directSigning
|
hash = directSigning
|
||||||
default:
|
default:
|
||||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
|
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
|
||||||
}
|
}
|
||||||
return sigType, hash, nil
|
return sigType, hash, nil
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func TestSignatureSelection(t *testing.T) {
|
|||||||
t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
|
t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
|
||||||
}
|
}
|
||||||
if test.expectedSigAlg != sigAlg {
|
if test.expectedSigAlg != sigAlg {
|
||||||
t.Errorf("test[%d]: expected signature scheme %#x, got %#x", testNo, test.expectedSigAlg, sigAlg)
|
t.Errorf("test[%d]: expected signature scheme %v, got %v", testNo, test.expectedSigAlg, sigAlg)
|
||||||
}
|
}
|
||||||
sigType, hashFunc, err := typeAndHashFromSignatureScheme(sigAlg)
|
sigType, hashFunc, err := typeAndHashFromSignatureScheme(sigAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +115,7 @@ func TestSignatureSelection(t *testing.T) {
|
|||||||
for testNo, test := range badTests {
|
for testNo, test := range badTests {
|
||||||
sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
|
sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test[%d]: unexpected success, got %#x", testNo, sigAlg)
|
t.Errorf("test[%d]: unexpected success, got %v", testNo, sigAlg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ func TestLegacyTypeAndHash(t *testing.T) {
|
|||||||
t.Errorf("RSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
t.Errorf("RSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
||||||
}
|
}
|
||||||
if expectedHashFunc := crypto.MD5SHA1; expectedHashFunc != hashFunc {
|
if expectedHashFunc := crypto.MD5SHA1; expectedHashFunc != hashFunc {
|
||||||
t.Errorf("RSA: expected hash %#x, got %#x", expectedHashFunc, sigType)
|
t.Errorf("RSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
sigType, hashFunc, err = legacyTypeAndHashFromPublicKey(testECDSAPrivateKey.Public())
|
sigType, hashFunc, err = legacyTypeAndHashFromPublicKey(testECDSAPrivateKey.Public())
|
||||||
@ -140,7 +140,7 @@ func TestLegacyTypeAndHash(t *testing.T) {
|
|||||||
t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
||||||
}
|
}
|
||||||
if expectedHashFunc := crypto.SHA1; expectedHashFunc != hashFunc {
|
if expectedHashFunc := crypto.SHA1; expectedHashFunc != hashFunc {
|
||||||
t.Errorf("ECDSA: expected hash %#x, got %#x", expectedHashFunc, sigType)
|
t.Errorf("ECDSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ed25519 is not supported by TLS 1.0 and 1.1.
|
// Ed25519 is not supported by TLS 1.0 and 1.1.
|
||||||
@ -156,13 +156,13 @@ func TestSupportedSignatureAlgorithms(t *testing.T) {
|
|||||||
for _, sigAlg := range supportedSignatureAlgorithms {
|
for _, sigAlg := range supportedSignatureAlgorithms {
|
||||||
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
|
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%#04x: unexpected error: %v", sigAlg, err)
|
t.Errorf("%v: unexpected error: %v", sigAlg, err)
|
||||||
}
|
}
|
||||||
if sigType == 0 {
|
if sigType == 0 {
|
||||||
t.Errorf("%#04x: missing signature type", sigAlg)
|
t.Errorf("%v: missing signature type", sigAlg)
|
||||||
}
|
}
|
||||||
if hash == 0 && sigAlg != Ed25519 {
|
if hash == 0 && sigAlg != Ed25519 {
|
||||||
t.Errorf("%#04x: missing hash", sigAlg)
|
t.Errorf("%v: missing hash", sigAlg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,6 +299,8 @@ type ClientSessionCache interface {
|
|||||||
Put(sessionKey string, cs *ClientSessionState)
|
Put(sessionKey string, cs *ClientSessionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
|
||||||
|
|
||||||
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
||||||
// RFC 8446, Section 4.2.3.
|
// RFC 8446, Section 4.2.3.
|
||||||
type SignatureScheme uint16
|
type SignatureScheme uint16
|
||||||
|
116
src/crypto/tls/common_string.go
Normal file
116
src/crypto/tls/common_string.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[PKCS1WithSHA256-1025]
|
||||||
|
_ = x[PKCS1WithSHA384-1281]
|
||||||
|
_ = x[PKCS1WithSHA512-1537]
|
||||||
|
_ = x[PSSWithSHA256-2052]
|
||||||
|
_ = x[PSSWithSHA384-2053]
|
||||||
|
_ = x[PSSWithSHA512-2054]
|
||||||
|
_ = x[ECDSAWithP256AndSHA256-1027]
|
||||||
|
_ = x[ECDSAWithP384AndSHA384-1283]
|
||||||
|
_ = x[ECDSAWithP521AndSHA512-1539]
|
||||||
|
_ = x[Ed25519-2055]
|
||||||
|
_ = x[PKCS1WithSHA1-513]
|
||||||
|
_ = x[ECDSAWithSHA1-515]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_SignatureScheme_name_0 = "PKCS1WithSHA1"
|
||||||
|
_SignatureScheme_name_1 = "ECDSAWithSHA1"
|
||||||
|
_SignatureScheme_name_2 = "PKCS1WithSHA256"
|
||||||
|
_SignatureScheme_name_3 = "ECDSAWithP256AndSHA256"
|
||||||
|
_SignatureScheme_name_4 = "PKCS1WithSHA384"
|
||||||
|
_SignatureScheme_name_5 = "ECDSAWithP384AndSHA384"
|
||||||
|
_SignatureScheme_name_6 = "PKCS1WithSHA512"
|
||||||
|
_SignatureScheme_name_7 = "ECDSAWithP521AndSHA512"
|
||||||
|
_SignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_SignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i SignatureScheme) String() string {
|
||||||
|
switch {
|
||||||
|
case i == 513:
|
||||||
|
return _SignatureScheme_name_0
|
||||||
|
case i == 515:
|
||||||
|
return _SignatureScheme_name_1
|
||||||
|
case i == 1025:
|
||||||
|
return _SignatureScheme_name_2
|
||||||
|
case i == 1027:
|
||||||
|
return _SignatureScheme_name_3
|
||||||
|
case i == 1281:
|
||||||
|
return _SignatureScheme_name_4
|
||||||
|
case i == 1283:
|
||||||
|
return _SignatureScheme_name_5
|
||||||
|
case i == 1537:
|
||||||
|
return _SignatureScheme_name_6
|
||||||
|
case i == 1539:
|
||||||
|
return _SignatureScheme_name_7
|
||||||
|
case 2052 <= i && i <= 2055:
|
||||||
|
i -= 2052
|
||||||
|
return _SignatureScheme_name_8[_SignatureScheme_index_8[i]:_SignatureScheme_index_8[i+1]]
|
||||||
|
default:
|
||||||
|
return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[CurveP256-23]
|
||||||
|
_ = x[CurveP384-24]
|
||||||
|
_ = x[CurveP521-25]
|
||||||
|
_ = x[X25519-29]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CurveID_name_0 = "CurveP256CurveP384CurveP521"
|
||||||
|
_CurveID_name_1 = "X25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_CurveID_index_0 = [...]uint8{0, 9, 18, 27}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i CurveID) String() string {
|
||||||
|
switch {
|
||||||
|
case 23 <= i && i <= 25:
|
||||||
|
i -= 23
|
||||||
|
return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]]
|
||||||
|
case i == 29:
|
||||||
|
return _CurveID_name_1
|
||||||
|
default:
|
||||||
|
return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[NoClientCert-0]
|
||||||
|
_ = x[RequestClientCert-1]
|
||||||
|
_ = x[RequireAnyClientCert-2]
|
||||||
|
_ = x[VerifyClientCertIfGiven-3]
|
||||||
|
_ = x[RequireAndVerifyClientCert-4]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _ClientAuthType_name = "NoClientCertRequestClientCertRequireAnyClientCertVerifyClientCertIfGivenRequireAndVerifyClientCert"
|
||||||
|
|
||||||
|
var _ClientAuthType_index = [...]uint8{0, 12, 29, 49, 72, 98}
|
||||||
|
|
||||||
|
func (i ClientAuthType) String() string {
|
||||||
|
if i < 0 || i >= ClientAuthType(len(_ClientAuthType_index)-1) {
|
||||||
|
return "ClientAuthType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _ClientAuthType_name[_ClientAuthType_index[i]:_ClientAuthType_index[i+1]]
|
||||||
|
}
|
@ -621,16 +621,14 @@ func TestBuildingWindowsGUI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
|
||||||
|
|
||||||
switch oh := f.OptionalHeader.(type) {
|
switch oh := f.OptionalHeader.(type) {
|
||||||
case *OptionalHeader32:
|
case *OptionalHeader32:
|
||||||
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
||||||
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
||||||
}
|
}
|
||||||
case *OptionalHeader64:
|
case *OptionalHeader64:
|
||||||
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
||||||
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
|
t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
|
||||||
|
@ -129,3 +129,56 @@ const (
|
|||||||
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
|
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
|
||||||
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
|
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Values of IMAGE_FILE_HEADER.Characteristics. These can be combined together.
|
||||||
|
const (
|
||||||
|
IMAGE_FILE_RELOCS_STRIPPED = 0x0001
|
||||||
|
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002
|
||||||
|
IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004
|
||||||
|
IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008
|
||||||
|
IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010
|
||||||
|
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020
|
||||||
|
IMAGE_FILE_BYTES_REVERSED_LO = 0x0080
|
||||||
|
IMAGE_FILE_32BIT_MACHINE = 0x0100
|
||||||
|
IMAGE_FILE_DEBUG_STRIPPED = 0x0200
|
||||||
|
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400
|
||||||
|
IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800
|
||||||
|
IMAGE_FILE_SYSTEM = 0x1000
|
||||||
|
IMAGE_FILE_DLL = 0x2000
|
||||||
|
IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000
|
||||||
|
IMAGE_FILE_BYTES_REVERSED_HI = 0x8000
|
||||||
|
)
|
||||||
|
|
||||||
|
// OptionalHeader64.Subsystem and OptionalHeader32.Subsystem values.
|
||||||
|
const (
|
||||||
|
IMAGE_SUBSYSTEM_UNKNOWN = 0
|
||||||
|
IMAGE_SUBSYSTEM_NATIVE = 1
|
||||||
|
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
||||||
|
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
|
||||||
|
IMAGE_SUBSYSTEM_OS2_CUI = 5
|
||||||
|
IMAGE_SUBSYSTEM_POSIX_CUI = 7
|
||||||
|
IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8
|
||||||
|
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9
|
||||||
|
IMAGE_SUBSYSTEM_EFI_APPLICATION = 10
|
||||||
|
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11
|
||||||
|
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12
|
||||||
|
IMAGE_SUBSYSTEM_EFI_ROM = 13
|
||||||
|
IMAGE_SUBSYSTEM_XBOX = 14
|
||||||
|
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
// OptionalHeader64.DllCharacteristics and OptionalHeader32.DllCharacteristics
|
||||||
|
// values. These can be combined together.
|
||||||
|
const (
|
||||||
|
IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
|
||||||
|
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040
|
||||||
|
IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080
|
||||||
|
IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100
|
||||||
|
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200
|
||||||
|
IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400
|
||||||
|
IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800
|
||||||
|
IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000
|
||||||
|
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000
|
||||||
|
IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000
|
||||||
|
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
|
||||||
|
)
|
||||||
|
@ -70,7 +70,7 @@ func Is(err, target error) bool {
|
|||||||
// setting target.
|
// setting target.
|
||||||
//
|
//
|
||||||
// An error type might provide an As method so it can be treated as if it were a
|
// An error type might provide an As method so it can be treated as if it were a
|
||||||
// a different error type.
|
// different error type.
|
||||||
//
|
//
|
||||||
// As panics if target is not a non-nil pointer to either a type that implements
|
// As panics if target is not a non-nil pointer to either a type that implements
|
||||||
// error, or to any interface type.
|
// error, or to any interface type.
|
||||||
|
@ -4,7 +4,7 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||||
golang.org/x/net v0.0.0-20200219183655-46282727080f
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
||||||
golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f // indirect
|
golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f // indirect
|
||||||
)
|
)
|
||||||
|
@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20200219183655-46282727080f h1:dB42wwhNuwPvh8f+5zZWNcU+F2Xs/B9wXXwvUCOH7r8=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||||
golang.org/x/net v0.0.0-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
|
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
|
||||||
|
@ -20,6 +20,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MaxLen is the maximum length of the string to be searched for (argument b) in Index.
|
// MaxLen is the maximum length of the string to be searched for (argument b) in Index.
|
||||||
|
// If MaxLen is not 0, make sure MaxLen >= 4.
|
||||||
var MaxLen int
|
var MaxLen int
|
||||||
|
|
||||||
// FIXME: the logic of HashStrBytes, HashStrRevBytes, IndexRabinKarpBytes and HashStr, HashStrRev,
|
// FIXME: the logic of HashStrBytes, HashStrRevBytes, IndexRabinKarpBytes and HashStr, HashStrRev,
|
||||||
|
@ -16,8 +16,42 @@ func Index(a, b []byte) int {
|
|||||||
|
|
||||||
// IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
|
// IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
|
||||||
// Requires 2 <= len(b) <= MaxLen.
|
// Requires 2 <= len(b) <= MaxLen.
|
||||||
func IndexString(a, b string) int {
|
func IndexString(s, substr string) int {
|
||||||
panic("unimplemented")
|
// This is a partial copy of strings.Index, here because bytes.IndexAny and bytes.LastIndexAny
|
||||||
|
// call bytealg.IndexString. Some platforms have an optimized assembly version of this function.
|
||||||
|
// This implementation is used for those that do not. Although the pure Go implementation here
|
||||||
|
// works for the case of len(b) > MaxLen, we do not require that its assembly implementation also
|
||||||
|
// supports the case of len(b) > MaxLen. And we do not guarantee that this function supports the
|
||||||
|
// case of len(b) > MaxLen.
|
||||||
|
n := len(substr)
|
||||||
|
c0 := substr[0]
|
||||||
|
c1 := substr[1]
|
||||||
|
i := 0
|
||||||
|
t := len(s) - n + 1
|
||||||
|
fails := 0
|
||||||
|
for i < t {
|
||||||
|
if s[i] != c0 {
|
||||||
|
o := IndexByteString(s[i:t], c0)
|
||||||
|
if o < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
i += o
|
||||||
|
}
|
||||||
|
if s[i+1] == c1 && s[i:i+n] == substr {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
fails++
|
||||||
|
if fails >= 4+i>>4 && i < t {
|
||||||
|
// See comment in src/bytes/bytes.go.
|
||||||
|
j := IndexRabinKarp(s[i:], substr)
|
||||||
|
if j < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return i + j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cutover reports the number of failures of IndexByte we should tolerate
|
// Cutover reports the number of failures of IndexByte we should tolerate
|
||||||
|
@ -412,10 +412,10 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
sect.Relocs[i].Type = rel.Rtype
|
sect.Relocs[i].Type = rel.Rtype
|
||||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||||
|
|
||||||
if rel.Rsize&0x80 == 1 {
|
if rel.Rsize&0x80 != 0 {
|
||||||
sect.Relocs[i].Signed = true
|
sect.Relocs[i].Signed = true
|
||||||
}
|
}
|
||||||
if rel.Rsize&0x40 == 1 {
|
if rel.Rsize&0x40 != 0 {
|
||||||
sect.Relocs[i].InstructionFixed = true
|
sect.Relocs[i].InstructionFixed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,10 +428,10 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||||||
sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
|
sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
|
||||||
sect.Relocs[i].Type = rel.Rtype
|
sect.Relocs[i].Type = rel.Rtype
|
||||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||||
if rel.Rsize&0x80 == 1 {
|
if rel.Rsize&0x80 != 0 {
|
||||||
sect.Relocs[i].Signed = true
|
sect.Relocs[i].Signed = true
|
||||||
}
|
}
|
||||||
if rel.Rsize&0x40 == 1 {
|
if rel.Rsize&0x40 != 0 {
|
||||||
sect.Relocs[i].InstructionFixed = true
|
sect.Relocs[i].InstructionFixed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +236,10 @@ type WriterAt interface {
|
|||||||
// ReadByte reads and returns the next byte from the input or
|
// ReadByte reads and returns the next byte from the input or
|
||||||
// any error encountered. If ReadByte returns an error, no input
|
// any error encountered. If ReadByte returns an error, no input
|
||||||
// byte was consumed, and the returned byte value is undefined.
|
// byte was consumed, and the returned byte value is undefined.
|
||||||
|
//
|
||||||
|
// ReadByte provides an efficient interface for byte-at-time
|
||||||
|
// processing. A Reader that does not implement ByteReader
|
||||||
|
// can be wrapped using bufio.NewReader to add this method.
|
||||||
type ByteReader interface {
|
type ByteReader interface {
|
||||||
ReadByte() (byte, error)
|
ReadByte() (byte, error)
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ var builtinTypesLower = map[string]string{
|
|||||||
".jpeg": "image/jpeg",
|
".jpeg": "image/jpeg",
|
||||||
".jpg": "image/jpeg",
|
".jpg": "image/jpeg",
|
||||||
".js": "text/javascript; charset=utf-8",
|
".js": "text/javascript; charset=utf-8",
|
||||||
|
".json": "application/json",
|
||||||
".mjs": "text/javascript; charset=utf-8",
|
".mjs": "text/javascript; charset=utf-8",
|
||||||
".pdf": "application/pdf",
|
".pdf": "application/pdf",
|
||||||
".png": "image/png",
|
".png": "image/png",
|
||||||
|
@ -441,6 +441,14 @@ func TestDialParallelSpuriousConnection(t *testing.T) {
|
|||||||
t.Skip("both IPv4 and IPv6 are required")
|
t.Skip("both IPv4 and IPv6 are required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var readDeadline time.Time
|
||||||
|
if td, ok := t.Deadline(); ok {
|
||||||
|
const arbitraryCleanupMargin = 1 * time.Second
|
||||||
|
readDeadline = td.Add(-arbitraryCleanupMargin)
|
||||||
|
} else {
|
||||||
|
readDeadline = time.Now().Add(5 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(2)
|
wg.Add(2)
|
||||||
handler := func(dss *dualStackServer, ln Listener) {
|
handler := func(dss *dualStackServer, ln Listener) {
|
||||||
@ -450,7 +458,7 @@ func TestDialParallelSpuriousConnection(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// The client should close itself, without sending data.
|
// The client should close itself, without sending data.
|
||||||
c.SetReadDeadline(time.Now().Add(1 * time.Second))
|
c.SetReadDeadline(readDeadline)
|
||||||
var b [1]byte
|
var b [1]byte
|
||||||
if _, err := c.Read(b[:]); err != io.EOF {
|
if _, err := c.Read(b[:]); err != io.EOF {
|
||||||
t.Errorf("got %v; want %v", err, io.EOF)
|
t.Errorf("got %v; want %v", err, io.EOF)
|
||||||
|
@ -89,8 +89,6 @@ func RequestFromMap(params map[string]string) (*http.Request, error) {
|
|||||||
r.Header.Add(strings.ReplaceAll(k[5:], "_", "-"), v)
|
r.Header.Add(strings.ReplaceAll(k[5:], "_", "-"), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cookies. parsing them isn't exported, though.
|
|
||||||
|
|
||||||
uriStr := params["REQUEST_URI"]
|
uriStr := params["REQUEST_URI"]
|
||||||
if uriStr == "" {
|
if uriStr == "" {
|
||||||
// Fallback to SCRIPT_NAME, PATH_INFO and QUERY_STRING.
|
// Fallback to SCRIPT_NAME, PATH_INFO and QUERY_STRING.
|
||||||
|
@ -4135,10 +4135,19 @@ func TestServerConnState(t *testing.T) {
|
|||||||
|
|
||||||
doRequests()
|
doRequests()
|
||||||
|
|
||||||
timer := time.NewTimer(5 * time.Second)
|
stateDelay := 5 * time.Second
|
||||||
|
if deadline, ok := t.Deadline(); ok {
|
||||||
|
// Allow an arbitrarily long delay.
|
||||||
|
// This test was observed to be flaky on the darwin-arm64-corellium builder,
|
||||||
|
// so we're increasing the deadline to see if it starts passing.
|
||||||
|
// See https://golang.org/issue/37322.
|
||||||
|
const arbitraryCleanupMargin = 1 * time.Second
|
||||||
|
stateDelay = time.Until(deadline) - arbitraryCleanupMargin
|
||||||
|
}
|
||||||
|
timer := time.NewTimer(stateDelay)
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
t.Errorf("Timed out waiting for connection to change state.")
|
t.Errorf("Timed out after %v waiting for connection to change state.", stateDelay)
|
||||||
case <-complete:
|
case <-complete:
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,8 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
|
|||||||
// is slower but more general and is used for hashing interface types
|
// is slower but more general and is used for hashing interface types
|
||||||
// (called from interhash or nilinterhash, above) or for hashing in
|
// (called from interhash or nilinterhash, above) or for hashing in
|
||||||
// maps generated by reflect.MapOf (reflect_typehash, below).
|
// maps generated by reflect.MapOf (reflect_typehash, below).
|
||||||
|
// Note: this function must match the compiler generated
|
||||||
|
// functions exactly. See issue 37716.
|
||||||
func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
|
func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
|
||||||
if t.tflag&tflagRegularMemory != 0 {
|
if t.tflag&tflagRegularMemory != 0 {
|
||||||
// Handle ptr sizes specially, see issue 37086.
|
// Handle ptr sizes specially, see issue 37086.
|
||||||
@ -195,12 +197,28 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
|
|||||||
return h
|
return h
|
||||||
case kindStruct:
|
case kindStruct:
|
||||||
s := (*structtype)(unsafe.Pointer(t))
|
s := (*structtype)(unsafe.Pointer(t))
|
||||||
|
memStart := uintptr(0)
|
||||||
|
memEnd := uintptr(0)
|
||||||
for _, f := range s.fields {
|
for _, f := range s.fields {
|
||||||
// TODO: maybe we could hash several contiguous fields all at once.
|
if memEnd > memStart && (f.name.isBlank() || f.offset() != memEnd || f.typ.tflag&tflagRegularMemory == 0) {
|
||||||
|
// flush any pending regular memory hashing
|
||||||
|
h = memhash(add(p, memStart), h, memEnd-memStart)
|
||||||
|
memStart = memEnd
|
||||||
|
}
|
||||||
if f.name.isBlank() {
|
if f.name.isBlank() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if f.typ.tflag&tflagRegularMemory == 0 {
|
||||||
h = typehash(f.typ, add(p, f.offset()), h)
|
h = typehash(f.typ, add(p, f.offset()), h)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if memStart == memEnd {
|
||||||
|
memStart = f.offset()
|
||||||
|
}
|
||||||
|
memEnd = f.offset() + f.typ.size
|
||||||
|
}
|
||||||
|
if memEnd > memStart {
|
||||||
|
h = memhash(add(p, memStart), h, memEnd-memStart)
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
default:
|
default:
|
||||||
|
@ -10,18 +10,18 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
|
|||||||
// Check that (*[n]elem)(p) is appropriately aligned.
|
// Check that (*[n]elem)(p) is appropriately aligned.
|
||||||
// TODO(mdempsky): What about fieldAlign?
|
// TODO(mdempsky): What about fieldAlign?
|
||||||
if uintptr(p)&(uintptr(elem.align)-1) != 0 {
|
if uintptr(p)&(uintptr(elem.align)-1) != 0 {
|
||||||
throw("checkptr: unsafe pointer conversion")
|
throw("checkptr: misaligned pointer conversion")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
|
// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
|
||||||
if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
|
if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
|
||||||
throw("checkptr: unsafe pointer conversion")
|
throw("checkptr: converted pointer straddles multiple allocations")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
|
func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
|
||||||
if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
|
if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
|
||||||
throw("checkptr: unsafe pointer arithmetic")
|
throw("checkptr: pointer arithmetic computed bad pointer value")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that if the computed pointer p points into a heap
|
// Check that if the computed pointer p points into a heap
|
||||||
@ -38,7 +38,7 @@ func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw("checkptr: unsafe pointer arithmetic")
|
throw("checkptr: pointer arithmetic result points to invalid allocation")
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkptrBase returns the base address for the allocation containing
|
// checkptrBase returns the base address for the allocation containing
|
||||||
|
@ -24,10 +24,10 @@ func TestCheckPtr(t *testing.T) {
|
|||||||
cmd string
|
cmd string
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{"CheckPtrAlignment", "fatal error: checkptr: unsafe pointer conversion\n"},
|
{"CheckPtrAlignment", "fatal error: checkptr: misaligned pointer conversion\n"},
|
||||||
{"CheckPtrArithmetic", "fatal error: checkptr: unsafe pointer arithmetic\n"},
|
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
|
||||||
{"CheckPtrSize", "fatal error: checkptr: unsafe pointer conversion\n"},
|
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
|
||||||
{"CheckPtrSmall", "fatal error: checkptr: unsafe pointer arithmetic\n"},
|
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
@ -288,6 +289,12 @@ func TestSignalExitStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSignalIgnoreSIGTRAP(t *testing.T) {
|
func TestSignalIgnoreSIGTRAP(t *testing.T) {
|
||||||
|
if runtime.GOOS == "openbsd" {
|
||||||
|
if bn := testenv.Builder(); strings.HasSuffix(bn, "-62") || strings.HasSuffix(bn, "-64") {
|
||||||
|
testenv.SkipFlaky(t, 17496)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP")
|
output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP")
|
||||||
want := "OK\n"
|
want := "OK\n"
|
||||||
if output != want {
|
if output != want {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user