mirror of
https://github.com/golang/go.git
synced 2025-05-16 12:54:37 +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.
|
||||
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 as, isASCII := makeASCIISet(chars); isASCII {
|
||||
for i, c := range s {
|
||||
@ -197,14 +220,26 @@ func IndexAny(s []byte, chars string) int {
|
||||
for i := 0; i < len(s); i += width {
|
||||
r := rune(s[i])
|
||||
if r < utf8.RuneSelf {
|
||||
width = 1
|
||||
} else {
|
||||
r, width = utf8.DecodeRune(s[i:])
|
||||
}
|
||||
for _, ch := range chars {
|
||||
if r == ch {
|
||||
if bytealg.IndexByteString(chars, s[i]) >= 0 {
|
||||
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
|
||||
@ -229,14 +264,60 @@ func LastIndexAny(s []byte, chars string) int {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
for i := len(s); i > 0; {
|
||||
r, size := utf8.DecodeLastRune(s[:i])
|
||||
i -= size
|
||||
for _, c := range chars {
|
||||
if r == c {
|
||||
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; {
|
||||
r, size := utf8.DecodeLastRune(s[:i])
|
||||
i -= size
|
||||
if r == cr {
|
||||
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
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ var indexAnyTests = []BinOpTest{
|
||||
{"", "abc", -1},
|
||||
{"a", "", -1},
|
||||
{"a", "a", 0},
|
||||
{"\x80", "\xffb", 0},
|
||||
{"aaa", "a", 0},
|
||||
{"abc", "xyz", -1},
|
||||
{"abc", "xcz", 2},
|
||||
@ -179,6 +180,7 @@ var indexAnyTests = []BinOpTest{
|
||||
{dots + dots + dots, " ", -1},
|
||||
{"012abcba210", "\xffb", 4},
|
||||
{"012\x80bcb\x80210", "\xffb", 3},
|
||||
{"0123456\xcf\x80abc", "\xcfb\x80", 10},
|
||||
}
|
||||
|
||||
var lastIndexAnyTests = []BinOpTest{
|
||||
@ -187,6 +189,7 @@ var lastIndexAnyTests = []BinOpTest{
|
||||
{"", "abc", -1},
|
||||
{"a", "", -1},
|
||||
{"a", "a", 0},
|
||||
{"\x80", "\xffb", 0},
|
||||
{"aaa", "a", 2},
|
||||
{"abc", "xyz", -1},
|
||||
{"abc", "ab", 1},
|
||||
@ -197,6 +200,7 @@ var lastIndexAnyTests = []BinOpTest{
|
||||
{dots + dots + dots, " ", -1},
|
||||
{"012abcba210", "\xffb", 6},
|
||||
{"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
|
||||
@ -1890,10 +1894,10 @@ func BenchmarkBytesCompare(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkIndexAnyASCII(b *testing.B) {
|
||||
x := Repeat([]byte{'#'}, 4096) // Never matches set
|
||||
cs := "0123456789abcdef"
|
||||
for k := 1; k <= 4096; k <<= 4 {
|
||||
for j := 1; j <= 16; j <<= 1 {
|
||||
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++ {
|
||||
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) {
|
||||
cs := "0123456789abcdef"
|
||||
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
|
||||
// <MNEMONIC> XA,XB,XT produces
|
||||
// <mnemonic> XT,XA,XB
|
||||
XXLANDQ VS0,VS1,VS32
|
||||
XXLAND VS0,VS1,VS32
|
||||
XXLANDC VS0,VS1,VS32
|
||||
XXLEQV VS0,VS1,VS32
|
||||
XXLNAND VS0,VS1,VS32
|
||||
@ -1093,6 +1093,11 @@ label1:
|
||||
// <mnemonic> XT,XB,UIM
|
||||
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
|
||||
// <MNEMONIC> XA,XB,DM,XT produces
|
||||
// <mnemonic> XT,XA,XB,DM
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -802,6 +803,28 @@ func (p *Package) packedAttribute() string {
|
||||
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
|
||||
// from Go so that they are callable from C.
|
||||
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 {
|
||||
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 += ")"
|
||||
|
||||
if len(exp.Doc) > 0 {
|
||||
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, "\nCGO_NO_SANITIZE_THREAD")
|
||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||
fmt.Fprintf(fgcc, "{\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) {
|
||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
|
||||
fmt.Fprintf(fgcc, "\t_cgo_a.recv = recv;\n")
|
||||
}
|
||||
forFieldList(fntype.Params,
|
||||
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, "\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_release_context(_cgo_ctxt);\n")
|
||||
if gccResult != "void" {
|
||||
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 {
|
||||
forFieldList(fntype.Results,
|
||||
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")
|
||||
}
|
||||
|
@ -77,8 +77,6 @@ Flags:
|
||||
-lang version
|
||||
Set language version to compile, as in -lang=go1.12.
|
||||
Default is current version.
|
||||
-largemodel
|
||||
Generate code that assumes a large memory model.
|
||||
-linkobj file
|
||||
Write linker-specific object to file and compiler-specific
|
||||
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
|
||||
// the hash of a value of type t.
|
||||
// Note: the generated function must match runtime.typehash exactly.
|
||||
func genhash(t *types.Type) *obj.LSym {
|
||||
switch algtype(t) {
|
||||
default:
|
||||
|
@ -673,10 +673,6 @@ func evconst(n *Node) {
|
||||
}
|
||||
|
||||
case OCOMPLEX:
|
||||
if nl == nil || nr == nil {
|
||||
// TODO(mdempsky): Remove after early OAS2FUNC rewrite CL lands.
|
||||
break
|
||||
}
|
||||
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||
// make it a complex literal
|
||||
c := newMpcmplx()
|
||||
|
@ -1371,7 +1371,7 @@ func (e *Escape) finish(fns []*Node) {
|
||||
fn.Esc = EscFuncTagged
|
||||
|
||||
narg := 0
|
||||
for _, fs := range types.RecvsParams {
|
||||
for _, fs := range &types.RecvsParams {
|
||||
for _, f := range fs(fn.Type).Fields().Slice() {
|
||||
narg++
|
||||
f.Note = e.paramTag(fn, narg, f)
|
||||
|
@ -585,28 +585,44 @@ 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 {
|
||||
switch mode {
|
||||
case FErr: // This is for the user
|
||||
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 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:
|
||||
return s.Pkg.Name + "." + s.Name
|
||||
b.WriteString(s.Pkg.Name)
|
||||
b.WriteByte('.')
|
||||
b.WriteString(s.Name)
|
||||
return
|
||||
|
||||
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:
|
||||
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 {
|
||||
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{
|
||||
@ -652,16 +670,16 @@ var basicnames = []string{
|
||||
TBLANK: "blank",
|
||||
}
|
||||
|
||||
var tconvBufferPool = sync.Pool{
|
||||
var fmtBufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
|
||||
buf := tconvBufferPool.Get().(*bytes.Buffer)
|
||||
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer tconvBufferPool.Put(buf)
|
||||
defer fmtBufferPool.Put(buf)
|
||||
|
||||
tconv2(buf, t, flag, mode, nil)
|
||||
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:
|
||||
t = types.Types[t.Etype]
|
||||
default:
|
||||
b.WriteString(sconv(t.Sym, FmtShort, mode))
|
||||
sconv2(b, t.Sym, FmtShort, mode)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -718,15 +736,16 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||
case FTypeId, FTypeIdName:
|
||||
if flag&FmtShort != 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
|
||||
}
|
||||
b.WriteString(sconv(t.Sym, FmtShort, mode))
|
||||
sconv2(b, t.Sym, FmtShort, mode)
|
||||
return
|
||||
}
|
||||
|
||||
if mode == FTypeIdName {
|
||||
b.WriteString(sconv(t.Sym, FmtUnsigned, mode))
|
||||
sconv2(b, t.Sym, FmtUnsigned, mode)
|
||||
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
|
||||
}
|
||||
|
||||
@ -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.
|
||||
break
|
||||
case types.IsExported(f.Sym.Name):
|
||||
b.WriteString(sconv(f.Sym, FmtShort, mode))
|
||||
sconv2(b, f.Sym, FmtShort, mode)
|
||||
default:
|
||||
flag1 := FmtLeft
|
||||
if flag&FmtUnsigned != 0 {
|
||||
flag1 = FmtUnsigned
|
||||
}
|
||||
b.WriteString(sconv(f.Sym, flag1, mode))
|
||||
sconv2(b, f.Sym, flag1, mode)
|
||||
}
|
||||
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")
|
||||
if t.Sym != nil {
|
||||
b.WriteByte(' ')
|
||||
b.WriteString(smodeString(t.Sym, mode))
|
||||
sconv2(b, t.Sym, 0, mode)
|
||||
}
|
||||
|
||||
case TUNSAFEPTR:
|
||||
@ -1731,9 +1750,30 @@ func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
|
||||
if s.Name == "_" {
|
||||
return "_"
|
||||
}
|
||||
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer fmtBufferPool.Put(buf)
|
||||
|
||||
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) {
|
||||
|
@ -954,7 +954,7 @@ func (w *exportWriter) funcExt(n *Node) {
|
||||
w.symIdx(n.Sym)
|
||||
|
||||
// Escape analysis.
|
||||
for _, fs := range types.RecvsParams {
|
||||
for _, fs := range &types.RecvsParams {
|
||||
for _, f := range fs(n.Type).FieldSlice() {
|
||||
w.string(f.Note)
|
||||
}
|
||||
|
@ -660,7 +660,7 @@ func (r *importReader) funcExt(n *Node) {
|
||||
r.symIdx(n.Sym)
|
||||
|
||||
// Escape analysis.
|
||||
for _, fs := range types.RecvsParams {
|
||||
for _, fs := range &types.RecvsParams {
|
||||
for _, f := range fs(n.Type).FieldSlice() {
|
||||
f.Note = r.string()
|
||||
}
|
||||
|
@ -1070,7 +1070,7 @@ func loadsys() {
|
||||
typecheckok = true
|
||||
|
||||
typs := runtimeTypes()
|
||||
for _, d := range runtimeDecls {
|
||||
for _, d := range &runtimeDecls {
|
||||
sym := Runtimepkg.Lookup(d.name)
|
||||
typ := typs[d.typ]
|
||||
switch d.tag {
|
||||
@ -1373,7 +1373,7 @@ var concurrentFlagOK = [256]bool{
|
||||
}
|
||||
|
||||
func concurrentBackendAllowed() bool {
|
||||
for i, x := range Debug {
|
||||
for i, x := range &Debug {
|
||||
if x != 0 && !concurrentFlagOK[i] {
|
||||
return false
|
||||
}
|
||||
|
@ -646,7 +646,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
|
||||
}
|
||||
n := p.nod(expr, op, p.expr(expr.X), nil)
|
||||
var index [3]*Node
|
||||
for i, x := range expr.Index {
|
||||
for i, x := range &expr.Index {
|
||||
if x != nil {
|
||||
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 {
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
@ -705,12 +705,6 @@ func (lv *Liveness) markUnsafePoints() {
|
||||
v = v.Args[0]
|
||||
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:
|
||||
// Args[0] is the address of the write
|
||||
// barrier control. Ignore Args[1],
|
||||
|
@ -3216,7 +3216,7 @@ func init() {
|
||||
var p4 []*sys.Arch
|
||||
var p8 []*sys.Arch
|
||||
var lwatomics []*sys.Arch
|
||||
for _, a := range sys.Archs {
|
||||
for _, a := range &sys.Archs {
|
||||
all = append(all, a)
|
||||
if a.PtrSize == 4 {
|
||||
p4 = append(p4, a)
|
||||
|
@ -66,7 +66,7 @@ var builtinFuncs = [...]struct {
|
||||
// isBuiltinFuncName reports whether name matches a builtin function
|
||||
// name.
|
||||
func isBuiltinFuncName(name string) bool {
|
||||
for _, fn := range builtinFuncs {
|
||||
for _, fn := range &builtinFuncs {
|
||||
if fn.name == name {
|
||||
return true
|
||||
}
|
||||
@ -92,7 +92,7 @@ func initUniverse() {
|
||||
|
||||
// lexinit initializes known symbols and the basic types.
|
||||
func lexinit() {
|
||||
for _, s := range basicTypes {
|
||||
for _, s := range &basicTypes {
|
||||
etype := s.etype
|
||||
if int(etype) >= len(types.Types) {
|
||||
Fatalf("lexinit: %s bad etype", s.name)
|
||||
@ -111,13 +111,13 @@ func lexinit() {
|
||||
asNode(s2.Def).Name = new(Name)
|
||||
}
|
||||
|
||||
for _, s := range builtinFuncs {
|
||||
for _, s := range &builtinFuncs {
|
||||
s2 := builtinpkg.Lookup(s.name)
|
||||
s2.Def = asTypesNode(newname(s2))
|
||||
asNode(s2.Def).SetSubOp(s.op)
|
||||
}
|
||||
|
||||
for _, s := range unsafeFuncs {
|
||||
for _, s := range &unsafeFuncs {
|
||||
s2 := unsafepkg.Lookup(s.name)
|
||||
s2.Def = asTypesNode(newname(s2))
|
||||
asNode(s2.Def).SetSubOp(s.op)
|
||||
@ -402,7 +402,7 @@ func lexinit1() {
|
||||
dowidth(types.Runetype)
|
||||
|
||||
// backend-dependent builtin types (e.g. int).
|
||||
for _, s := range typedefs {
|
||||
for _, s := range &typedefs {
|
||||
s1 := builtinpkg.Lookup(s.name)
|
||||
|
||||
sameas := s.sameas32
|
||||
|
@ -390,7 +390,7 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
|
||||
var w io.WriteCloser
|
||||
|
||||
if slashPkgPath == "" {
|
||||
slashPkgPath = string(0)
|
||||
slashPkgPath = "\000"
|
||||
}
|
||||
subdirpath := filepath.Join(dest, pathEscape(slashPkgPath))
|
||||
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 {
|
||||
return e.i
|
||||
}
|
||||
func (e Edge) String() string {
|
||||
return fmt.Sprintf("{%v,%d}", e.b, e.i)
|
||||
}
|
||||
|
||||
// kind controls successors
|
||||
// ------------------------------------------
|
||||
|
@ -442,6 +442,7 @@ var passes = [...]pass{
|
||||
{name: "insert resched checks", fn: insertLoopReschedChecks,
|
||||
disabled: objabi.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
|
||||
{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 cse", fn: cse},
|
||||
{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)
|
||||
(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)
|
||||
(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)
|
||||
@ -611,34 +607,22 @@
|
||||
|
||||
// fold constants into memory operations
|
||||
// Note that this is not always a good idea because if not all the uses of
|
||||
// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
|
||||
// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
|
||||
// the ADDLconst get eliminated, we still have to compute the ADDLconst and we now
|
||||
// have potentially two live values (ptr and (ADDLconst [off] ptr)) instead of one.
|
||||
// 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)store [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOV(L|W|B|SS|SD)store [off1+off2] {sym} ptr val mem)
|
||||
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem)
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val (ADDLconst [off2] base) idx mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {sym} val base idx mem)
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym} val base (ADDLconst [off2] idx) mem) && is32Bit(off1+off2*4) ->
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2*4] {sym} val base idx mem)
|
||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} (ADDLconst [off2] base) idx val mem) && is32Bit(off1+off2) ->
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {sym} base idx val mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym} base (ADDLconst [off2] idx) val mem) && is32Bit(off1+off2*4) ->
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2*4] {sym} base idx val mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} (ADDLconst [off2] base) idx mem) && ValAndOff(valoff1).canAdd(off2) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {sym} base idx mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym} base (ADDLconst [off2] idx) mem) && ValAndOff(valoff1).canAdd(off2*4) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2*4)] {sym} base idx mem)
|
||||
|
||||
// Fold constants into stores.
|
||||
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
|
||||
@ -652,7 +636,7 @@
|
||||
(MOV(L|W|B)storeconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
|
||||
(MOV(L|W|B)storeconst [ValAndOff(sc).add(off)] {s} ptr mem)
|
||||
|
||||
// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
|
||||
// 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.
|
||||
// Note: we turn off this merging for operations on globals when building
|
||||
// position-independent code (when Flag_shared is set).
|
||||
@ -672,31 +656,9 @@
|
||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
(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)
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1] {sym1} val (LEAL [off2] {sym2} base) idx mem)
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lloadidx4 [off1+off2] {mergeSym(sym1,sym2)} val base idx mem)
|
||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
@ -706,97 +668,20 @@
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1] {sym1} (LEAL [off2] {sym2} base) idx val mem)
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|SUB|AND|OR|XOR)Lmodifyidx4 [off1+off2] {mergeSym(sym1,sym2)} base idx val mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [valoff1] {sym1} (LEAL [off2] {sym2} base) idx mem)
|
||||
&& ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodifyidx4 [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base idx mem)
|
||||
|
||||
(MOV(B|W|L|SS|SD)load [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)loadidx1 [off] {sym} ptr idx mem)
|
||||
(MOV(B|W|L|SS|SD)store [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOV(B|W|L|SS|SD)storeidx1 [off] {sym} ptr idx val mem)
|
||||
|
||||
(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
|
||||
((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)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|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)
|
||||
(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)
|
||||
&& y.Uses==1 && l.Uses==1 && clobber(y, l) && validValAndOff(c,off) ->
|
||||
((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem)
|
||||
(MOVLstoreidx4 {sym} [off] ptr idx y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLloadidx4 [off] {sym} ptr idx mem)) mem)
|
||||
&& y.Uses==1 && l.Uses==1 && clobber(y, 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
|
||||
(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) ->
|
||||
(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.
|
||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||
(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
|
||||
@ -1039,23 +934,27 @@
|
||||
// TEST %reg,%reg is shorter than CMP
|
||||
(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.
|
||||
// There are many ways these combinations could occur. This is
|
||||
// designed to match the way encoding/binary.LittleEndian does it.
|
||||
(ORL x0:(MOVBload [i0] {s} p mem)
|
||||
s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
|
||||
(ORL x0:(MOVBload [i0] {s} p0 mem)
|
||||
s0:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+1
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& s0.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
x0:(MOVWload [i0] {s} p mem)
|
||||
s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p mem)))
|
||||
s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p mem)))
|
||||
x0:(MOVWload [i0] {s} p0 mem)
|
||||
s0:(SHLLconst [16] x1:(MOVBload [i2] {s} p1 mem)))
|
||||
s1:(SHLLconst [24] x2:(MOVBload [i3] {s} p2 mem)))
|
||||
&& i2 == i0+2
|
||||
&& i3 == i0+3
|
||||
&& x0.Uses == 1
|
||||
@ -1064,126 +963,84 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& o0.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& same(p1, p2, 1)
|
||||
&& mergePoint(b,x0,x1,x2) != nil
|
||||
&& clobber(x0, x1, x2, s0, s1, o0)
|
||||
-> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p 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)
|
||||
-> @mergePoint(b,x0,x1,x2) (MOVLload [i0] {s} p0 mem)
|
||||
|
||||
// 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
|
||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p 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)
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||
|
||||
// Combine stores into larger (unaligned) stores.
|
||||
(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
||||
(MOVBstore [i] {s} p1 (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p0 w mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i-1] {s} p w mem)
|
||||
(MOVBstore [i] {s} p w x:(MOVBstore {s} [i+1] p (SHR(W|L)const [8] w) mem))
|
||||
-> (MOVWstore [i-1] {s} p0 w mem)
|
||||
(MOVBstore [i] {s} p1 w x:(MOVBstore {s} [i+1] p0 (SHR(W|L)const [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i] {s} p w mem)
|
||||
(MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
|
||||
-> (MOVWstore [i] {s} p0 w mem)
|
||||
(MOVBstore [i] {s} p1 (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p0 w0:(SHRLconst [j-8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i-1] {s} p w0 mem)
|
||||
(MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
|
||||
-> (MOVWstore [i-1] {s} p0 w0 mem)
|
||||
(MOVWstore [i] {s} p1 (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p0 w mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVLstore [i-2] {s} p w mem)
|
||||
(MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
|
||||
-> (MOVLstore [i-2] {s} p0 w mem)
|
||||
(MOVWstore [i] {s} p1 (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p0 w0:(SHRLconst [j-16] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& 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))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreidx1 [i-1] {s} p idx w mem)
|
||||
(MOVBstoreidx1 [i] {s} p idx w x:(MOVBstoreidx1 [i+1] {s} p idx (SHR(L|W)const [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreidx1 [i] {s} p idx w mem)
|
||||
(MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
-> (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)
|
||||
// Move constant offsets from LEALx up into load. This lets the above combining
|
||||
// rules discover indexed load-combining instances.
|
||||
(MOV(B|W|L)load [i0] {s0} l:(LEAL1 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL1 <l.Type> [0] {s1} x y) mem)
|
||||
(MOV(B|W|L)load [i0] {s0} l:(LEAL2 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL2 <l.Type> [0] {s1} x y) mem)
|
||||
(MOV(B|W|L)load [i0] {s0} l:(LEAL4 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL4 <l.Type> [0] {s1} x y) mem)
|
||||
(MOV(B|W|L)load [i0] {s0} l:(LEAL8 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)load [i0+i1] {s0} (LEAL8 <l.Type> [0] {s1} x y) mem)
|
||||
|
||||
(MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem)
|
||||
(MOVWstoreidx2 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem)
|
||||
(MOV(B|W|L)store [i0] {s0} l:(LEAL1 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL1 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L)store [i0] {s0} l:(LEAL2 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL2 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L)store [i0] {s0} l:(LEAL4 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L)store [i0+i1] {s0} (LEAL4 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L)store [i0] {s0} l:(LEAL8 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (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
|
||||
// a register to use for holding the address of the constant pool entry.
|
||||
|
@ -1043,12 +1043,6 @@
|
||||
(MOVWQZX x) && zeroUpper48Bits(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)
|
||||
(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)
|
||||
@ -1166,86 +1160,6 @@
|
||||
&& is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||
((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
|
||||
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
|
||||
(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) ->
|
||||
(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.
|
||||
(LT (InvertFlags cmp) yes no) -> (GT 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)
|
||||
(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.
|
||||
|
||||
@ -1552,60 +1480,65 @@
|
||||
|
||||
// Little-endian loads
|
||||
|
||||
(ORL x0:(MOVBload [i0] {s} p mem)
|
||||
sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p mem)))
|
||||
(ORL x0:(MOVBload [i0] {s} p0 mem)
|
||||
sh:(SHLLconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+1
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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)
|
||||
sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p mem)))
|
||||
(ORQ x0:(MOVBload [i0] {s} p0 mem)
|
||||
sh:(SHLQconst [8] x1:(MOVBload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+1
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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)
|
||||
sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p mem)))
|
||||
(ORL x0:(MOVWload [i0] {s} p0 mem)
|
||||
sh:(SHLLconst [16] x1:(MOVWload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+2
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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)
|
||||
sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p mem)))
|
||||
(ORQ x0:(MOVWload [i0] {s} p0 mem)
|
||||
sh:(SHLQconst [16] x1:(MOVWload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+2
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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)
|
||||
sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p mem)))
|
||||
(ORQ x0:(MOVLload [i0] {s} p0 mem)
|
||||
sh:(SHLQconst [32] x1:(MOVLload [i1] {s} p1 mem)))
|
||||
&& i1 == i0+4
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& clobber(x0, x1, sh)
|
||||
-> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p mem)
|
||||
-> @mergePoint(b,x0,x1) (MOVQload [i0] {s} p0 mem)
|
||||
|
||||
(ORL
|
||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
|
||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p0 mem))
|
||||
or:(ORL
|
||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
|
||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p1 mem))
|
||||
y))
|
||||
&& i1 == i0+1
|
||||
&& j1 == j0+8
|
||||
@ -1615,14 +1548,15 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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] (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
|
||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
|
||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p0 mem))
|
||||
or:(ORQ
|
||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
|
||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p1 mem))
|
||||
y))
|
||||
&& i1 == i0+1
|
||||
&& j1 == j0+8
|
||||
@ -1632,14 +1566,15 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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] (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
|
||||
s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p mem))
|
||||
s1:(SHLQconst [j1] x1:(MOVWload [i1] {s} p0 mem))
|
||||
or:(ORQ
|
||||
s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p mem))
|
||||
s0:(SHLQconst [j0] x0:(MOVWload [i0] {s} p1 mem))
|
||||
y))
|
||||
&& i1 == i0+2
|
||||
&& j1 == j0+16
|
||||
@ -1649,180 +1584,105 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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] (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
|
||||
|
||||
(ORL x0:(MOVBloadidx1 [i0] {s} p idx mem)
|
||||
sh:(SHLLconst [8] x1:(MOVBloadidx1 [i1] {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) (MOVWloadidx1 <v.Type> [i0] {s} p idx mem)
|
||||
// Move constants offsets from LEAQx up into load. This lets the above combining
|
||||
// rules discover indexed load-combining instances.
|
||||
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ1 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) mem)
|
||||
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ2 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) mem)
|
||||
(MOV(B|W|L|Q)load [i0] {s0} l:(LEAQ4 [i1] {s1} x y) mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)load [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) 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)
|
||||
sh:(SHLQconst [8] x1:(MOVBloadidx1 [i1] {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) (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)
|
||||
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ1 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ1 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ2 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ2 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ4 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ4 <l.Type> [0] {s1} x y) val mem)
|
||||
(MOV(B|W|L|Q)store [i0] {s0} l:(LEAQ8 [i1] {s1} x y) val mem) && i1 != 0 && is32Bit(i0+i1)
|
||||
-> (MOV(B|W|L|Q)store [i0+i1] {s0} (LEAQ8 <l.Type> [0] {s1} x y) val mem)
|
||||
|
||||
// Big-endian loads
|
||||
|
||||
(ORL
|
||||
x1:(MOVBload [i1] {s} p mem)
|
||||
sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p mem)))
|
||||
x1:(MOVBload [i1] {s} p0 mem)
|
||||
sh:(SHLLconst [8] x0:(MOVBload [i0] {s} p1 mem)))
|
||||
&& i1 == i0+1
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
x1:(MOVBload [i1] {s} p mem)
|
||||
sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p mem)))
|
||||
x1:(MOVBload [i1] {s} p0 mem)
|
||||
sh:(SHLQconst [8] x0:(MOVBload [i0] {s} p1 mem)))
|
||||
&& i1 == i0+1
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
|
||||
sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
|
||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem))
|
||||
sh:(SHLLconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem))))
|
||||
&& i1 == i0+2
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& r0.Uses == 1
|
||||
&& r1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p mem))
|
||||
sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p mem))))
|
||||
r1:(ROLWconst [8] x1:(MOVWload [i1] {s} p0 mem))
|
||||
sh:(SHLQconst [16] r0:(ROLWconst [8] x0:(MOVWload [i0] {s} p1 mem))))
|
||||
&& i1 == i0+2
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& r0.Uses == 1
|
||||
&& r1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
r1:(BSWAPL x1:(MOVLload [i1] {s} p mem))
|
||||
sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p mem))))
|
||||
r1:(BSWAPL x1:(MOVLload [i1] {s} p0 mem))
|
||||
sh:(SHLQconst [32] r0:(BSWAPL x0:(MOVLload [i0] {s} p1 mem))))
|
||||
&& i1 == i0+4
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& r0.Uses == 1
|
||||
&& r1.Uses == 1
|
||||
&& sh.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& mergePoint(b,x0,x1) != nil
|
||||
&& 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
|
||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p mem))
|
||||
s0:(SHLLconst [j0] x0:(MOVBload [i0] {s} p0 mem))
|
||||
or:(ORL
|
||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p mem))
|
||||
s1:(SHLLconst [j1] x1:(MOVBload [i1] {s} p1 mem))
|
||||
y))
|
||||
&& i1 == i0+1
|
||||
&& j1 == j0-8
|
||||
@ -1832,14 +1692,15 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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] (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
|
||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p mem))
|
||||
s0:(SHLQconst [j0] x0:(MOVBload [i0] {s} p0 mem))
|
||||
or:(ORQ
|
||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p mem))
|
||||
s1:(SHLQconst [j1] x1:(MOVBload [i1] {s} p1 mem))
|
||||
y))
|
||||
&& i1 == i0+1
|
||||
&& j1 == j0-8
|
||||
@ -1849,14 +1710,15 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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] (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
|
||||
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
|
||||
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))
|
||||
&& i1 == i0+2
|
||||
&& j1 == j0-16
|
||||
@ -1868,168 +1730,41 @@
|
||||
&& s0.Uses == 1
|
||||
&& s1.Uses == 1
|
||||
&& or.Uses == 1
|
||||
&& same(p0, p1, 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> (MOVLload [i0] {s} p 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)
|
||||
-> @mergePoint(b,x0,x1,y) (ORQ <v.Type> (SHLQconst <v.Type> [j1] (BSWAPL <typ.UInt32> (MOVLload [i0] {s} p0 mem))) y)
|
||||
|
||||
// Combine 2 byte stores + shift into rolw 8 + word store
|
||||
(MOVBstore [i] {s} p w
|
||||
x0:(MOVBstore [i-1] {s} p (SHRWconst [8] w) mem))
|
||||
(MOVBstore [i] {s} p1 w
|
||||
x0:(MOVBstore [i-1] {s} p0 (SHRWconst [8] w) mem))
|
||||
&& x0.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x0)
|
||||
-> (MOVWstore [i-1] {s} p (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)
|
||||
-> (MOVWstore [i-1] {s} p0 (ROLWconst <w.Type> [8] w) mem)
|
||||
|
||||
// Combine stores + shifts into bswap and larger (unaligned) stores
|
||||
(MOVBstore [i] {s} p w
|
||||
x2:(MOVBstore [i-1] {s} p (SHRLconst [8] w)
|
||||
x1:(MOVBstore [i-2] {s} p (SHRLconst [16] w)
|
||||
x0:(MOVBstore [i-3] {s} p (SHRLconst [24] w) mem))))
|
||||
(MOVBstore [i] {s} p3 w
|
||||
x2:(MOVBstore [i-1] {s} p2 (SHRLconst [8] w)
|
||||
x1:(MOVBstore [i-2] {s} p1 (SHRLconst [16] w)
|
||||
x0:(MOVBstore [i-3] {s} p0 (SHRLconst [24] w) mem))))
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& same(p1, p2, 1)
|
||||
&& same(p2, p3, 1)
|
||||
&& 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
|
||||
x2:(MOVBstoreidx1 [i-1] {s} p idx (SHRLconst [8] w)
|
||||
x1:(MOVBstoreidx1 [i-2] {s} p idx (SHRLconst [16] w)
|
||||
x0:(MOVBstoreidx1 [i-3] {s} p idx (SHRLconst [24] w) mem))))
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
&& clobber(x0, x1, x2)
|
||||
-> (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))))))))
|
||||
(MOVBstore [i] {s} p7 w
|
||||
x6:(MOVBstore [i-1] {s} p6 (SHRQconst [8] w)
|
||||
x5:(MOVBstore [i-2] {s} p5 (SHRQconst [16] w)
|
||||
x4:(MOVBstore [i-3] {s} p4 (SHRQconst [24] w)
|
||||
x3:(MOVBstore [i-4] {s} p3 (SHRQconst [32] w)
|
||||
x2:(MOVBstore [i-5] {s} p2 (SHRQconst [40] w)
|
||||
x1:(MOVBstore [i-6] {s} p1 (SHRQconst [48] w)
|
||||
x0:(MOVBstore [i-7] {s} p0 (SHRQconst [56] w) mem))))))))
|
||||
&& x0.Uses == 1
|
||||
&& x1.Uses == 1
|
||||
&& x2.Uses == 1
|
||||
@ -2037,165 +1772,99 @@
|
||||
&& x4.Uses == 1
|
||||
&& x5.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)
|
||||
-> (MOVQstore [i-7] {s} p (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)
|
||||
-> (MOVQstore [i-7] {s} p0 (BSWAPQ <w.Type> w) mem)
|
||||
|
||||
// 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
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVBstoreconst [a] {s} p1 x:(MOVBstoreconst [c] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
||||
-> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVWstoreconst [a] {s} p1 x:(MOVWstoreconst [c] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
|
||||
(MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
|
||||
-> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p0 mem)
|
||||
(MOVLstoreconst [c] {s} p1 x:(MOVLstoreconst [a] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||
(MOVLstoreconst [a] {s} p x:(MOVLstoreconst [c] {s} p mem))
|
||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||
(MOVLstoreconst [a] {s} p1 x:(MOVLstoreconst [c] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||
(MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem))
|
||||
-> (MOVQstore [ValAndOff(a).Off()] {s} p0 (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
|
||||
(MOVQstoreconst [c] {s} p1 x:(MOVQstoreconst [c2] {s} p0 mem))
|
||||
&& config.useSSE
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& ValAndOff(c2).Off() + 8 == ValAndOff(c).Off()
|
||||
&& ValAndOff(c).Val() == 0
|
||||
&& ValAndOff(c2).Val() == 0
|
||||
&& clobber(x)
|
||||
-> (MOVOstore [ValAndOff(c2).Off()] {s} p (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)
|
||||
-> (MOVOstore [ValAndOff(c2).Off()] {s} p0 (MOVOconst [0]) mem)
|
||||
|
||||
// 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
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i-1] {s} p w mem)
|
||||
(MOVBstore [i] {s} p w x:(MOVBstore [i+1] {s} p (SHR(W|L|Q)const [8] w) mem))
|
||||
-> (MOVWstore [i-1] {s} p0 w mem)
|
||||
(MOVBstore [i] {s} p1 w x:(MOVBstore [i+1] {s} p0 (SHR(W|L|Q)const [8] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i] {s} p 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))
|
||||
-> (MOVWstore [i] {s} p0 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
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVWstore [i-1] {s} p w0 mem)
|
||||
(MOVWstore [i] {s} p (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p w mem))
|
||||
-> (MOVWstore [i-1] {s} p0 w0 mem)
|
||||
(MOVWstore [i] {s} p1 (SHR(L|Q)const [16] w) x:(MOVWstore [i-2] {s} p0 w mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVLstore [i-2] {s} p 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))
|
||||
-> (MOVLstore [i-2] {s} p0 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
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVLstore [i-2] {s} p w0 mem)
|
||||
(MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
|
||||
-> (MOVLstore [i-2] {s} p0 w0 mem)
|
||||
(MOVLstore [i] {s} p1 (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p0 w mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVQstore [i-4] {s} p w mem)
|
||||
(MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
|
||||
-> (MOVQstore [i-4] {s} p0 w mem)
|
||||
(MOVLstore [i] {s} p1 (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p0 w0:(SHRQconst [j-32] w) mem))
|
||||
&& x.Uses == 1
|
||||
&& same(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
-> (MOVQstore [i-4] {s} p 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)
|
||||
-> (MOVQstore [i-4] {s} p0 w0 mem)
|
||||
|
||||
(MOVBstore [i] {s} p
|
||||
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<<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
|
||||
// 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).
|
||||
|
@ -245,6 +245,7 @@ dd.ssa-prog {
|
||||
svg {
|
||||
cursor: default;
|
||||
outline: 1px solid #eee;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.darkmode {
|
||||
@ -975,7 +976,7 @@ func (d *dotWriter) writeFuncSVG(w io.Writer, phase string, f *Func) {
|
||||
fmt.Println(err)
|
||||
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)
|
||||
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"];`)
|
||||
|
@ -1305,9 +1305,9 @@ func isNonNegative(v *Value) bool {
|
||||
if !v.Type.IsInteger() {
|
||||
panic("isNonNegative bad type")
|
||||
}
|
||||
if !v.Type.IsSigned() {
|
||||
return true
|
||||
}
|
||||
// TODO: return true if !v.Type.IsSigned()
|
||||
// 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 {
|
||||
case OpConst64:
|
||||
|
@ -1247,3 +1247,43 @@ func read64(sym interface{}, off int64, byteorder binary.ByteOrder) uint64 {
|
||||
copy(buf, src)
|
||||
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.
|
||||
func (s *scanner) errorf(format string, args ...interface{}) {
|
||||
s.bad = true
|
||||
s.error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// 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{}) {
|
||||
s.bad = true
|
||||
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.
|
||||
//
|
||||
// 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) {
|
||||
s.bad = false
|
||||
|
||||
ok := true
|
||||
kind := IntLit
|
||||
base := 10 // number base
|
||||
prefix := rune(0) // one of 0 (decimal), '0' (0-octal), 'x', 'o', or 'b'
|
||||
digsep := 0 // bit 0: digit present, bit 1: '_' present
|
||||
@ -470,7 +477,6 @@ func (s *scanner) number(seenPoint bool) {
|
||||
|
||||
// integer part
|
||||
if !seenPoint {
|
||||
s.kind = IntLit
|
||||
if s.ch == '0' {
|
||||
s.nextch()
|
||||
switch lower(s.ch) {
|
||||
@ -491,7 +497,8 @@ func (s *scanner) number(seenPoint bool) {
|
||||
digsep |= s.digits(base, &invalid)
|
||||
if s.ch == '.' {
|
||||
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()
|
||||
seenPoint = true
|
||||
@ -500,68 +507,77 @@ func (s *scanner) number(seenPoint bool) {
|
||||
|
||||
// fractional part
|
||||
if seenPoint {
|
||||
s.kind = FloatLit
|
||||
kind = FloatLit
|
||||
digsep |= s.digits(base, &invalid)
|
||||
}
|
||||
|
||||
if digsep&1 == 0 && !s.bad {
|
||||
s.errorf("%s has no digits", litname(prefix))
|
||||
if digsep&1 == 0 && ok {
|
||||
s.errorf("%s literal has no digits", baseName(base))
|
||||
ok = false
|
||||
}
|
||||
|
||||
// exponent
|
||||
if e := lower(s.ch); e == 'e' || e == 'p' {
|
||||
if !s.bad {
|
||||
if ok {
|
||||
switch {
|
||||
case e == 'e' && prefix != 0 && prefix != '0':
|
||||
s.errorf("%q exponent requires decimal mantissa", s.ch)
|
||||
ok = false
|
||||
case e == 'p' && prefix != 'x':
|
||||
s.errorf("%q exponent requires hexadecimal mantissa", s.ch)
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
s.nextch()
|
||||
s.kind = FloatLit
|
||||
kind = FloatLit
|
||||
if s.ch == '+' || s.ch == '-' {
|
||||
s.nextch()
|
||||
}
|
||||
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")
|
||||
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")
|
||||
ok = false
|
||||
}
|
||||
|
||||
// suffix 'i'
|
||||
if s.ch == 'i' {
|
||||
s.kind = ImagLit
|
||||
kind = ImagLit
|
||||
s.nextch()
|
||||
}
|
||||
|
||||
s.nlsemi = true
|
||||
s.lit = string(s.segment())
|
||||
s.tok = _Literal
|
||||
s.setLit(kind, ok) // do this now so we can use s.lit below
|
||||
|
||||
if s.kind == IntLit && invalid >= 0 && !s.bad {
|
||||
s.errorAtf(invalid, "invalid digit %q in %s", s.lit[invalid], litname(prefix))
|
||||
if kind == IntLit && invalid >= 0 && ok {
|
||||
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 {
|
||||
s.errorAtf(i, "'_' must separate successive digits")
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
s.bad = !ok // correct s.bad
|
||||
}
|
||||
|
||||
func litname(prefix rune) string {
|
||||
switch prefix {
|
||||
case 'x':
|
||||
return "hexadecimal literal"
|
||||
case 'o', '0':
|
||||
return "octal literal"
|
||||
case 'b':
|
||||
return "binary literal"
|
||||
func baseName(base int) string {
|
||||
switch base {
|
||||
case 2:
|
||||
return "binary"
|
||||
case 8:
|
||||
return "octal"
|
||||
case 10:
|
||||
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.
|
||||
@ -605,17 +621,19 @@ func invalidSep(x string) int {
|
||||
}
|
||||
|
||||
func (s *scanner) rune() {
|
||||
s.bad = false
|
||||
ok := true
|
||||
s.nextch()
|
||||
|
||||
n := 0
|
||||
for ; ; n++ {
|
||||
if s.ch == '\'' {
|
||||
if !s.bad {
|
||||
if ok {
|
||||
if n == 0 {
|
||||
s.errorf("empty rune literal or unescaped '")
|
||||
ok = false
|
||||
} else if n != 1 {
|
||||
s.errorAtf(0, "more than one character in rune literal")
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
s.nextch()
|
||||
@ -623,32 +641,33 @@ func (s *scanner) rune() {
|
||||
}
|
||||
if s.ch == '\\' {
|
||||
s.nextch()
|
||||
s.escape('\'')
|
||||
if !s.escape('\'') {
|
||||
ok = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
if s.ch == '\n' {
|
||||
if !s.bad {
|
||||
if ok {
|
||||
s.errorf("newline in rune literal")
|
||||
ok = false
|
||||
}
|
||||
break
|
||||
}
|
||||
if s.ch < 0 {
|
||||
if !s.bad {
|
||||
if ok {
|
||||
s.errorAtf(0, "rune literal not terminated")
|
||||
ok = false
|
||||
}
|
||||
break
|
||||
}
|
||||
s.nextch()
|
||||
}
|
||||
|
||||
s.nlsemi = true
|
||||
s.lit = string(s.segment())
|
||||
s.kind = RuneLit
|
||||
s.tok = _Literal
|
||||
s.setLit(RuneLit, ok)
|
||||
}
|
||||
|
||||
func (s *scanner) stdString() {
|
||||
s.bad = false
|
||||
ok := true
|
||||
s.nextch()
|
||||
|
||||
for {
|
||||
@ -658,28 +677,29 @@ func (s *scanner) stdString() {
|
||||
}
|
||||
if s.ch == '\\' {
|
||||
s.nextch()
|
||||
s.escape('"')
|
||||
if !s.escape('"') {
|
||||
ok = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
if s.ch == '\n' {
|
||||
s.errorf("newline in string")
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
if s.ch < 0 {
|
||||
s.errorAtf(0, "string not terminated")
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
s.nextch()
|
||||
}
|
||||
|
||||
s.nlsemi = true
|
||||
s.lit = string(s.segment())
|
||||
s.kind = StringLit
|
||||
s.tok = _Literal
|
||||
s.setLit(StringLit, ok)
|
||||
}
|
||||
|
||||
func (s *scanner) rawString() {
|
||||
s.bad = false
|
||||
ok := true
|
||||
s.nextch()
|
||||
|
||||
for {
|
||||
@ -689,6 +709,7 @@ func (s *scanner) rawString() {
|
||||
}
|
||||
if s.ch < 0 {
|
||||
s.errorAtf(0, "string not terminated")
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
s.nextch()
|
||||
@ -697,10 +718,7 @@ func (s *scanner) rawString() {
|
||||
// literal (even though they are not part of the literal
|
||||
// value).
|
||||
|
||||
s.nlsemi = true
|
||||
s.lit = string(s.segment())
|
||||
s.kind = StringLit
|
||||
s.tok = _Literal
|
||||
s.setLit(StringLit, ok)
|
||||
}
|
||||
|
||||
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 base, max uint32
|
||||
|
||||
switch s.ch {
|
||||
case quote, 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
|
||||
s.nextch()
|
||||
return
|
||||
return true
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
n, base, max = 3, 8, 255
|
||||
case 'x':
|
||||
@ -818,16 +836,16 @@ func (s *scanner) escape(quote rune) {
|
||||
n, base, max = 8, 16, unicode.MaxRune
|
||||
default:
|
||||
if s.ch < 0 {
|
||||
return // complain in caller about EOF
|
||||
return true // complain in caller about EOF
|
||||
}
|
||||
s.errorf("unknown escape")
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
var x uint32
|
||||
for i := n; i > 0; i-- {
|
||||
if s.ch < 0 {
|
||||
return // complain in caller about EOF
|
||||
return true // complain in caller about EOF
|
||||
}
|
||||
d := base
|
||||
if isDecimal(s.ch) {
|
||||
@ -836,12 +854,8 @@ func (s *scanner) escape(quote rune) {
|
||||
d = uint32(lower(s.ch)) - 'a' + 10
|
||||
}
|
||||
if d >= base {
|
||||
kind := "hex"
|
||||
if base == 8 {
|
||||
kind = "octal"
|
||||
}
|
||||
s.errorf("invalid character %q in %s escape", s.ch, kind)
|
||||
return
|
||||
s.errorf("invalid character %q in %s escape", s.ch, baseName(int(base)))
|
||||
return false
|
||||
}
|
||||
// d < base
|
||||
x = x*base + d
|
||||
@ -850,10 +864,13 @@ func (s *scanner) escape(quote rune) {
|
||||
|
||||
if x > max && base == 8 {
|
||||
s.errorf("octal escape value %d > 255", x)
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
if x > max || 0xD800 <= x && x < 0xE000 /* surrogate range */ {
|
||||
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},
|
||||
{`'\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},
|
||||
{`'\x0'`, "invalid character '\\'' in hex escape", 0, 4},
|
||||
{`'\x0'`, "invalid character '\\'' in hexadecimal escape", 0, 4},
|
||||
{`'\00'`, "invalid character '\\'' in octal escape", 0, 4},
|
||||
{`'\377' /*`, "comment not terminated", 0, 7}, // valid octal escape
|
||||
{`'\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},
|
||||
{`"\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},
|
||||
{`"\x0"`, "invalid character '\"' in hex escape", 0, 4},
|
||||
{`"\x0"`, "invalid character '\"' in hexadecimal escape", 0, 4},
|
||||
{`"\00"`, "invalid character '\"' in octal escape", 0, 4},
|
||||
{`"\377" /*`, "comment not terminated", 0, 7}, // valid octal escape
|
||||
{`"\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\z00\nbar"`, "unknown escape", 0, 10},
|
||||
{`"\x`, "string not terminated", 0, 0},
|
||||
{`"\x"`, "invalid character '\"' in hex escape", 0, 3},
|
||||
{`var s string = "\x"`, "invalid character '\"' in hex escape", 0, 18},
|
||||
{`"\x"`, "invalid character '\"' in hexadecimal escape", 0, 3},
|
||||
{`var s string = "\x"`, "invalid character '\"' in hexadecimal escape", 0, 18},
|
||||
{`return "\Uffffffff"`, "escape is invalid Unicode code point U+FFFFFFFF", 0, 18},
|
||||
|
||||
{"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) {
|
||||
s := "/*" + strings.Repeat(" ", 4089) + "*/ .5"
|
||||
|
||||
|
@ -293,6 +293,11 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
|
||||
ast.Walk(f, n.Assign)
|
||||
return nil
|
||||
}
|
||||
case *ast.FuncDecl:
|
||||
// Don't annotate functions with blank names - they cannot be executed.
|
||||
if n.Name.Name == "_" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
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")))
|
||||
}
|
||||
|
||||
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 {
|
||||
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)))
|
||||
if flag.NArg() > 0 && t.runRxStr != "" {
|
||||
|
@ -3,11 +3,10 @@ module cmd
|
||||
go 1.14
|
||||
|
||||
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/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||
golang.org/x/mod v0.2.0
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c // indirect
|
||||
golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca
|
||||
)
|
||||
|
@ -1,8 +1,9 @@
|
||||
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/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-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3 h1:SRgJV+IoxM5MKyFdlSUeNy6/ycRUF2yBAKdAQswoHUk=
|
||||
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/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
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-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||
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/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-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-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-20190412213103-97732733099d/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/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-20200219195521-7c4b6277d74d h1:ZQ18He7VORO2x4IEBuwfdp56K+ftEzRjvL0cFuCGCcM=
|
||||
golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca h1:cFQHQhDv9N1vc+64dtXDAyd3exHDGfRTtveOnD0IsLI=
|
||||
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-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
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) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
testenv.MustHaveExecPath(t, "git")
|
||||
testenv.MustHaveExecPath(t, "svn")
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@ -2208,15 +2209,10 @@ func testBuildmodePIE(t *testing.T, useCgo bool) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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 {
|
||||
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")
|
||||
}
|
||||
var dc uint16
|
||||
@ -2225,13 +2221,13 @@ func testBuildmodePIE(t *testing.T, useCgo bool) {
|
||||
dc = oh.DllCharacteristics
|
||||
case *pe.OptionalHeader64:
|
||||
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")
|
||||
}
|
||||
default:
|
||||
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")
|
||||
}
|
||||
default:
|
||||
|
@ -10,10 +10,12 @@ import "net/http"
|
||||
// AddCredentials fills in the user's credentials for req, if any.
|
||||
// The return value reports whether any matching credentials were found.
|
||||
func AddCredentials(req *http.Request) (added bool) {
|
||||
host := req.URL.Hostname()
|
||||
|
||||
// TODO(golang.org/issue/26232): Support arbitrary user-provided credentials.
|
||||
netrcOnce.Do(readNetrc)
|
||||
for _, l := range netrc {
|
||||
if l.machine == req.URL.Host {
|
||||
if l.machine == host {
|
||||
req.SetBasicAuth(l.login, l.password)
|
||||
return true
|
||||
}
|
||||
|
@ -13,19 +13,19 @@
|
||||
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
||||
// does not require per-inode bookkeeping in the application.
|
||||
//
|
||||
// TODO(bcmills): If we add a build tag for Illumos (see golang.org/issue/20603)
|
||||
// then Illumos should use F_OFD_SETLK, and the resulting code would be as
|
||||
// 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.
|
||||
// TODO(golang.org/issue/35618): add a syscall.Flock binding for Illumos and
|
||||
// switch it over to use filelock_unix.go.
|
||||
|
||||
package filelock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type lockType int16
|
||||
@ -91,7 +91,67 @@ func lock(f File, lt lockType) (err error) {
|
||||
wait <- f
|
||||
}
|
||||
|
||||
err = setlkw(f.Fd(), lt)
|
||||
// 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)
|
||||
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 {
|
||||
unlock(f)
|
||||
|
@ -8,8 +8,11 @@
|
||||
package lockedfile_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
@ -172,3 +175,98 @@ func TestCanLockExistingFile(t *testing.T) {
|
||||
f.Close()
|
||||
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 (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -67,12 +68,10 @@ func verifyMod(mod module.Version) bool {
|
||||
_, zipErr = os.Stat(zip)
|
||||
}
|
||||
dir, dirErr := modfetch.DownloadDir(mod)
|
||||
if dirErr == nil {
|
||||
_, dirErr = os.Stat(dir)
|
||||
}
|
||||
data, err := ioutil.ReadFile(zip + "hash")
|
||||
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.
|
||||
return true
|
||||
}
|
||||
@ -81,7 +80,7 @@ func verifyMod(mod module.Version) bool {
|
||||
}
|
||||
h := string(bytes.TrimSpace(data))
|
||||
|
||||
if zipErr != nil && os.IsNotExist(zipErr) {
|
||||
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
|
||||
// ok
|
||||
} else {
|
||||
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
||||
@ -93,7 +92,7 @@ func verifyMod(mod module.Version) bool {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
if dirErr != nil && os.IsNotExist(dirErr) {
|
||||
if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
||||
// ok
|
||||
} else {
|
||||
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
||||
|
@ -7,6 +7,7 @@ package modfetch
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -56,8 +57,11 @@ func CachePath(m module.Version, suffix string) (string, error) {
|
||||
return filepath.Join(dir, encVer+"."+suffix), nil
|
||||
}
|
||||
|
||||
// DownloadDir returns the directory to which m should be downloaded.
|
||||
// Note that the directory may not yet exist.
|
||||
// DownloadDir returns the directory to which m should have been downloaded.
|
||||
// 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) {
|
||||
if PkgMod == "" {
|
||||
return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
|
||||
@ -76,9 +80,39 @@ func DownloadDir(m module.Version) (string, error) {
|
||||
if err != nil {
|
||||
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
|
||||
// and extraction of the zipfile for the given module version.
|
||||
func lockVersion(mod module.Version) (unlock func(), err error) {
|
||||
|
@ -563,7 +563,7 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
|
||||
return err
|
||||
}
|
||||
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 := ""
|
||||
|
@ -46,24 +46,26 @@ func Download(mod module.Version) (dir string, err error) {
|
||||
err error
|
||||
}
|
||||
c := downloadCache.Do(mod, func() interface{} {
|
||||
dir, err := DownloadDir(mod)
|
||||
dir, err := download(mod)
|
||||
if err != nil {
|
||||
return cached{"", err}
|
||||
}
|
||||
if err := download(mod, dir); err != nil {
|
||||
return cached{"", err}
|
||||
}
|
||||
checkMod(mod)
|
||||
return cached{dir, nil}
|
||||
}).(cached)
|
||||
return c.dir, c.err
|
||||
}
|
||||
|
||||
func download(mod module.Version, dir string) (err error) {
|
||||
// If the directory exists, the module has already been extracted.
|
||||
fi, err := os.Stat(dir)
|
||||
if err == nil && fi.IsDir() {
|
||||
return nil
|
||||
func download(mod module.Version) (dir string, err error) {
|
||||
// If the directory exists, and no .partial file exists, the module has
|
||||
// already been completely extracted. .partial files may be created when a
|
||||
// module zip directory is extracted in place instead of being extracted to a
|
||||
// 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,
|
||||
@ -71,22 +73,24 @@ func download(mod module.Version, dir string) (err error) {
|
||||
// Invoke DownloadZip before locking the file.
|
||||
zipfile, err := DownloadZip(mod)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
unlock, err := lockVersion(mod)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
// Check whether the directory was populated while we were waiting on the lock.
|
||||
fi, err = os.Stat(dir)
|
||||
if err == nil && fi.IsDir() {
|
||||
return nil
|
||||
_, dirErr := DownloadDir(mod)
|
||||
if dirErr == 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
|
||||
// are no longer active.
|
||||
parentDir := filepath.Dir(dir)
|
||||
@ -96,35 +100,75 @@ func download(mod module.Version, dir string) (err error) {
|
||||
RemoveAll(path) // best effort
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the zip file to a temporary directory, then rename it to the
|
||||
// final path. That way, we can use the existence of the source directory to
|
||||
// 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
|
||||
}
|
||||
tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
RemoveAll(tmpDir)
|
||||
if dirExists {
|
||||
if err := RemoveAll(dir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}()
|
||||
|
||||
if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "-> %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := robustio.Rename(tmpDir, dir); 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)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "-> %s\n", err)
|
||||
RemoveAll(tmpDir)
|
||||
return "", err
|
||||
}
|
||||
if err := robustio.Rename(tmpDir, dir); err != nil {
|
||||
RemoveAll(tmpDir)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
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
|
||||
@ -306,7 +361,7 @@ func RemoveAll(dir string) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return os.RemoveAll(dir)
|
||||
return robustio.RemoveAll(dir)
|
||||
}
|
||||
|
||||
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-]+)*)?$`)
|
||||
|
||||
const pseudoVersionTimestampFormat = "20060102150405"
|
||||
|
||||
// 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,
|
||||
// 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 == "" {
|
||||
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)
|
||||
older = semver.Canonical(older)
|
||||
if older == "" {
|
||||
|
@ -148,9 +148,7 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
|
||||
}
|
||||
dir, err := modfetch.DownloadDir(mod)
|
||||
if err == nil {
|
||||
if info, err := os.Stat(dir); err == nil && info.IsDir() {
|
||||
m.Dir = dir
|
||||
}
|
||||
m.Dir = dir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,27 +59,6 @@ var (
|
||||
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.
|
||||
//
|
||||
// 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() {
|
||||
if modFile == nil {
|
||||
path, err := findModulePath(modRoot)
|
||||
@ -983,113 +867,3 @@ func WriteGoMod() {
|
||||
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"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
@ -27,9 +25,7 @@ import (
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// buildList is the list of modules to use for building packages.
|
||||
@ -1033,354 +1029,3 @@ func WhyDepth(path string) int {
|
||||
}
|
||||
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"
|
||||
)
|
||||
|
||||
const arbitraryTimeout = 500 * time.Millisecond
|
||||
const arbitraryTimeout = 2000 * time.Millisecond
|
||||
|
||||
// retry retries ephemeral errors from f up to an arbitrary timeout
|
||||
// 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 {
|
||||
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, "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)
|
||||
|
@ -109,6 +109,7 @@ func (ts *testScript) setup() {
|
||||
"CCACHE_DISABLE=1", // ccache breaks with non-existent HOME
|
||||
"GOARCH=" + runtime.GOARCH,
|
||||
"GOCACHE=" + testGOCACHE,
|
||||
"GODEBUG=" + os.Getenv("GODEBUG"),
|
||||
"GOEXE=" + cfg.ExeSuffix,
|
||||
"GOOS=" + runtime.GOOS,
|
||||
"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
|
||||
PATH=<actual PATH>
|
||||
TMPDIR=$WORK/tmp
|
||||
GODEBUG=<actual GODEBUG>
|
||||
devnull=<value of os.DevNull>
|
||||
goversion=<current Go version; for example, 1.12>
|
||||
:=<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
|
||||
[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'
|
||||
|
||||
-- override.go --
|
||||
|
@ -1,15 +1,16 @@
|
||||
[short] 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".*"-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[^"]+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 --
|
||||
package main
|
||||
// #cgo CFLAGS: -I"c flags"
|
||||
// #cgo LDFLAGS: -L"ld flags"
|
||||
import "C"
|
||||
func main() {}
|
||||
func 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'
|
||||
[short] skip
|
||||
|
||||
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||
|
||||
# -gcflags=-e applies to named packages, not dependencies
|
||||
go build -n -v -gcflags=-e z1 z2
|
||||
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
|
||||
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 --
|
||||
module m
|
||||
go 1.8
|
||||
|
@ -14,6 +14,9 @@ go get -d golang.org/x/text@14c0d48
|
||||
|
||||
# dropping -d, we should see a build.
|
||||
[short] skip
|
||||
|
||||
env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache.
|
||||
|
||||
go get -x golang.org/x/text/language@14c0d48
|
||||
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
|
||||
|
||||
# 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 example.com/version '
|
||||
! 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
|
||||
cd outside
|
||||
! 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 ..
|
||||
! 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
|
||||
# with a valid one.
|
||||
go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c
|
||||
cd outside
|
||||
! 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 ..
|
||||
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'
|
||||
|
@ -47,6 +47,7 @@ func findGorootModules(t *testing.T) []gorootModule {
|
||||
// Use 'go list' to describe the module contained in this directory (but
|
||||
// not its dependencies).
|
||||
cmd := exec.Command(goBin, "list", "-json", "-m")
|
||||
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||
cmd.Dir = dir
|
||||
cmd.Stderr = new(strings.Builder)
|
||||
out, err := cmd.Output()
|
||||
@ -103,6 +104,7 @@ func TestAllDependenciesVendored(t *testing.T) {
|
||||
// dependencies are vendored. If any imported package is missing,
|
||||
// 'go list -deps' will fail when attempting to load it.
|
||||
cmd := exec.Command(goBin, "list", "-mod=vendor", "-deps", "./...")
|
||||
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||
cmd.Dir = m.Dir
|
||||
cmd.Stderr = new(strings.Builder)
|
||||
_, err := cmd.Output()
|
||||
@ -115,7 +117,8 @@ func TestAllDependenciesVendored(t *testing.T) {
|
||||
|
||||
// There is no vendor directory, so the module must have no dependencies.
|
||||
// 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.Stderr = new(strings.Builder)
|
||||
out, err := cmd.Output()
|
||||
|
@ -944,22 +944,16 @@ const (
|
||||
ASTXVW4X
|
||||
ASTXVH8X
|
||||
ASTXVB16X
|
||||
ALXS
|
||||
ALXSDX
|
||||
ASTXS
|
||||
ASTXSDX
|
||||
ALXSI
|
||||
ALXSIWAX
|
||||
ALXSIWZX
|
||||
ASTXSI
|
||||
ASTXSIWX
|
||||
AMFVSR
|
||||
AMFVSRD
|
||||
AMFFPRD
|
||||
AMFVRD
|
||||
AMFVSRWZ
|
||||
AMFVSRLD
|
||||
AMTVSR
|
||||
AMTVSRD
|
||||
AMTFPRD
|
||||
AMTVRD
|
||||
@ -968,7 +962,6 @@ const (
|
||||
AMTVSRDD
|
||||
AMTVSRWS
|
||||
AXXLAND
|
||||
AXXLANDQ
|
||||
AXXLANDC
|
||||
AXXLEQV
|
||||
AXXLNAND
|
||||
@ -978,34 +971,27 @@ const (
|
||||
AXXLORQ
|
||||
AXXLXOR
|
||||
AXXSEL
|
||||
AXXMRG
|
||||
AXXMRGHW
|
||||
AXXMRGLW
|
||||
AXXSPLT
|
||||
AXXSPLTW
|
||||
AXXPERM
|
||||
AXXPERMDI
|
||||
AXXSI
|
||||
AXXSLDWI
|
||||
AXSCV
|
||||
AXSCVDPSP
|
||||
AXSCVSPDP
|
||||
AXSCVDPSPN
|
||||
AXSCVSPDPN
|
||||
AXVCV
|
||||
AXVCVDPSP
|
||||
AXVCVSPDP
|
||||
AXSCVX
|
||||
AXSCVDPSXDS
|
||||
AXSCVDPSXWS
|
||||
AXSCVDPUXDS
|
||||
AXSCVDPUXWS
|
||||
AXSCVXP
|
||||
AXSCVSXDDP
|
||||
AXSCVUXDDP
|
||||
AXSCVSXDSP
|
||||
AXSCVUXDSP
|
||||
AXVCVX
|
||||
AXVCVDPSXDS
|
||||
AXVCVDPSXWS
|
||||
AXVCVDPUXDS
|
||||
@ -1014,7 +1000,6 @@ const (
|
||||
AXVCVSPSXWS
|
||||
AXVCVSPUXDS
|
||||
AXVCVSPUXWS
|
||||
AXVCVXP
|
||||
AXVCVSXDDP
|
||||
AXVCVSXWDP
|
||||
AXVCVUXDDP
|
||||
|
@ -532,22 +532,16 @@ var Anames = []string{
|
||||
"STXVW4X",
|
||||
"STXVH8X",
|
||||
"STXVB16X",
|
||||
"LXS",
|
||||
"LXSDX",
|
||||
"STXS",
|
||||
"STXSDX",
|
||||
"LXSI",
|
||||
"LXSIWAX",
|
||||
"LXSIWZX",
|
||||
"STXSI",
|
||||
"STXSIWX",
|
||||
"MFVSR",
|
||||
"MFVSRD",
|
||||
"MFFPRD",
|
||||
"MFVRD",
|
||||
"MFVSRWZ",
|
||||
"MFVSRLD",
|
||||
"MTVSR",
|
||||
"MTVSRD",
|
||||
"MTFPRD",
|
||||
"MTVRD",
|
||||
@ -556,7 +550,6 @@ var Anames = []string{
|
||||
"MTVSRDD",
|
||||
"MTVSRWS",
|
||||
"XXLAND",
|
||||
"XXLANDQ",
|
||||
"XXLANDC",
|
||||
"XXLEQV",
|
||||
"XXLNAND",
|
||||
@ -566,34 +559,27 @@ var Anames = []string{
|
||||
"XXLORQ",
|
||||
"XXLXOR",
|
||||
"XXSEL",
|
||||
"XXMRG",
|
||||
"XXMRGHW",
|
||||
"XXMRGLW",
|
||||
"XXSPLT",
|
||||
"XXSPLTW",
|
||||
"XXPERM",
|
||||
"XXPERMDI",
|
||||
"XXSI",
|
||||
"XXSLDWI",
|
||||
"XSCV",
|
||||
"XSCVDPSP",
|
||||
"XSCVSPDP",
|
||||
"XSCVDPSPN",
|
||||
"XSCVSPDPN",
|
||||
"XVCV",
|
||||
"XVCVDPSP",
|
||||
"XVCVSPDP",
|
||||
"XSCVX",
|
||||
"XSCVDPSXDS",
|
||||
"XSCVDPSXWS",
|
||||
"XSCVDPUXDS",
|
||||
"XSCVDPUXWS",
|
||||
"XSCVXP",
|
||||
"XSCVSXDDP",
|
||||
"XSCVUXDDP",
|
||||
"XSCVSXDSP",
|
||||
"XSCVUXDSP",
|
||||
"XVCVX",
|
||||
"XVCVDPSXDS",
|
||||
"XVCVDPSXWS",
|
||||
"XVCVDPUXDS",
|
||||
@ -602,7 +588,6 @@ var Anames = []string{
|
||||
"XVCVSPSXWS",
|
||||
"XVCVSPUXDS",
|
||||
"XVCVSPUXWS",
|
||||
"XVCVXP",
|
||||
"XVCVSXDDP",
|
||||
"XVCVSXWDP",
|
||||
"XVCVUXDDP",
|
||||
|
@ -462,10 +462,10 @@ var optab = []Optab{
|
||||
{AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector select, va-form */
|
||||
|
||||
/* Vector splat */
|
||||
{AVSPLT, 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},
|
||||
{AVSPLTI, 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},
|
||||
{AVSPLTB, C_SCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector splat, vx-form */
|
||||
{AVSPLTB, C_ADDCON, C_VREG, C_NONE, C_VREG, 82, 4, 0},
|
||||
{AVSPLTISB, C_SCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector splat immediate, vx-form */
|
||||
{AVSPLTISB, C_ADDCON, C_NONE, C_NONE, C_VREG, 82, 4, 0},
|
||||
|
||||
/* Vector AES */
|
||||
{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 */
|
||||
|
||||
/* 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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{AMFVSR, 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},
|
||||
{AMFVSR, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
||||
{AMFVSRD, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */
|
||||
{AMFVSRD, C_FREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
||||
{AMFVSRD, C_VREG, C_NONE, C_NONE, C_REG, 88, 4, 0},
|
||||
|
||||
/* VSX move to VSR */
|
||||
{AMTVSR, 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},
|
||||
{AMTVSR, 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_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */
|
||||
{AMTVSRD, C_REG, C_REG, C_NONE, C_VSREG, 88, 4, 0},
|
||||
{AMTVSRD, C_REG, C_NONE, C_NONE, C_FREG, 88, 4, 0},
|
||||
{AMTVSRD, C_REG, C_NONE, C_NONE, C_VREG, 88, 4, 0},
|
||||
|
||||
/* VSX logical */
|
||||
{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 */
|
||||
|
||||
/* 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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{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 */
|
||||
{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
|
||||
@ -1519,13 +1519,11 @@ func buildop(ctxt *obj.Link) {
|
||||
case AVSEL: /* vsel */
|
||||
opset(AVSEL, r0)
|
||||
|
||||
case AVSPLT: /* vspltb, vsplth, vspltw */
|
||||
opset(AVSPLTB, r0)
|
||||
case AVSPLTB: /* vspltb, vsplth, vspltw */
|
||||
opset(AVSPLTH, r0)
|
||||
opset(AVSPLTW, r0)
|
||||
|
||||
case AVSPLTI: /* vspltisb, vspltish, vspltisw */
|
||||
opset(AVSPLTISB, r0)
|
||||
case AVSPLTISB: /* vspltisb, vspltish, vspltisw */
|
||||
opset(AVSPLTISH, r0)
|
||||
opset(AVSPLTISW, r0)
|
||||
|
||||
@ -1561,28 +1559,25 @@ func buildop(ctxt *obj.Link) {
|
||||
case ASTXV: /* stxv */
|
||||
opset(ASTXV, r0)
|
||||
|
||||
case ALXS: /* lxsdx */
|
||||
case ALXSDX: /* lxsdx */
|
||||
opset(ALXSDX, r0)
|
||||
|
||||
case ASTXS: /* stxsdx */
|
||||
case ASTXSDX: /* stxsdx */
|
||||
opset(ASTXSDX, r0)
|
||||
|
||||
case ALXSI: /* lxsiwax, lxsiwzx */
|
||||
opset(ALXSIWAX, r0)
|
||||
case ALXSIWAX: /* lxsiwax, lxsiwzx */
|
||||
opset(ALXSIWZX, r0)
|
||||
|
||||
case ASTXSI: /* stxsiwx */
|
||||
case ASTXSIWX: /* stxsiwx */
|
||||
opset(ASTXSIWX, r0)
|
||||
|
||||
case AMFVSR: /* mfvsrd, mfvsrwz (and extended mnemonics), mfvsrld */
|
||||
opset(AMFVSRD, r0)
|
||||
case AMFVSRD: /* mfvsrd, mfvsrwz (and extended mnemonics), mfvsrld */
|
||||
opset(AMFFPRD, r0)
|
||||
opset(AMFVRD, r0)
|
||||
opset(AMFVSRWZ, r0)
|
||||
opset(AMFVSRLD, r0)
|
||||
|
||||
case AMTVSR: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics), mtvsrdd, mtvsrws */
|
||||
opset(AMTVSRD, r0)
|
||||
case AMTVSRD: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics), mtvsrdd, mtvsrws */
|
||||
opset(AMTFPRD, r0)
|
||||
opset(AMTVRD, r0)
|
||||
opset(AMTVSRWA, r0)
|
||||
@ -1591,7 +1586,6 @@ func buildop(ctxt *obj.Link) {
|
||||
opset(AMTVSRWS, r0)
|
||||
|
||||
case AXXLAND: /* xxland, xxlandc, xxleqv, xxlnand */
|
||||
opset(AXXLANDQ, r0)
|
||||
opset(AXXLANDC, r0)
|
||||
opset(AXXLEQV, r0)
|
||||
opset(AXXLNAND, r0)
|
||||
@ -1605,42 +1599,38 @@ func buildop(ctxt *obj.Link) {
|
||||
case AXXSEL: /* xxsel */
|
||||
opset(AXXSEL, r0)
|
||||
|
||||
case AXXMRG: /* xxmrghw, xxmrglw */
|
||||
opset(AXXMRGHW, r0)
|
||||
case AXXMRGHW: /* xxmrghw, xxmrglw */
|
||||
opset(AXXMRGLW, r0)
|
||||
|
||||
case AXXSPLT: /* xxspltw */
|
||||
case AXXSPLTW: /* xxspltw */
|
||||
opset(AXXSPLTW, r0)
|
||||
|
||||
case AXXPERM: /* xxpermdi */
|
||||
opset(AXXPERMDI, r0)
|
||||
opset(AXXPERM, r0)
|
||||
|
||||
case AXXSI: /* xxsldwi */
|
||||
case AXXSLDWI: /* xxsldwi */
|
||||
opset(AXXPERMDI, r0)
|
||||
opset(AXXSLDWI, r0)
|
||||
|
||||
case AXSCV: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
|
||||
opset(AXSCVDPSP, r0)
|
||||
case AXSCVDPSP: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
|
||||
opset(AXSCVSPDP, r0)
|
||||
opset(AXSCVDPSPN, r0)
|
||||
opset(AXSCVSPDPN, r0)
|
||||
|
||||
case AXVCV: /* xvcvdpsp, xvcvspdp */
|
||||
opset(AXVCVDPSP, r0)
|
||||
case AXVCVDPSP: /* xvcvdpsp, xvcvspdp */
|
||||
opset(AXVCVSPDP, r0)
|
||||
|
||||
case AXSCVX: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
|
||||
opset(AXSCVDPSXDS, r0)
|
||||
case AXSCVDPSXDS: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
|
||||
opset(AXSCVDPSXWS, r0)
|
||||
opset(AXSCVDPUXDS, r0)
|
||||
opset(AXSCVDPUXWS, r0)
|
||||
|
||||
case AXSCVXP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
|
||||
opset(AXSCVSXDDP, r0)
|
||||
case AXSCVSXDDP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
|
||||
opset(AXSCVUXDDP, r0)
|
||||
opset(AXSCVSXDSP, 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(AXVCVDPSXWS, r0)
|
||||
opset(AXVCVDPUXDS, r0)
|
||||
@ -1650,8 +1640,7 @@ func buildop(ctxt *obj.Link) {
|
||||
opset(AXVCVSPUXDS, r0)
|
||||
opset(AXVCVSPUXWS, r0)
|
||||
|
||||
case AXVCVXP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
|
||||
opset(AXVCVSXDDP, r0)
|
||||
case AXVCVSXDDP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
|
||||
opset(AXVCVSXWDP, r0)
|
||||
opset(AXVCVUXDDP, r0)
|
||||
opset(AXVCVUXWDP, r0)
|
||||
@ -4616,7 +4605,7 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
|
||||
case AMTVSRWS:
|
||||
return OPVXX1(31, 403, 0) /* mtvsrws - v3.00 */
|
||||
|
||||
case AXXLANDQ:
|
||||
case AXXLAND:
|
||||
return OPVXX3(60, 130, 0) /* xxland - v2.06 */
|
||||
case AXXLANDC:
|
||||
return OPVXX3(60, 138, 0) /* xxlandc - v2.06 */
|
||||
@ -4645,6 +4634,8 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
|
||||
case AXXSPLTW:
|
||||
return OPVXX2(60, 164, 0) /* xxspltw - v2.06 */
|
||||
|
||||
case AXXPERM:
|
||||
return OPVXX3(60, 26, 0) /* xxperm - v2.06 */
|
||||
case AXXPERMDI:
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -1239,6 +1239,7 @@ func TestPackageNameAttr(t *testing.T) {
|
||||
}
|
||||
|
||||
rdr := d.Reader()
|
||||
runtimeUnitSeen := false
|
||||
for {
|
||||
e, err := rdr.Next()
|
||||
if err != nil {
|
||||
@ -1254,11 +1255,25 @@ func TestPackageNameAttr(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
_, ok := e.Val(dwarfAttrGoPackageName).(string)
|
||||
pn, ok := e.Val(dwarfAttrGoPackageName).(string)
|
||||
if !ok {
|
||||
name, _ := e.Val(dwarf.AttrName).(string)
|
||||
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,47 +58,15 @@ var (
|
||||
)
|
||||
|
||||
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_INITIALIZED_DATA = 0x00000040
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000
|
||||
IMAGE_SCN_MEM_READ = 0x40000000
|
||||
IMAGE_SCN_MEM_WRITE = 0x80000000
|
||||
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
|
||||
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
|
||||
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
|
||||
IMAGE_SCN_CNT_CODE = 0x00000020
|
||||
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
|
||||
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000
|
||||
IMAGE_SCN_MEM_READ = 0x40000000
|
||||
IMAGE_SCN_MEM_WRITE = 0x80000000
|
||||
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
|
||||
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
|
||||
IMAGE_SCN_ALIGN_32BYTES = 0x600000
|
||||
)
|
||||
|
||||
// TODO(crawshaw): add these constants to debug/pe.
|
||||
@ -762,11 +730,11 @@ func (f *peFile) writeFileHeader(ctxt *Link) {
|
||||
default:
|
||||
Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
|
||||
case sys.AMD64:
|
||||
fh.Machine = IMAGE_FILE_MACHINE_AMD64
|
||||
fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
|
||||
case sys.I386:
|
||||
fh.Machine = IMAGE_FILE_MACHINE_I386
|
||||
fh.Machine = pe.IMAGE_FILE_MACHINE_I386
|
||||
case sys.ARM:
|
||||
fh.Machine = IMAGE_FILE_MACHINE_ARMNT
|
||||
fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
|
||||
}
|
||||
|
||||
fh.NumberOfSections = uint16(len(f.sections))
|
||||
@ -776,24 +744,24 @@ func (f *peFile) writeFileHeader(ctxt *Link) {
|
||||
fh.TimeDateStamp = 0
|
||||
|
||||
if ctxt.LinkMode == LinkExternal {
|
||||
fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||
fh.Characteristics = pe.IMAGE_FILE_LINE_NUMS_STRIPPED
|
||||
} 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 {
|
||||
case sys.AMD64, sys.I386:
|
||||
if ctxt.BuildMode != BuildModePIE {
|
||||
fh.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED
|
||||
fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
|
||||
}
|
||||
}
|
||||
}
|
||||
if pe64 != 0 {
|
||||
var oh64 pe.OptionalHeader64
|
||||
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
|
||||
fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
|
||||
fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
|
||||
} else {
|
||||
var oh pe.OptionalHeader32
|
||||
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
|
||||
fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
|
||||
fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
|
||||
}
|
||||
|
||||
fh.PointerToSymbolTable = uint32(f.symtabOffset)
|
||||
@ -854,36 +822,36 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
|
||||
oh64.SizeOfHeaders = uint32(PEFILEHEADR)
|
||||
oh.SizeOfHeaders = uint32(PEFILEHEADR)
|
||||
if windowsgui {
|
||||
oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||
oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||
oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||
oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||
} else {
|
||||
oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||
oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||
oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||
oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
|
||||
}
|
||||
|
||||
// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
|
||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
|
||||
|
||||
// Enable DEP
|
||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
|
||||
|
||||
// The DLL can be relocated at load time.
|
||||
switch ctxt.Arch.Family {
|
||||
case sys.AMD64, sys.I386:
|
||||
if ctxt.BuildMode == BuildModePIE {
|
||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
}
|
||||
case sys.ARM:
|
||||
oh64.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
|
||||
}
|
||||
|
||||
// Image can handle a high entropy 64-bit virtual address space.
|
||||
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
|
||||
@ -1229,10 +1197,10 @@ func addimports(ctxt *Link, datsect *peSection) {
|
||||
out.Write32(0)
|
||||
|
||||
// update data directory
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
|
||||
pefile.dataDirectory[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_IMPORT].VirtualAddress = isect.virtualAddress
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
|
||||
|
||||
out.SeekSet(endoff)
|
||||
}
|
||||
@ -1272,8 +1240,8 @@ func addexports(ctxt *Link) {
|
||||
sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
|
||||
sect.checkOffset(ctxt.Out.Offset())
|
||||
va := int(sect.virtualAddress)
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
|
||||
|
||||
vaName := va + binary.Size(&e) + nexport*4
|
||||
vaAddr := va + binary.Size(&e)
|
||||
@ -1481,8 +1449,8 @@ func addPEBaseReloc(ctxt *Link) {
|
||||
rsect.checkOffset(startoff)
|
||||
rsect.pad(ctxt.Out, uint32(size))
|
||||
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
|
||||
pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
|
||||
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
|
||||
}
|
||||
|
||||
func (ctxt *Link) dope() {
|
||||
@ -1528,9 +1496,9 @@ func addpersrc(ctxt *Link) {
|
||||
h.pad(ctxt.Out, uint32(size))
|
||||
|
||||
// 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) {
|
||||
|
@ -106,8 +106,11 @@ func testDisasm(t *testing.T, printCode bool, flags ...string) {
|
||||
hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash))
|
||||
args := []string{"build", "-o", hello}
|
||||
args = append(args, flags...)
|
||||
args = append(args, "testdata/fmthello.go")
|
||||
out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
|
||||
args = append(args, "fmthello.go")
|
||||
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 {
|
||||
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...)
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
Println("hello, world")
|
||||
if flag {
|
||||
//line fmthello.go:999999
|
||||
Println("bad line")
|
||||
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{})
|
||||
for _, sample := range prof.Sample {
|
||||
var stack graph.Nodes
|
||||
type stk struct {
|
||||
*graph.NodeInfo
|
||||
inline bool
|
||||
}
|
||||
var stack []stk
|
||||
for _, loc := range sample.Location {
|
||||
id := loc.ID
|
||||
stack = append(stack, locations[id]...)
|
||||
nodes := locations[loc.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 {
|
||||
@ -875,10 +884,15 @@ func printTraces(w io.Writer, rpt *Report) error {
|
||||
if d != 0 {
|
||||
v = v / d
|
||||
}
|
||||
fmt.Fprintf(w, "%10s %s\n",
|
||||
rpt.formatValue(v), stack[0].Info.PrintableName())
|
||||
for _, s := range stack[1:] {
|
||||
fmt.Fprintf(w, "%10s %s\n", "", s.Info.PrintableName())
|
||||
for i, s := range stack {
|
||||
var vs, inline string
|
||||
if i == 0 {
|
||||
vs = rpt.formatValue(v)
|
||||
}
|
||||
if s.inline {
|
||||
inline = " (inline)"
|
||||
}
|
||||
fmt.Fprintf(w, "%10s %s%s\n", vs, s.PrintableName(), inline)
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
field int // field tag
|
||||
@ -235,7 +238,7 @@ func decodeField(b *buffer, data []byte) ([]byte, error) {
|
||||
b.u64 = uint64(le32(data[:4]))
|
||||
data = data[4:]
|
||||
default:
|
||||
return nil, errors.New("unknown wire type: " + string(b.typ))
|
||||
return nil, fmt.Errorf("unknown wire type: %d", b.typ)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
|
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
|
||||
github.com/google/pprof/driver
|
||||
github.com/google/pprof/internal/binutils
|
||||
@ -43,7 +43,7 @@ golang.org/x/mod/zip
|
||||
## explicit
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/tools v0.0.0-20200219195521-7c4b6277d74d
|
||||
# golang.org/x/tools v0.0.0-20200309180859-aa4048aca1ca
|
||||
## explicit
|
||||
golang.org/x/tools/go/analysis
|
||||
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/errorsas
|
||||
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/internal/analysisutil
|
||||
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/shift
|
||||
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/tests
|
||||
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/typeutil
|
||||
# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||
## explicit
|
||||
golang.org/x/xerrors
|
||||
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/errorsas"
|
||||
"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/lostcancel"
|
||||
"golang.org/x/tools/go/analysis/passes/nilfunc"
|
||||
"golang.org/x/tools/go/analysis/passes/printf"
|
||||
"golang.org/x/tools/go/analysis/passes/shift"
|
||||
"golang.org/x/tools/go/analysis/passes/stdmethods"
|
||||
"golang.org/x/tools/go/analysis/passes/stringintconv"
|
||||
"golang.org/x/tools/go/analysis/passes/structtag"
|
||||
"golang.org/x/tools/go/analysis/passes/tests"
|
||||
"golang.org/x/tools/go/analysis/passes/unmarshal"
|
||||
@ -43,12 +45,14 @@ func main() {
|
||||
copylock.Analyzer,
|
||||
errorsas.Analyzer,
|
||||
httpresponse.Analyzer,
|
||||
ifaceassert.Analyzer,
|
||||
loopclosure.Analyzer,
|
||||
lostcancel.Analyzer,
|
||||
nilfunc.Analyzer,
|
||||
printf.Analyzer,
|
||||
shift.Analyzer,
|
||||
stdmethods.Analyzer,
|
||||
stringintconv.Analyzer,
|
||||
structtag.Analyzer,
|
||||
tests.Analyzer,
|
||||
unmarshal.Analyzer,
|
||||
|
@ -106,7 +106,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
|
||||
case Ed25519:
|
||||
sigType = signatureEd25519
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
|
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
|
||||
}
|
||||
switch signatureAlgorithm {
|
||||
case PKCS1WithSHA1, ECDSAWithSHA1:
|
||||
@ -120,7 +120,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
|
||||
case Ed25519:
|
||||
hash = directSigning
|
||||
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
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func TestSignatureSelection(t *testing.T) {
|
||||
t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
@ -115,7 +115,7 @@ func TestSignatureSelection(t *testing.T) {
|
||||
for testNo, test := range badTests {
|
||||
sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
|
||||
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)
|
||||
}
|
||||
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())
|
||||
@ -140,7 +140,7 @@ func TestLegacyTypeAndHash(t *testing.T) {
|
||||
t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
|
||||
}
|
||||
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.
|
||||
@ -156,13 +156,13 @@ func TestSupportedSignatureAlgorithms(t *testing.T) {
|
||||
for _, sigAlg := range supportedSignatureAlgorithms {
|
||||
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
|
||||
if err != nil {
|
||||
t.Errorf("%#04x: unexpected error: %v", sigAlg, err)
|
||||
t.Errorf("%v: unexpected error: %v", sigAlg, err)
|
||||
}
|
||||
if sigType == 0 {
|
||||
t.Errorf("%#04x: missing signature type", sigAlg)
|
||||
t.Errorf("%v: missing signature type", sigAlg)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
|
||||
|
||||
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
||||
// RFC 8446, Section 4.2.3.
|
||||
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()
|
||||
|
||||
const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
||||
|
||||
switch oh := f.OptionalHeader.(type) {
|
||||
case *OptionalHeader32:
|
||||
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
||||
t.Errorf("unexpected Subsystem value: have %d, but want %d", 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)
|
||||
}
|
||||
case *OptionalHeader64:
|
||||
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
||||
t.Errorf("unexpected Subsystem value: have %d, but want %d", 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)
|
||||
}
|
||||
default:
|
||||
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_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.
|
||||
//
|
||||
// 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
|
||||
// error, or to any interface type.
|
||||
|
@ -4,7 +4,7 @@ go 1.14
|
||||
|
||||
require (
|
||||
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/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/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.
|
||||
// If MaxLen is not 0, make sure MaxLen >= 4.
|
||||
var MaxLen int
|
||||
|
||||
// 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.
|
||||
// Requires 2 <= len(b) <= MaxLen.
|
||||
func IndexString(a, b string) int {
|
||||
panic("unimplemented")
|
||||
func IndexString(s, substr string) int {
|
||||
// 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
|
||||
|
@ -412,10 +412,10 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
sect.Relocs[i].Type = rel.Rtype
|
||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||
|
||||
if rel.Rsize&0x80 == 1 {
|
||||
if rel.Rsize&0x80 != 0 {
|
||||
sect.Relocs[i].Signed = true
|
||||
}
|
||||
if rel.Rsize&0x40 == 1 {
|
||||
if rel.Rsize&0x40 != 0 {
|
||||
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].Type = rel.Rtype
|
||||
sect.Relocs[i].Length = rel.Rsize&0x3F + 1
|
||||
if rel.Rsize&0x80 == 1 {
|
||||
if rel.Rsize&0x80 != 0 {
|
||||
sect.Relocs[i].Signed = true
|
||||
}
|
||||
if rel.Rsize&0x40 == 1 {
|
||||
if rel.Rsize&0x40 != 0 {
|
||||
sect.Relocs[i].InstructionFixed = true
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +236,10 @@ type WriterAt interface {
|
||||
// ReadByte reads and returns the next byte from the input or
|
||||
// any error encountered. If ReadByte returns an error, no input
|
||||
// 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 {
|
||||
ReadByte() (byte, error)
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ var builtinTypesLower = map[string]string{
|
||||
".jpeg": "image/jpeg",
|
||||
".jpg": "image/jpeg",
|
||||
".js": "text/javascript; charset=utf-8",
|
||||
".json": "application/json",
|
||||
".mjs": "text/javascript; charset=utf-8",
|
||||
".pdf": "application/pdf",
|
||||
".png": "image/png",
|
||||
|
@ -441,6 +441,14 @@ func TestDialParallelSpuriousConnection(t *testing.T) {
|
||||
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
|
||||
wg.Add(2)
|
||||
handler := func(dss *dualStackServer, ln Listener) {
|
||||
@ -450,7 +458,7 @@ func TestDialParallelSpuriousConnection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The client should close itself, without sending data.
|
||||
c.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||
c.SetReadDeadline(readDeadline)
|
||||
var b [1]byte
|
||||
if _, err := c.Read(b[:]); 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)
|
||||
}
|
||||
|
||||
// TODO: cookies. parsing them isn't exported, though.
|
||||
|
||||
uriStr := params["REQUEST_URI"]
|
||||
if uriStr == "" {
|
||||
// Fallback to SCRIPT_NAME, PATH_INFO and QUERY_STRING.
|
||||
|
@ -4135,10 +4135,19 @@ func TestServerConnState(t *testing.T) {
|
||||
|
||||
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 {
|
||||
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:
|
||||
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
|
||||
// (called from interhash or nilinterhash, above) or for hashing in
|
||||
// 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 {
|
||||
if t.tflag&tflagRegularMemory != 0 {
|
||||
// Handle ptr sizes specially, see issue 37086.
|
||||
@ -195,12 +197,28 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
|
||||
return h
|
||||
case kindStruct:
|
||||
s := (*structtype)(unsafe.Pointer(t))
|
||||
memStart := uintptr(0)
|
||||
memEnd := uintptr(0)
|
||||
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() {
|
||||
continue
|
||||
}
|
||||
h = typehash(f.typ, add(p, f.offset()), h)
|
||||
if f.typ.tflag&tflagRegularMemory == 0 {
|
||||
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
|
||||
default:
|
||||
|
@ -10,18 +10,18 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
|
||||
// Check that (*[n]elem)(p) is appropriately aligned.
|
||||
// TODO(mdempsky): What about fieldAlign?
|
||||
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.
|
||||
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) {
|
||||
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
|
||||
@ -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
|
||||
|
@ -24,10 +24,10 @@ func TestCheckPtr(t *testing.T) {
|
||||
cmd string
|
||||
want string
|
||||
}{
|
||||
{"CheckPtrAlignment", "fatal error: checkptr: unsafe pointer conversion\n"},
|
||||
{"CheckPtrArithmetic", "fatal error: checkptr: unsafe pointer arithmetic\n"},
|
||||
{"CheckPtrSize", "fatal error: checkptr: unsafe pointer conversion\n"},
|
||||
{"CheckPtrSmall", "fatal error: checkptr: unsafe pointer arithmetic\n"},
|
||||
{"CheckPtrAlignment", "fatal error: checkptr: misaligned pointer conversion\n"},
|
||||
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
|
||||
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
|
||||
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
@ -288,6 +289,12 @@ func TestSignalExitStatus(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")
|
||||
want := "OK\n"
|
||||
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