diff --git a/.gitattributes b/.gitattributes index bcea0290f4..cabbb1732c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,16 +1,16 @@ # Treat all files in the Go repo as binary, with no git magic updating -# line endings. Windows users contributing to Go will need to use a -# modern version of git and editors capable of LF line endings. +# line endings. This produces predictable results in different environments. +# +# Windows users contributing to Go will need to use a modern version +# of git and editors capable of LF line endings. +# +# Windows .bat files are known to have multiple bugs when run with LF +# endings, and so they are checked in with CRLF endings, with a test +# in test/winbatch.go to catch problems. (See golang.org/issue/37791.) # # We'll prevent accidental CRLF line endings from entering the repo -# via the git-review gofmt checks. +# via the git-codereview gofmt checks and tests. # -# See golang.org/issue/9281 +# See golang.org/issue/9281. * -text - -# The only exception is Windows files that must absolutely be CRLF or -# might not work. Batch files are known to have multiple bugs when run -# with LF endings. See golang.org/issue/37791 for more information. - -*.bat text eol=crlf diff --git a/AUTHORS b/AUTHORS index 69e35a13ae..80c79feb33 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1397,6 +1397,7 @@ Upthere, Inc. Uriel Mangado Vadim Grek Vadim Vygonets +Vee Zhang Vendasta Veselkov Konstantin Victor Vrantchan diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 934834fc79..6b6ee09415 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2195,6 +2195,7 @@ Vadim Grek Vadim Vygonets Val Polouchkine Valentin Vidic +Vee Zhang Vega Garcia Luis Alfonso Venil Noronha Veselkov Konstantin diff --git a/api/go1.15.txt b/api/go1.15.txt new file mode 100644 index 0000000000..b51837cf38 --- /dev/null +++ b/api/go1.15.txt @@ -0,0 +1,132 @@ +pkg bufio, var ErrBadReadCount error +pkg crypto, method (Hash) String() string +pkg crypto/ecdsa, func SignASN1(io.Reader, *PrivateKey, []uint8) ([]uint8, error) +pkg crypto/ecdsa, func VerifyASN1(*PublicKey, []uint8, []uint8) bool +pkg crypto/ecdsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool +pkg crypto/ecdsa, method (*PublicKey) Equal(crypto.PublicKey) bool +pkg crypto/ed25519, method (PrivateKey) Equal(crypto.PrivateKey) bool +pkg crypto/ed25519, method (PublicKey) Equal(crypto.PublicKey) bool +pkg crypto/elliptic, func MarshalCompressed(Curve, *big.Int, *big.Int) []uint8 +pkg crypto/elliptic, func UnmarshalCompressed(Curve, []uint8) (*big.Int, *big.Int) +pkg crypto/rsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool +pkg crypto/rsa, method (*PublicKey) Equal(crypto.PublicKey) bool +pkg crypto/tls, method (*Dialer) Dial(string, string) (net.Conn, error) +pkg crypto/tls, method (*Dialer) DialContext(context.Context, string, string) (net.Conn, error) +pkg crypto/tls, method (ClientAuthType) String() string +pkg crypto/tls, method (CurveID) String() string +pkg crypto/tls, method (SignatureScheme) String() string +pkg crypto/tls, type Config struct, VerifyConnection func(ConnectionState) error +pkg crypto/tls, type Dialer struct +pkg crypto/tls, type Dialer struct, Config *Config +pkg crypto/tls, type Dialer struct, NetDialer *net.Dialer +pkg crypto/x509, func CreateRevocationList(io.Reader, *RevocationList, *Certificate, crypto.Signer) ([]uint8, error) +pkg crypto/x509, type RevocationList struct +pkg crypto/x509, type RevocationList struct, ExtraExtensions []pkix.Extension +pkg crypto/x509, type RevocationList struct, NextUpdate time.Time +pkg crypto/x509, type RevocationList struct, Number *big.Int +pkg crypto/x509, type RevocationList struct, RevokedCertificates []pkix.RevokedCertificate +pkg crypto/x509, type RevocationList struct, SignatureAlgorithm SignatureAlgorithm +pkg crypto/x509, type RevocationList struct, ThisUpdate time.Time +pkg database/sql, method (*DB) SetConnMaxIdleTime(time.Duration) +pkg database/sql, method (*Row) Err() error +pkg database/sql, type DBStats struct, MaxIdleTimeClosed int64 +pkg database/sql/driver, type Validator interface { IsValid } +pkg database/sql/driver, type Validator interface, IsValid() bool +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 4096 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 64 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 128 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 16384 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 32 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND = 2048 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 512 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH = 1024 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 256 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 32768 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ideal-int +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 8192 +pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER ideal-int +pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE = 256 +pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE ideal-int +pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM = 16 +pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM ideal-int +pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI = 32768 +pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI ideal-int +pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO = 128 +pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO ideal-int +pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED = 512 +pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED ideal-int +pkg debug/pe, const IMAGE_FILE_DLL = 8192 +pkg debug/pe, const IMAGE_FILE_DLL ideal-int +pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE = 2 +pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE ideal-int +pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE = 32 +pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE ideal-int +pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED = 4 +pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED ideal-int +pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 8 +pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED ideal-int +pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP = 2048 +pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP ideal-int +pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED = 1 +pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED ideal-int +pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 1024 +pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ideal-int +pkg debug/pe, const IMAGE_FILE_SYSTEM = 4096 +pkg debug/pe, const IMAGE_FILE_SYSTEM ideal-int +pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY = 16384 +pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM = 13 +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 +pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE = 1 +pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8 +pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI = 5 +pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI = 7 +pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN = 0 +pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 +pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int +pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14 +pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int +pkg go/printer, const StdFormat = 16 +pkg go/printer, const StdFormat Mode +pkg math/big, method (*Int) FillBytes([]uint8) []uint8 +pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error) +pkg net/url, method (*URL) EscapedFragment() string +pkg net/url, method (*URL) Redacted() string +pkg net/url, type URL struct, RawFragment string +pkg os, method (*File) ReadFrom(io.Reader) (int64, error) +pkg os, var ErrDeadlineExceeded error +pkg regexp, method (*Regexp) SubexpIndex(string) int +pkg strconv, func FormatComplex(complex128, uint8, int, int) string +pkg strconv, func ParseComplex(string, int) (complex128, error) +pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool) +pkg testing, method (*B) TempDir() string +pkg testing, method (*T) Deadline() (time.Time, bool) +pkg testing, method (*T) TempDir() string +pkg testing, type TB interface, TempDir() string +pkg time, method (*Ticker) Reset(Duration) diff --git a/api/next.txt b/api/next.txt index 442c29a416..e69de29bb2 100644 --- a/api/next.txt +++ b/api/next.txt @@ -1,3 +0,0 @@ -pkg testing, method (*T) Deadline() (time.Time, bool) -pkg time, method (*Ticker) Reset(Duration) -pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool) diff --git a/doc/go1.10.html b/doc/go1.10.html index 41db36ab1e..853f874ded 100644 --- a/doc/go1.10.html +++ b/doc/go1.10.html @@ -30,7 +30,7 @@ adds caching of successful test results, runs vet automatically during tests, and permits passing string values directly between Go and C using cgo. -A new compiler option whitelist may cause +A new hard-coded set of safe compiler options may cause unexpected invalid flag errors in code that built successfully with older releases. @@ -267,7 +267,7 @@ and the test2json documentation.

Options specified by cgo using #cgo CFLAGS and the like -are now checked against a whitelist of permitted options. +are now checked against a list of permitted options. This closes a security hole in which a downloaded package uses compiler options like -fplugin diff --git a/doc/go1.15.html b/doc/go1.15.html index 492cac0b09..dd25b27c5f 100644 --- a/doc/go1.15.html +++ b/doc/go1.15.html @@ -55,6 +55,13 @@ Do not send CLs removing the interior tags from such phrases. on Windows.

+

+ The -race and -msan flags now always + enable -d=checkptr, which checks uses + of unsafe.Pointer. This was previously the case on all + OSes except Windows. +

+

Go-built DLLs no longer cause the process to exit when it receives a signal (such as Ctrl-C at a terminal). @@ -211,10 +218,24 @@ Do not send CLs removing the interior tags from such phrases.

Runtime

-

- Go now retries system calls that return EINTR. This - became more common in Go 1.14 with the addition of asynchronous - preemption, but is now handled transparently. +

+ If panic is invoked with a value whose type is derived from any + of: bool, complex64, complex128, float32, float64, + int, int8, int16, int32, int64, string, + uint, uint8, uint16, uint32, uint64, uintptr, + then the value will be printed, instead of just its address. + Previously, this was only true for values of exactly these types. +

+ +

+ On a Unix system, if the kill command + or kill system call is used to send + a SIGSEGV, SIGBUS, + or SIGFPE signal to a Go program, and if the signal + is not being handled via + os/signal.Notify, + the Go program will now reliably crash with a stack trace. + In earlier releases the behavior was unpredictable.

@@ -222,8 +243,14 @@ Do not send CLs removing the interior tags from such phrases. counts, and has lower worst-case latency.

-

-TODO +

+ Converting a small integer value into an interface value no longer + causes allocation. +

+ +

+ Non-blocking receives on closed channels now perform as well as + non-blocking receives on open channels.

Compiler

@@ -245,6 +272,15 @@ TODO aggressively eliminating unused type metadata.

+

+ The toolchain now mitigates + Intel + CPU erratum SKX102 on GOARCH=amd64 by aligning + functions to 32 byte boundaries and padding jump instructions. While + this padding increases binary sizes, this is more than made up for + by the binary size improvements mentioned above. +

+

Go 1.15 adds a -spectre flag to both the compiler and the assembler, to allow enabling Spectre mitigations. @@ -253,6 +289,19 @@ TODO See the Spectre wiki page for details.

+

+ The compiler now rejects //go: compiler directives that + have no meaning for the declaration they are applied to with a + "misplaced compiler directive" error. Such misapplied directives + were broken before, but were silently ignored by the compiler. +

+ +

+ The compiler's -json optimization logging now reports + large (>= 128 byte) copies and includes explanations of escape + analysis decisions. +

+

Linker

@@ -283,6 +332,14 @@ TODO improvements expected in future releases.

+

Objdump

+ +

+ The objdump tool now supports + disassembling in GNU assembler syntax with the -gnu + flag. +

+

Core library

New embedded tzdata package

@@ -299,10 +356,6 @@ TODO Either approach increases the size of the program by about 800 KB.

-

-TODO -

-

Cgo

@@ -321,10 +374,6 @@ TODO in mind.

-

-TODO -

-
debug/pe

@@ -336,10 +385,53 @@ TODO

+
crypto
+
+

+ The PrivateKey and PublicKey types in the + crypto/rsa, + crypto/ecdsa, and + crypto/ed25519 packages + now have an Equal method to compare keys for equivalence + or to make type-safe interfaces for public keys. The method signature + is compatible with + go-cmp's + definition of equality. +

+ +

+ Hash now implements + fmt.Stringer. +

+
+
+ +
crypto/ecdsa
+
+

+ The new SignASN1 + and VerifyASN1 + functions allow generating and verifying ECDSA signatures in the standard + ASN.1 DER encoding. +

+
+
+ +
crypto/elliptic
+
+

+ The new MarshalCompressed + and UnmarshalCompressed + functions allow encoding and decoding NIST elliptic curve points in compressed format. +

+
+
+
crypto/rsa

- VerifyPKCS1v15 now rejects invalid short signatures with missing leading zeroes. + VerifyPKCS1v15 + now rejects invalid short signatures with missing leading zeroes, according to RFC 8017.

@@ -353,21 +445,137 @@ TODO DialContext method permits using a context to both connect and handshake with a TLS server.

+ +

+ The new + VerifyConnection + callback on the Config type + allows custom verification logic for every connection. It has access to the + ConnectionState + which includes peer certificates, SCTs, and stapled OCSP responses. +

+ +

+ Auto-generated session ticket keys are now automatically rotated every 24 hours, + with a lifetime of 7 days, to limit their impact on forward secrecy. +

+ +

+ Session ticket lifetimes in TLS 1.2 and earlier, where the session keys + are reused for resumed connections, are now limited to 7 days, also to + limit their impact on forward secrecy. +

+ +

+ The client-side downgrade protection checks specified in RFC 8446 are now + enforced. This has the potential to cause connection errors for clients + encountering middleboxes that behave like unauthorized downgrade attacks. +

+ +

+ SignatureScheme, + CurveID, and + ClientAuthType + now implement fmt.Stringer. +

+ +

+ The ConnectionState + fields OCSPResponse and SignedCertificateTimestamps + are now repopulated on client-side resumed connections. +

- +
crypto/x509
+

+ If either the name on the certificate or the name being verified (with + VerifyOptions.DNSName + or VerifyHostname) + are invalid, they will now be compared case-insensitively without further + processing (without honoring wildcards or stripping trailing dots). + Invalid names include those with any characters other than letters, + digits, hyphens and underscores, those with empty labels, and names on + certificates with trailing dots. +

+ +

+ The deprecated, legacy behavior of treating the CommonName + field as a hostname when no Subject Alternative Names are present is now + disabled by default. It can be temporarily re-enabled by adding the value + x509ignoreCN=0 to the GODEBUG environment + variable. If the CommonName is an invalid hostname, it's + always ignored. +

+ +

+ The new CreateRevocationList + function and RevocationList type + allow creating RFC 5280-compliant X.509 v2 Certificate Revocation Lists. +

+ +

+ CreateCertificate + now automatically generates the SubjectKeyId if the template + is a CA and doesn't explicitly specify one. +

+ +

+ CreateCertificate + now returns an error if the template specifies MaxPathLen but is not a CA. +

+

- TODO: https://golang.org/cl/205237: load roots from colon separated SSL_CERT_DIR in loadSystemRoots + On Unix systems other than macOS, the SSL_CERT_DIR + environment variable can now be a colon-separated list. +

+ +

+ On macOS, binaries are now always linked against + Security.framework to extract the system trust roots, + regardless of whether cgo is available. The resulting behavior should be + more consistent with the OS verifier.

+
crypto/x509/pkix
+
+

+ Name.String + now prints non-standard attributes from + Names if + ExtraNames is empty. +

+
+
+ +
encoding/json
+
+

+ Decoding a JSON array into a slice no longer reuses any existing slice elements, + following the rules that the package documentation already stated. +

+ +

+ Introduce an internal limit to the maximum depth of nesting when decoding. + This reduces the possibility that a deeply nested input could use large quantities + of stack memory, or even cause a "goroutine stack exceeds limit" panic. +

+
+
+
encoding/xml

- TODO: https://golang.org/cl/203417: fix reserved namespace check to be case-insensitive + The encoder has always taken care to avoid using namespace prefixes beginning with + xml, + which are reserved by the XML specification. + Now, following the specification more closely, + that check is case-insensitive, so that prefixes beginning with + XML, XmL, + and so on are also avoided.

@@ -390,7 +598,8 @@ TODO
fmt

- TODO: https://golang.org/cl/215001: do not remove trailing zeros for %g and %G with #(sharp) flag + The printing verbs %#g and %#G now preserve + trailing zeros for floating-point values.

@@ -410,7 +619,8 @@ TODO
math/big

- TODO: https://golang.org/cl/230397: add (*Int).FillBytes + The new Int.FillBytes + method allows serializing to fixed-size pre-allocated byte slices.

@@ -441,8 +651,10 @@ TODO
net/http
-

- TODO: https://golang.org/cl/231418: only support "chunked" in inbound Transfer-Encoding headers +

+ Parsing is now stricter as a hardening measure against request smuggling attacks: + non-ASCII white space is no longer trimmed like SP and HTAB, and support for the + "identity" Transfer-Encoding was dropped.

@@ -457,7 +669,9 @@ TODO

- TODO: https://golang.org/cl/224897: make Switching Protocol requests (e.g. Websockets) cancelable + When a Switching Protocol (like WebSocket) request handled by + ReverseProxy + is canceled, the backend connection is now correctly closed.

@@ -506,6 +720,14 @@ TODO which Timeout returns true although a deadline has not been exceeded.

+ +

+ Packages os and net now automatically + retry system calls that fail with EINTR. Previously + this led to spurious failures, which became more common in Go + 1.14 with the addition of asynchronous preemption. Now this is + handled transparently. +

@@ -525,7 +747,7 @@ TODO
reflect

- Package reflect now disallows accessing methods of all + Package reflect now disallows accessing methods of all non-exported fields, whereas previously it allowed accessing those of non-exported, embedded fields. Code that relies on the previous behavior should be updated to instead access the @@ -546,26 +768,6 @@ TODO

runtime
-

- If panic is invoked with a value whose type is derived from any - of: bool, complex64, complex128, float32, float64, - int, int8, int16, int32, int64, string, - uint, uint8, uint16, uint32, uint64, uintptr, - then the value will be printed, instead of just its address. - Previously, this was only true for values of exactly these types. -

- -

- On a Unix system, if the kill command - or kill system call is used to send - a SIGSEGV, SIGBUS, - or SIGFPE signal to a Go program, and if the signal - is not being handled via - os/signal.Notify, - the Go program will now reliably crash with a stack trace. - In earlier releases the behavior was unpredictable. -

-

Several functions, including ReadMemStats @@ -573,16 +775,6 @@ TODO GoroutineProfile, no longer block if a garbage collection is in progress.

- -

- Converting small integer values into an interface value no - longer causes allocation. -

- -

- Non-blocking receives on closed channels now perform as well as - non-blocking receives on open channels. -

diff --git a/src/all.bat b/src/all.bat index 8bbd6b1b5d..ae835d992f 100644 --- a/src/all.bat +++ b/src/all.bat @@ -1,27 +1,27 @@ -:: Copyright 2012 The Go Authors. All rights reserved. -:: Use of this source code is governed by a BSD-style -:: license that can be found in the LICENSE file. - -@echo off - -setlocal - -if exist make.bat goto ok -echo all.bat must be run from go\src -:: cannot exit: would kill parent command interpreter -goto end -:ok - -set OLDPATH=%PATH% -call make.bat --no-banner --no-local -if %GOBUILDFAIL%==1 goto end -call run.bat --no-rebuild --no-local -if %GOBUILDFAIL%==1 goto end -:: we must restore %PATH% before running "dist banner" so that the latter -:: can get the original %PATH% and give suggestion to add %GOROOT%/bin -:: to %PATH% if necessary. -set PATH=%OLDPATH% -"%GOTOOLDIR%/dist" banner - -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +:: Copyright 2012 The Go Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style +:: license that can be found in the LICENSE file. + +@echo off + +setlocal + +if exist make.bat goto ok +echo all.bat must be run from go\src +:: cannot exit: would kill parent command interpreter +goto end +:ok + +set OLDPATH=%PATH% +call make.bat --no-banner --no-local +if %GOBUILDFAIL%==1 goto end +call run.bat --no-rebuild --no-local +if %GOBUILDFAIL%==1 goto end +:: we must restore %PATH% before running "dist banner" so that the latter +:: can get the original %PATH% and give suggestion to add %GOROOT%/bin +:: to %PATH% if necessary. +set PATH=%OLDPATH% +"%GOTOOLDIR%/dist" banner + +:end +if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% diff --git a/src/clean.bat b/src/clean.bat index 0954dcd67f..c957353d0f 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -1,32 +1,32 @@ -:: Copyright 2012 The Go Authors. All rights reserved. -:: Use of this source code is governed by a BSD-style -:: license that can be found in the LICENSE file. - -@echo off - -setlocal - -set GOBUILDFAIL=0 - -go tool dist env -w -p >env.bat -if errorlevel 1 goto fail -call env.bat -del env.bat -echo. - -if exist %GOTOOLDIR%\dist.exe goto distok -echo cannot find %GOTOOLDIR%\dist; nothing to clean -goto fail -:distok - -"%GOBIN%\go" clean -i std -"%GOBIN%\go" tool dist clean -"%GOBIN%\go" clean -i cmd - -goto end - -:fail -set GOBUILDFAIL=1 - -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +:: Copyright 2012 The Go Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style +:: license that can be found in the LICENSE file. + +@echo off + +setlocal + +set GOBUILDFAIL=0 + +go tool dist env -w -p >env.bat +if errorlevel 1 goto fail +call env.bat +del env.bat +echo. + +if exist %GOTOOLDIR%\dist.exe goto distok +echo cannot find %GOTOOLDIR%\dist; nothing to clean +goto fail +:distok + +"%GOBIN%\go" clean -i std +"%GOBIN%\go" tool dist clean +"%GOBIN%\go" clean -i cmd + +goto end + +:fail +set GOBUILDFAIL=1 + +:end +if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go index 22bf1379bb..578d88e432 100644 --- a/src/cmd/addr2line/addr2line_test.go +++ b/src/cmd/addr2line/addr2line_test.go @@ -73,19 +73,29 @@ func testAddr2Line(t *testing.T, exepath, addr string) { if err != nil { t.Fatalf("Stat failed: %v", err) } + // Debug paths are stored slash-separated, so convert to system-native. + srcPath = filepath.FromSlash(srcPath) fi2, err := os.Stat(srcPath) + if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" && strings.HasPrefix(srcPath, gorootFinal) { + if os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2)) { + // srcPath has had GOROOT_FINAL substituted for GOROOT, and it doesn't + // match the actual file. GOROOT probably hasn't been moved to its final + // location yet, so try the original location instead. + fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal)) + } + } if err != nil { t.Fatalf("Stat failed: %v", err) } if !os.SameFile(fi1, fi2) { t.Fatalf("addr2line_test.go and %s are not same file", srcPath) } - if srcLineNo != "89" { - t.Fatalf("line number = %v; want 89", srcLineNo) + if srcLineNo != "99" { + t.Fatalf("line number = %v; want 99", srcLineNo) } } -// This is line 88. The test depends on that. +// This is line 98. The test depends on that. func TestAddr2Line(t *testing.T) { testenv.MustHaveGoBuild(t) diff --git a/src/cmd/asm/internal/asm/testdata/arm64enc.s b/src/cmd/asm/internal/asm/testdata/arm64enc.s index a483c731b8..56cf51c303 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64enc.s +++ b/src/cmd/asm/internal/asm/testdata/arm64enc.s @@ -420,6 +420,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8 UXTBW R2, R6 // 461c0053 UXTHW R7, R20 // f43c0053 VCNT V0.B8, V0.B8 // 0058200e + VCNT V0.B16, V0.B16 // 0058204e WFE // 5f2003d5 WFI // 7f2003d5 YIELD // 3f2003d5 diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 4366df4b55..ca18c45d9d 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -990,7 +990,7 @@ produces a file named a.out, even if cmd/link does so by invoking the host linker in external linking mode. By default, cmd/link will decide the linking mode as follows: if the only -packages using cgo are those on a whitelist of standard library +packages using cgo are those on a list of known standard library packages (net, os/user, runtime/cgo), cmd/link will use internal linking mode. Otherwise, there are non-standard cgo packages involved, and cmd/link will use external linking mode. The first rule means that a build of diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go index f1af6473c7..e372259c78 100644 --- a/src/cmd/compile/fmt_test.go +++ b/src/cmd/compile/fmt_test.go @@ -96,7 +96,7 @@ func TestFormats(t *testing.T) { } importPath := filepath.Join("cmd/compile", path) - if blacklistedPackages[filepath.ToSlash(importPath)] { + if ignoredPackages[filepath.ToSlash(importPath)] { return filepath.SkipDir } @@ -344,8 +344,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) { for index, file := range files { ast.Inspect(file, func(n ast.Node) bool { if call, ok := n.(*ast.CallExpr); ok { - // ignore blacklisted functions - if blacklistedFunctions[nodeString(call.Fun)] { + if ignoredFunctions[nodeString(call.Fun)] { return true } // look for an arguments that might be a format string @@ -354,7 +353,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) { // make sure we have enough arguments n := numFormatArgs(s) if i+1+n > len(call.Args) { - t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun)) + t.Errorf("%s: not enough format args (ignore %s?)", posString(call), nodeString(call.Fun)) break // ignore this call } // assume last n arguments are to be formatted; @@ -549,14 +548,14 @@ func formatReplace(in string, f func(i int, s string) string) string { return string(append(buf, in[i0:]...)) } -// blacklistedPackages is the set of packages which can +// ignoredPackages is the set of packages which can // be ignored. -var blacklistedPackages = map[string]bool{} +var ignoredPackages = map[string]bool{} -// blacklistedFunctions is the set of functions which may have +// ignoredFunctions is the set of functions which may have // format-like arguments but which don't do any formatting and // thus may be ignored. -var blacklistedFunctions = map[string]bool{} +var ignoredFunctions = map[string]bool{} func init() { // verify that knownFormats entries are correctly formatted diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go index 6f69abf4fb..cb7a7d9af8 100644 --- a/src/cmd/compile/fmtmap_test.go +++ b/src/cmd/compile/fmtmap_test.go @@ -140,6 +140,7 @@ var knownFormats = map[string]string{ "float64 %.3f": "", "float64 %.6g": "", "float64 %g": "", + "int %#x": "", "int %-12d": "", "int %-6d": "", "int %-8o": "", @@ -203,6 +204,7 @@ var knownFormats = map[string]string{ "uint64 %b": "", "uint64 %d": "", "uint64 %x": "", + "uint8 %#x": "", "uint8 %d": "", "uint8 %v": "", "uint8 %x": "", diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go index 9935616f41..1da72aaf56 100644 --- a/src/cmd/compile/internal/arm/ssa.go +++ b/src/cmd/compile/internal/arm/ssa.go @@ -888,16 +888,30 @@ var condBits = map[ssa.Op]uint8{ var blockJump = map[ssa.BlockKind]struct { asm, invasm obj.As }{ - ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE}, - ssa.BlockARMNE: {arm.ABNE, arm.ABEQ}, - ssa.BlockARMLT: {arm.ABLT, arm.ABGE}, - ssa.BlockARMGE: {arm.ABGE, arm.ABLT}, - ssa.BlockARMLE: {arm.ABLE, arm.ABGT}, - ssa.BlockARMGT: {arm.ABGT, arm.ABLE}, - ssa.BlockARMULT: {arm.ABLO, arm.ABHS}, - ssa.BlockARMUGE: {arm.ABHS, arm.ABLO}, - ssa.BlockARMUGT: {arm.ABHI, arm.ABLS}, - ssa.BlockARMULE: {arm.ABLS, arm.ABHI}, + ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE}, + ssa.BlockARMNE: {arm.ABNE, arm.ABEQ}, + ssa.BlockARMLT: {arm.ABLT, arm.ABGE}, + ssa.BlockARMGE: {arm.ABGE, arm.ABLT}, + ssa.BlockARMLE: {arm.ABLE, arm.ABGT}, + ssa.BlockARMGT: {arm.ABGT, arm.ABLE}, + ssa.BlockARMULT: {arm.ABLO, arm.ABHS}, + ssa.BlockARMUGE: {arm.ABHS, arm.ABLO}, + ssa.BlockARMUGT: {arm.ABHI, arm.ABLS}, + ssa.BlockARMULE: {arm.ABLS, arm.ABHI}, + ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL}, + ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI}, +} + +// To model a 'LEnoov' ('<=' without overflow checking) branching +var leJumps = [2][2]gc.IndexJump{ + {{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0] + {{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1] +} + +// To model a 'GTnoov' ('>' without overflow checking) branching +var gtJumps = [2][2]gc.IndexJump{ + {{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0] + {{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1] } func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { @@ -941,7 +955,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { ssa.BlockARMLT, ssa.BlockARMGE, ssa.BlockARMLE, ssa.BlockARMGT, ssa.BlockARMULT, ssa.BlockARMUGT, - ssa.BlockARMULE, ssa.BlockARMUGE: + ssa.BlockARMULE, ssa.BlockARMUGE, + ssa.BlockARMLTnoov, ssa.BlockARMGEnoov: jmp := blockJump[b.Kind] switch next { case b.Succs[0].Block(): @@ -958,6 +973,12 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { } } + case ssa.BlockARMLEnoov: + s.CombJump(b, next, &leJumps) + + case ssa.BlockARMGTnoov: + s.CombJump(b, next, >Jumps) + default: b.Fatalf("branch not implemented: %s", b.LongString()) } diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 8e781a7997..f3e9ab78ef 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -141,13 +141,13 @@ func isSelfAssign(dst, src *Node) bool { return samesafeexpr(dst.Left, src.Left) } -// mayAffectMemory reports whether n evaluation may affect program memory state. -// If expression can't affect it, then it can be safely ignored by the escape analysis. +// mayAffectMemory reports whether evaluation of n may affect the program's +// memory state. If the expression can't affect memory state, then it can be +// safely ignored by the escape analysis. func mayAffectMemory(n *Node) bool { - // We may want to use "memory safe" black list instead of general - // "side-effect free", which can include all calls and other ops - // that can affect allocate or change global state. - // It's safer to start from a whitelist for now. + // We may want to use a list of "memory safe" ops instead of generally + // "side-effect free", which would include all calls and other ops that can + // allocate or change global state. For now, it's safer to start with the latter. // // We're ignoring things like division by zero, index out of range, // and nil pointer dereference here. diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 2dbe9cf405..dbdd027716 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -451,6 +451,7 @@ var passes = [...]pass{ {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}, + {name: "tighten tuple selectors", fn: tightenTupleSelectors, required: true}, {name: "lowered deadcode", fn: deadcode, required: true}, {name: "checkLower", fn: checkLower, required: true}, {name: "late phielim", fn: phielim}, @@ -509,6 +510,8 @@ var passOrder = [...]constraint{ {"decompose builtin", "late opt"}, // decompose builtin is the last pass that may introduce new float ops, so run softfloat after it {"decompose builtin", "softfloat"}, + // tuple selectors must be tightened to generators and de-duplicated before scheduling + {"tighten tuple selectors", "schedule"}, // remove critical edges before phi tighten, so that phi args get better placement {"critical", "phi tighten"}, // don't layout blocks until critical edges have been removed diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index 6bfd2960c1..3b4f2be37e 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -223,60 +223,6 @@ func cse(f *Func) { } } - // Fixup tuple selectors. - // - // If we have rewritten a tuple generator to a new one in a different - // block, copy its selectors to the new generator's block, so tuple - // generator and selectors stay together. - // - // Note: that there must be only one selector of each type per tuple - // generator. CSE may have left us with more than one so we de-duplicate - // them using a map. See issue 16741. - selectors := make(map[struct { - id ID - op Op - }]*Value) - for _, b := range f.Blocks { - for _, selector := range b.Values { - if selector.Op != OpSelect0 && selector.Op != OpSelect1 { - continue - } - - // Get the tuple generator to use as a key for de-duplication. - tuple := selector.Args[0] - if !tuple.Type.IsTuple() { - f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString()) - } - - // If there is a pre-existing selector in the target block then - // use that. Do this even if the selector is already in the - // target block to avoid duplicate tuple selectors. - key := struct { - id ID - op Op - }{tuple.ID, selector.Op} - if t := selectors[key]; t != nil { - if selector != t { - selector.copyOf(t) - } - continue - } - - // If the selector is in the wrong block copy it into the target - // block. - if selector.Block != tuple.Block { - t := selector.copyInto(tuple.Block) - selector.copyOf(t) - selectors[key] = t - continue - } - - // The selector is in the target block. Add it to the map so it - // cannot be duplicated. - selectors[key] = selector - } - } - if f.pass.stats > 0 { f.LogStat("CSE REWRITES", rewrites) } diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index a8cea68c5f..5b3179acbe 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -704,6 +704,10 @@ (UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no) (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no) (NE (InvertFlags cmp) yes no) -> (NE cmp yes no) +(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no) +(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no) +(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no) +(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no) // absorb flag constants into boolean values (Equal (FlagEQ)) -> (MOVWconst [1]) @@ -1417,42 +1421,42 @@ (NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no) (NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no) (NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no) -(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no) -(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL x y)) yes no) -(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no) -(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no) -(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no) -(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no) -(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no) -(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no) -(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no) -(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no) -(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL x y)) yes no) -(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no) -(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no) -(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no) -(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no) -(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no) -(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no) -(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no) -(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no) -(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL x y)) yes no) -(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no) -(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no) -(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no) -(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no) -(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no) -(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no) -(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no) -(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no) -(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL x y)) yes no) -(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no) -(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no) -(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no) -(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no) -(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no) -(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no) -(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LTnoov (CMP x y) yes no) +(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LTnoov (CMP a (MUL x y)) yes no) +(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMPconst [c] x) yes no) +(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LEnoov (CMP x y) yes no) +(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LEnoov (CMP a (MUL x y)) yes no) +(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMPconst [c] x) yes no) +(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LTnoov (CMN x y) yes no) +(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LTnoov (CMN a (MUL x y)) yes no) +(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMNconst [c] x) yes no) +(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LEnoov (CMN x y) yes no) +(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LEnoov (CMN a (MUL x y)) yes no) +(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMNconst [c] x) yes no) +(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRAreg x y z) yes no) (LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no) (LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no) (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no) @@ -1485,43 +1489,43 @@ (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no) (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no) (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no) -(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no) -(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL x y)) yes no) -(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no) -(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no) -(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no) -(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no) -(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no) -(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no) -(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no) -(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no) -(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL x y)) yes no) -(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no) -(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no) -(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no) -(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no) -(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no) -(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no) -(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no) -(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no) -(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no) -(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no) -(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no) -(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no) -(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no) -(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no) -(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no) -(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no) -(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL x y)) yes no) -(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no) -(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no) -(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no) -(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no) -(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no) -(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no) -(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GTnoov (CMP x y) yes no) +(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GTnoov (CMP a (MUL x y)) yes no) +(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMPconst [c] x) yes no) +(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GEnoov (CMP x y) yes no) +(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GEnoov (CMP a (MUL x y)) yes no) +(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMPconst [c] x) yes no) +(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GTnoov (CMN x y) yes no) +(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMNconst [c] x) yes no) +(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GEnoov (CMN x y) yes no) +(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GEnoov (CMN a (MUL x y)) yes no) +(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMNconst [c] x) yes no) +(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRAreg x y z) yes no) (GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no) -(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL x y)) yes no) +(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL x y)) yes no) (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no) (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no) (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no) diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go index 4abe5c9a8b..14407feaa2 100644 --- a/src/cmd/compile/internal/ssa/gen/ARMOps.go +++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go @@ -584,6 +584,10 @@ func init() { {name: "ULE", controls: 1}, {name: "UGT", controls: 1}, {name: "UGE", controls: 1}, + {name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow + {name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow + {name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow + {name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow } archs = append(archs, arch{ diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 4a83a46be2..7f6bf3e15b 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -61,6 +61,10 @@ const ( BlockARMULE BlockARMUGT BlockARMUGE + BlockARMLTnoov + BlockARMLEnoov + BlockARMGTnoov + BlockARMGEnoov BlockARM64EQ BlockARM64NE @@ -185,16 +189,20 @@ var blockString = [...]string{ BlockAMD64ORD: "ORD", BlockAMD64NAN: "NAN", - BlockARMEQ: "EQ", - BlockARMNE: "NE", - BlockARMLT: "LT", - BlockARMLE: "LE", - BlockARMGT: "GT", - BlockARMGE: "GE", - BlockARMULT: "ULT", - BlockARMULE: "ULE", - BlockARMUGT: "UGT", - BlockARMUGE: "UGE", + BlockARMEQ: "EQ", + BlockARMNE: "NE", + BlockARMLT: "LT", + BlockARMLE: "LE", + BlockARMGT: "GT", + BlockARMGE: "GE", + BlockARMULT: "ULT", + BlockARMULE: "ULE", + BlockARMUGT: "UGT", + BlockARMUGE: "UGE", + BlockARMLTnoov: "LTnoov", + BlockARMLEnoov: "LEnoov", + BlockARMGTnoov: "GTnoov", + BlockARMGEnoov: "GEnoov", BlockARM64EQ: "EQ", BlockARM64NE: "NE", diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 5c8dd0f2ed..be5f56a1f7 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -17514,7 +17514,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (GE (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 - // result: (GE (CMP x y) yes no) + // result: (GEnoov (CMP x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17531,12 +17531,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(MULS x y a)) yes no) // cond: l.Uses==1 - // result: (GE (CMP a (MUL x y)) yes no) + // result: (GEnoov (CMP a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17556,12 +17556,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GE (CMPconst [c] x) yes no) + // result: (GEnoov (CMPconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17579,12 +17579,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftLL x y [c]) yes no) + // result: (GEnoov (CMPshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17603,12 +17603,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftRL x y [c]) yes no) + // result: (GEnoov (CMPshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17627,12 +17627,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftRA x y [c]) yes no) + // result: (GEnoov (CMPshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17651,12 +17651,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftLLreg x y z) yes no) + // result: (GEnoov (CMPshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17674,12 +17674,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftRLreg x y z) yes no) + // result: (GEnoov (CMPshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17697,12 +17697,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMPshiftRAreg x y z) yes no) + // result: (GEnoov (CMPshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17720,12 +17720,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADD x y)) yes no) // cond: l.Uses==1 - // result: (GE (CMN x y) yes no) + // result: (GEnoov (CMN x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17746,14 +17746,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } break } // match: (GE (CMPconst [0] l:(MULA x y a)) yes no) // cond: l.Uses==1 - // result: (GE (CMN a (MUL x y)) yes no) + // result: (GEnoov (CMN a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17773,12 +17773,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GE (CMNconst [c] x) yes no) + // result: (GEnoov (CMNconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17796,12 +17796,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftLL x y [c]) yes no) + // result: (GEnoov (CMNshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17820,12 +17820,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftRL x y [c]) yes no) + // result: (GEnoov (CMNshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17844,12 +17844,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftRA x y [c]) yes no) + // result: (GEnoov (CMNshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17868,12 +17868,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftLLreg x y z) yes no) + // result: (GEnoov (CMNshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17891,12 +17891,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftRLreg x y z) yes no) + // result: (GEnoov (CMNshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17914,12 +17914,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (CMNshiftRAreg x y z) yes no) + // result: (GEnoov (CMNshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -17937,7 +17937,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(AND x y)) yes no) @@ -18324,6 +18324,15 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMGE, v0) return true } + case BlockARMGEnoov: + // match: (GEnoov (InvertFlags cmp) yes no) + // result: (LEnoov cmp yes no) + for b.Controls[0].Op == OpARMInvertFlags { + v_0 := b.Controls[0] + cmp := v_0.Args[0] + b.resetWithControl(BlockARMLEnoov, cmp) + return true + } case BlockARMGT: // match: (GT (FlagEQ) yes no) // result: (First no yes) @@ -18368,7 +18377,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (GT (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 - // result: (GT (CMP x y) yes no) + // result: (GTnoov (CMP x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18385,12 +18394,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(MULS x y a)) yes no) // cond: l.Uses==1 - // result: (GT (CMP a (MUL x y)) yes no) + // result: (GTnoov (CMP a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18410,12 +18419,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GT (CMPconst [c] x) yes no) + // result: (GTnoov (CMPconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18433,12 +18442,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftLL x y [c]) yes no) + // result: (GTnoov (CMPshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18457,12 +18466,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftRL x y [c]) yes no) + // result: (GTnoov (CMPshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18481,12 +18490,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftRA x y [c]) yes no) + // result: (GTnoov (CMPshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18505,12 +18514,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftLLreg x y z) yes no) + // result: (GTnoov (CMPshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18528,12 +18537,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftRLreg x y z) yes no) + // result: (GTnoov (CMPshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18551,12 +18560,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMPshiftRAreg x y z) yes no) + // result: (GTnoov (CMPshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18574,12 +18583,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADD x y)) yes no) // cond: l.Uses==1 - // result: (GT (CMN x y) yes no) + // result: (GTnoov (CMN x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18600,14 +18609,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } break } // match: (GT (CMPconst [0] l:(ADDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GT (CMNconst [c] x) yes no) + // result: (GTnoov (CMNconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18625,12 +18634,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftLL x y [c]) yes no) + // result: (GTnoov (CMNshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18649,12 +18658,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftRL x y [c]) yes no) + // result: (GTnoov (CMNshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18673,12 +18682,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftRA x y [c]) yes no) + // result: (GTnoov (CMNshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18697,12 +18706,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftLLreg x y z) yes no) + // result: (GTnoov (CMNshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18720,12 +18729,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftRLreg x y z) yes no) + // result: (GTnoov (CMNshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18743,12 +18752,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (CMNshiftRAreg x y z) yes no) + // result: (GTnoov (CMNshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18766,7 +18775,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(AND x y)) yes no) @@ -18799,7 +18808,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (GT (CMPconst [0] l:(MULA x y a)) yes no) // cond: l.Uses==1 - // result: (GT (CMN a (MUL x y)) yes no) + // result: (GTnoov (CMN a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -18819,7 +18828,7 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) @@ -19178,6 +19187,15 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMGT, v0) return true } + case BlockARMGTnoov: + // match: (GTnoov (InvertFlags cmp) yes no) + // result: (LTnoov cmp yes no) + for b.Controls[0].Op == OpARMInvertFlags { + v_0 := b.Controls[0] + cmp := v_0.Args[0] + b.resetWithControl(BlockARMLTnoov, cmp) + return true + } case BlockIf: // match: (If (Equal cc) yes no) // result: (EQ cc yes no) @@ -19312,7 +19330,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (LE (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 - // result: (LE (CMP x y) yes no) + // result: (LEnoov (CMP x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19329,12 +19347,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(MULS x y a)) yes no) // cond: l.Uses==1 - // result: (LE (CMP a (MUL x y)) yes no) + // result: (LEnoov (CMP a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19354,12 +19372,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LE (CMPconst [c] x) yes no) + // result: (LEnoov (CMPconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19377,12 +19395,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftLL x y [c]) yes no) + // result: (LEnoov (CMPshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19401,12 +19419,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftRL x y [c]) yes no) + // result: (LEnoov (CMPshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19425,12 +19443,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftRA x y [c]) yes no) + // result: (LEnoov (CMPshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19449,12 +19467,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftLLreg x y z) yes no) + // result: (LEnoov (CMPshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19472,12 +19490,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftRLreg x y z) yes no) + // result: (LEnoov (CMPshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19495,12 +19513,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMPshiftRAreg x y z) yes no) + // result: (LEnoov (CMPshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19518,12 +19536,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADD x y)) yes no) // cond: l.Uses==1 - // result: (LE (CMN x y) yes no) + // result: (LEnoov (CMN x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19544,14 +19562,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } break } // match: (LE (CMPconst [0] l:(MULA x y a)) yes no) // cond: l.Uses==1 - // result: (LE (CMN a (MUL x y)) yes no) + // result: (LEnoov (CMN a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19571,12 +19589,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LE (CMNconst [c] x) yes no) + // result: (LEnoov (CMNconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19594,12 +19612,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftLL x y [c]) yes no) + // result: (LEnoov (CMNshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19618,12 +19636,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftRL x y [c]) yes no) + // result: (LEnoov (CMNshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19642,12 +19660,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftRA x y [c]) yes no) + // result: (LEnoov (CMNshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19666,12 +19684,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftLLreg x y z) yes no) + // result: (LEnoov (CMNshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19689,12 +19707,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftRLreg x y z) yes no) + // result: (LEnoov (CMNshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19712,12 +19730,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (CMNshiftRAreg x y z) yes no) + // result: (LEnoov (CMNshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -19735,7 +19753,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(AND x y)) yes no) @@ -20122,6 +20140,15 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMLE, v0) return true } + case BlockARMLEnoov: + // match: (LEnoov (InvertFlags cmp) yes no) + // result: (GEnoov cmp yes no) + for b.Controls[0].Op == OpARMInvertFlags { + v_0 := b.Controls[0] + cmp := v_0.Args[0] + b.resetWithControl(BlockARMGEnoov, cmp) + return true + } case BlockARMLT: // match: (LT (FlagEQ) yes no) // result: (First no yes) @@ -20166,7 +20193,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (LT (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 - // result: (LT (CMP x y) yes no) + // result: (LTnoov (CMP x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20183,12 +20210,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(MULS x y a)) yes no) // cond: l.Uses==1 - // result: (LT (CMP a (MUL x y)) yes no) + // result: (LTnoov (CMP a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20208,12 +20235,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LT (CMPconst [c] x) yes no) + // result: (LTnoov (CMPconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20231,12 +20258,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftLL x y [c]) yes no) + // result: (LTnoov (CMPshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20255,12 +20282,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftRL x y [c]) yes no) + // result: (LTnoov (CMPshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20279,12 +20306,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftRA x y [c]) yes no) + // result: (LTnoov (CMPshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20303,12 +20330,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftLLreg x y z) yes no) + // result: (LTnoov (CMPshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20326,12 +20353,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftRLreg x y z) yes no) + // result: (LTnoov (CMPshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20349,12 +20376,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMPshiftRAreg x y z) yes no) + // result: (LTnoov (CMPshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20372,12 +20399,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADD x y)) yes no) // cond: l.Uses==1 - // result: (LT (CMN x y) yes no) + // result: (LTnoov (CMN x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20398,14 +20425,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } break } // match: (LT (CMPconst [0] l:(MULA x y a)) yes no) // cond: l.Uses==1 - // result: (LT (CMN a (MUL x y)) yes no) + // result: (LTnoov (CMN a (MUL x y)) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20425,12 +20452,12 @@ func rewriteBlockARM(b *Block) bool { v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) v1.AddArg2(x, y) v0.AddArg2(a, v1) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LT (CMNconst [c] x) yes no) + // result: (LTnoov (CMNconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20448,12 +20475,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c v0.AddArg(x) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftLL x y [c]) yes no) + // result: (LTnoov (CMNshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20472,12 +20499,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftRL x y [c]) yes no) + // result: (LTnoov (CMNshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20496,12 +20523,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftRA x y [c]) yes no) + // result: (LTnoov (CMNshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20520,12 +20547,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftLLreg x y z) yes no) + // result: (LTnoov (CMNshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20543,12 +20570,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftRLreg x y z) yes no) + // result: (LTnoov (CMNshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20566,12 +20593,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (CMNshiftRAreg x y z) yes no) + // result: (LTnoov (CMNshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if v_0.AuxInt != 0 { @@ -20589,7 +20616,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(AND x y)) yes no) @@ -20976,6 +21003,15 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMLT, v0) return true } + case BlockARMLTnoov: + // match: (LTnoov (InvertFlags cmp) yes no) + // result: (GTnoov cmp yes no) + for b.Controls[0].Op == OpARMInvertFlags { + v_0 := b.Controls[0] + cmp := v_0.Args[0] + b.resetWithControl(BlockARMGTnoov, cmp) + return true + } case BlockARMNE: // match: (NE (CMPconst [0] (Equal cc)) yes no) // result: (EQ cc yes no) diff --git a/src/cmd/compile/internal/ssa/rewriteCond_test.go b/src/cmd/compile/internal/ssa/rewriteCond_test.go index 6536d3a7d7..2c26fdf142 100644 --- a/src/cmd/compile/internal/ssa/rewriteCond_test.go +++ b/src/cmd/compile/internal/ssa/rewriteCond_test.go @@ -7,24 +7,26 @@ package ssa import ( "math" "math/rand" - "runtime" "testing" ) var ( - x64 int64 = math.MaxInt64 - 2 - x64b int64 = math.MaxInt64 - 2 - x64c int64 = math.MaxInt64 - 2 - y64 int64 = math.MinInt64 + 1 - x32 int32 = math.MaxInt32 - 2 - x32b int32 = math.MaxInt32 - 2 - y32 int32 = math.MinInt32 + 1 - one64 int64 = 1 - one32 int32 = 1 - v64 int64 = 11 // ensure it's not 2**n +/- 1 - v64_n int64 = -11 - v32 int32 = 11 - v32_n int32 = -11 + x64 int64 = math.MaxInt64 - 2 + x64b int64 = math.MaxInt64 - 2 + x64c int64 = math.MaxInt64 - 2 + y64 int64 = math.MinInt64 + 1 + x32 int32 = math.MaxInt32 - 2 + x32b int32 = math.MaxInt32 - 2 + x32c int32 = math.MaxInt32 - 2 + y32 int32 = math.MinInt32 + 1 + one64 int64 = 1 + one32 int32 = 1 + v64 int64 = 11 // ensure it's not 2**n +/- 1 + v64_n int64 = -11 + v32 int32 = 11 + v32_n int32 = -11 + uv32 uint32 = 19 + uz uint8 = 1 // for lowering to SLL/SRL/SRA ) var crTests = []struct { @@ -39,6 +41,8 @@ var crTests = []struct { {"MAddVar32", testMAddVar32}, {"MSubVar64", testMSubVar64}, {"MSubVar32", testMSubVar32}, + {"AddShift32", testAddShift32}, + {"SubShift32", testSubShift32}, } var crBenches = []struct { @@ -58,9 +62,6 @@ var crBenches = []struct { // and machine code sequences are covered. // It's for arm64 initially, please see https://github.com/golang/go/issues/38740 func TestCondRewrite(t *testing.T) { - if runtime.GOARCH == "arm" { - t.Skip("fix on arm expected!") - } for _, test := range crTests { t.Run(test.name, test.tf) } @@ -408,6 +409,66 @@ func testMSubVar32(t *testing.T) { } } +// 32-bit ADDshift, pick up 1~2 scenarios randomly for each condition +func testAddShift32(t *testing.T) { + if x32+v32<<1 < 0 { + } else { + t.Errorf("'%#x + %#x<<%#x < 0' failed", x32, v32, 1) + } + + if x32+v32>>1 <= 0 { + } else { + t.Errorf("'%#x + %#x>>%#x <= 0' failed", x32, v32, 1) + } + + if x32+int32(uv32>>1) > 0 { + t.Errorf("'%#x + int32(%#x>>%#x) > 0' failed", x32, uv32, 1) + } + + if x32+v32<= 0 { + t.Errorf("'%#x + %#x<<%#x >= 0' failed", x32, v32, uz) + } + + if x32+v32>>uz > 0 { + t.Errorf("'%#x + %#x>>%#x > 0' failed", x32, v32, uz) + } + + if x32+int32(uv32>>uz) < 0 { + } else { + t.Errorf("'%#x + int32(%#x>>%#x) < 0' failed", x32, uv32, uz) + } +} + +// 32-bit SUBshift, pick up 1~2 scenarios randomly for each condition +func testSubShift32(t *testing.T) { + if y32-v32<<1 > 0 { + } else { + t.Errorf("'%#x - %#x<<%#x > 0' failed", y32, v32, 1) + } + + if y32-v32>>1 < 0 { + t.Errorf("'%#x - %#x>>%#x < 0' failed", y32, v32, 1) + } + + if y32-int32(uv32>>1) >= 0 { + } else { + t.Errorf("'%#x - int32(%#x>>%#x) >= 0' failed", y32, uv32, 1) + } + + if y32-v32<>uz >= 0 { + } else { + t.Errorf("'%#x - %#x>>%#x >= 0' failed", y32, v32, uz) + } + + if y32-int32(uv32>>uz) <= 0 { + t.Errorf("'%#x - int32(%#x>>%#x) <= 0' failed", y32, uv32, uz) + } +} + var rnd = rand.New(rand.NewSource(0)) var sink int64 diff --git a/src/cmd/compile/internal/ssa/tuple.go b/src/cmd/compile/internal/ssa/tuple.go new file mode 100644 index 0000000000..38deabf83d --- /dev/null +++ b/src/cmd/compile/internal/ssa/tuple.go @@ -0,0 +1,59 @@ +// 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 + +// tightenTupleSelectors ensures that tuple selectors (Select0 and +// Select1 ops) are in the same block as their tuple generator. The +// function also ensures that there are no duplicate tuple selectors. +// These properties are expected by the scheduler but may not have +// been maintained by the optimization pipeline up to this point. +// +// See issues 16741 and 39472. +func tightenTupleSelectors(f *Func) { + selectors := make(map[struct { + id ID + op Op + }]*Value) + for _, b := range f.Blocks { + for _, selector := range b.Values { + if selector.Op != OpSelect0 && selector.Op != OpSelect1 { + continue + } + + // Get the tuple generator to use as a key for de-duplication. + tuple := selector.Args[0] + if !tuple.Type.IsTuple() { + f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString()) + } + + // If there is a pre-existing selector in the target block then + // use that. Do this even if the selector is already in the + // target block to avoid duplicate tuple selectors. + key := struct { + id ID + op Op + }{tuple.ID, selector.Op} + if t := selectors[key]; t != nil { + if selector != t { + selector.copyOf(t) + } + continue + } + + // If the selector is in the wrong block copy it into the target + // block. + if selector.Block != tuple.Block { + t := selector.copyInto(tuple.Block) + selector.copyOf(t) + selectors[key] = t + continue + } + + // The selector is in the target block. Add it to the map so it + // cannot be duplicated. + selectors[key] = selector + } + } +} diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 08ef056164..e1cd4965c3 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -178,15 +178,6 @@ func (t *tester) run() { return } - // We must unset GOROOT_FINAL before tests, because runtime/debug requires - // correct access to source code, so if we have GOROOT_FINAL in effect, - // at least runtime/debug test will fail. - // If GOROOT_FINAL was set before, then now all the commands will appear stale. - // Nothing we can do about that other than not checking them below. - // (We call checkNotStale but only with "std" not "cmd".) - os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test - os.Unsetenv("GOROOT_FINAL") - for _, name := range t.runNames { if !t.isRegisteredTestName(name) { fatalf("unknown test %q", name) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 4c30de4781..021930a8a8 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -124,7 +124,6 @@ func TestMain(m *testing.M) { fmt.Printf("SKIP\n") return } - os.Unsetenv("GOROOT_FINAL") flag.Parse() @@ -180,6 +179,11 @@ func TestMain(m *testing.M) { } testGOROOT = goEnv("GOROOT") os.Setenv("TESTGO_GOROOT", testGOROOT) + // Ensure that GOROOT is set explicitly. + // Otherwise, if the toolchain was built with GOROOT_FINAL set but has not + // yet been moved to its final location, programs that invoke runtime.GOROOT + // may accidentally use the wrong path. + os.Setenv("GOROOT", testGOROOT) // The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH // toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH). @@ -216,8 +220,10 @@ func TestMain(m *testing.M) { } testCC = strings.TrimSpace(string(out)) - if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil { - fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err) + cmd := exec.Command(testGo, "env", "CGO_ENABLED") + cmd.Stderr = new(strings.Builder) + if out, err := cmd.Output(); err != nil { + fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr) canRun = false } else { canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out))) diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go index beb80c505d..e0509808d6 100644 --- a/src/cmd/go/internal/web/http.go +++ b/src/cmd/go/internal/web/http.go @@ -13,6 +13,7 @@ package web import ( "crypto/tls" + "errors" "fmt" "mime" "net/http" @@ -47,6 +48,13 @@ var securityPreservingHTTPClient = &http.Client{ lastHop := via[len(via)-1].URL return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL) } + + // Go's http.DefaultClient allows 10 redirects before returning an error. + // The securityPreservingHTTPClient also uses this default policy to avoid + // Go command hangs. + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } return nil }, } diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 318d688d2e..f1d08e0268 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -168,7 +168,7 @@ func gcBackendConcurrency(gcflags []string) int { CheckFlags: for _, flag := range gcflags { // Concurrent compilation is presumed incompatible with any gcflags, - // except for a small whitelist of commonly used flags. + // except for known commonly used flags. // If the user knows better, they can manually add their own -c to the gcflags. switch flag { case "-N", "-l", "-S", "-B", "-C", "-I": diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 8214488a59..2a4d2935b3 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -174,6 +174,25 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { return } + // Request for $GOPROXY/redirect//... goes to redirects. + if strings.HasPrefix(path, "redirect/") { + path = path[len("redirect/"):] + if j := strings.Index(path, "/"); j >= 0 { + count, err := strconv.Atoi(path[:j]) + if err != nil { + return + } + + // The last redirect. + if count <= 1 { + http.Redirect(w, r, fmt.Sprintf("/mod/%s", path[j+1:]), 302) + return + } + http.Redirect(w, r, fmt.Sprintf("/mod/redirect/%d/%s", count-1, path[j+1:]), 302) + return + } + } + // Request for $GOPROXY/sumdb//supported // is checking whether it's OK to access sumdb via the proxy. if path == "sumdb/"+testSumDBName+"/supported" { diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index a49a705fa6..2e8f18a897 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -130,6 +130,7 @@ func (ts *testScript) setup() { "GOPROXY=" + proxyURL, "GOPRIVATE=", "GOROOT=" + testGOROOT, + "GOROOT_FINAL=" + os.Getenv("GOROOT_FINAL"), // causes spurious rebuilds and breaks the "stale" built-in if not propagated "TESTGO_GOROOT=" + testGOROOT, "GOSUMDB=" + testSumDBVerifierKey, "GONOPROXY=", diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index c7fa7cfef5..76d6651718 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -34,6 +34,7 @@ Scripts also have access to these other environment variables: GOPATH=$WORK/gopath GOPROXY= GOROOT= + GOROOT_FINAL= TESTGO_GOROOT= HOME=/no-home PATH= diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt index cfab80743e..ad78bcf2b2 100644 --- a/src/cmd/go/testdata/script/build_trimpath.txt +++ b/src/cmd/go/testdata/script/build_trimpath.txt @@ -1,5 +1,9 @@ [short] skip +# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting +# binary instead of GOROOT. Explicitly unset it here. +env GOROOT_FINAL= + # Set up two identical directories that can be used as GOPATH. env GO111MODULE=on mkdir $WORK/a/src/paths $WORK/b/src/paths diff --git a/src/cmd/go/testdata/script/goroot_executable.txt b/src/cmd/go/testdata/script/goroot_executable.txt index 4e04bad69b..fdbcde06cb 100644 --- a/src/cmd/go/testdata/script/goroot_executable.txt +++ b/src/cmd/go/testdata/script/goroot_executable.txt @@ -2,6 +2,13 @@ mkdir $WORK/new/bin +# In this test, we are specifically checking the logic for deriving +# the value of GOROOT from runtime.GOROOT. +# GOROOT_FINAL changes the default behavior of runtime.GOROOT, +# and will thus cause the test to fail if it is set when our +# new cmd/go is built. +env GOROOT_FINAL= + go build -o $WORK/new/bin/go$GOEXE cmd/go & go build -o $WORK/bin/check$GOEXE check.go & wait diff --git a/src/cmd/go/testdata/script/mod_convert_dep.txt b/src/cmd/go/testdata/script/mod_convert_dep.txt index 267c90eb3c..ad22aca5be 100644 --- a/src/cmd/go/testdata/script/mod_convert_dep.txt +++ b/src/cmd/go/testdata/script/mod_convert_dep.txt @@ -20,7 +20,6 @@ cd $WORK/gopkgdir/x ! go list . stderr 'cannot find main module' ! stderr 'Gopkg.lock' -! stderr 'go mod init' -- $WORK/test/Gopkg.lock -- -- $WORK/test/x/x.go -- diff --git a/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt new file mode 100644 index 0000000000..9cbe0d279d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on +env GOPROXYBASE=$GOPROXY +env GOPROXY=$GOPROXYBASE/redirect/11 +env GOSUMDB=off + +! go get -d rsc.io/quote@v1.2.0 +stderr 'stopped after 10 redirects' + +env GOPROXY=$GOPROXYBASE/redirect/9 +go get -d rsc.io/quote@v1.2.0 diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 5d73edd318..2e6167322e 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -36,7 +36,7 @@ func findGorootModules(t *testing.T) []gorootModule { if err != nil { return err } - if info.Name() == "vendor" || info.Name() == "testdata" { + if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") { return filepath.SkipDir } if path == filepath.Join(runtime.GOROOT(), "pkg") { diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 7f5cba645a..df17729a76 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -460,7 +460,6 @@ var optab = []Optab{ {AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0}, {ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, {AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, - {AVCNT, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0}, {AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0}, {AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0}, {AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0}, @@ -2773,6 +2772,7 @@ func buildop(ctxt *obj.Link) { oprangeset(AVSRI, t) case AVREV32: + oprangeset(AVCNT, t) oprangeset(AVRBIT, t) oprangeset(AVREV64, t) oprangeset(AVREV16, t) @@ -4523,7 +4523,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { c.ctxt.Diag("invalid arrangement: %v\n", p) } - if (p.As == AVMOV || p.As == AVRBIT) && (af != ARNG_16B && af != ARNG_8B) { + if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) { c.ctxt.Diag("invalid arrangement: %v", p) } diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index 2f94ec6a67..f7873a42b9 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -134,7 +134,7 @@ func init() { } func Framepointer_enabled(goos, goarch string) bool { - return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && goos == "linux") + return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && (goos == "linux" || goos == "darwin")) } func addexp(s string) { diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go index 326f493e2d..ac6937ced0 100644 --- a/src/cmd/link/dwarf_test.go +++ b/src/cmd/link/dwarf_test.go @@ -33,8 +33,8 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) t.Fatalf("go list: %v\n%s", err, out) } if string(out) != "false\n" { - if os.Getenv("GOROOT_FINAL_OLD") != "" { - t.Skip("cmd/link is stale, but $GOROOT_FINAL_OLD is set") + if strings.HasPrefix(testenv.Builder(), "darwin-") { + t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598") } t.Fatalf("cmd/link is stale - run go install cmd/link") } diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 9b4214bdca..f87776ef12 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -616,15 +616,15 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) { } fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason) - // For the moment, whitelist DWARF subprogram DIEs for + // For the moment, allow DWARF subprogram DIEs for // auto-generated wrapper functions. What seems to happen // here is that we get different line numbers on formal // params; I am guessing that the pos is being inherited // from the spot where the wrapper is needed. - whitelist := strings.HasPrefix(name, "go.info.go.interface") || + allowed := strings.HasPrefix(name, "go.info.go.interface") || strings.HasPrefix(name, "go.info.go.builtin") || strings.HasPrefix(name, "go.debuglines") - if !whitelist { + if !allowed { l.strictDupMsgs++ } } diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index c974d6707b..a9dc7d1a5e 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -138,7 +138,11 @@ func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string) args = append(args, flags...) 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 + // "Bad line" bug #36683 is sensitive to being run in the source directory. + cmd.Dir = "testdata" + // Ensure that the source file location embedded in the binary matches our + // actual current GOROOT, instead of GOROOT_FINAL if set. + cmd.Env = append(os.Environ(), "GOROOT_FINAL=") t.Logf("Running %v", cmd.Args) out, err := cmd.CombinedOutput() if err != nil { diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index fd21ae8fb1..3a5ca22613 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -278,6 +278,8 @@ type ClientSessionState struct { serverCertificates []*x509.Certificate // Certificate chain presented by the server verifiedChains [][]*x509.Certificate // Certificate chains we built for verification receivedAt time.Time // When the session ticket was received from the server + ocspResponse []byte // Stapled OCSP response presented by the server + scts [][]byte // SCTs presented by the server // TLS 1.3 fields. nonce []byte // Ticket nonce sent by the server, to derive PSK diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 40c8e02c53..46b0a770d5 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -728,10 +728,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return false, errors.New("tls: server resumed a session with a different cipher suite") } - // Restore masterSecret and peerCerts from previous state + // Restore masterSecret, peerCerts, and ocspResponse from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates c.verifiedChains = hs.session.verifiedChains + c.ocspResponse = hs.session.ocspResponse + // Let the ServerHello SCTs override the session SCTs from the original + // connection, if any are provided + if len(c.scts) == 0 && len(hs.session.scts) != 0 { + c.scts = hs.session.scts + } + return true, nil } @@ -788,6 +795,8 @@ func (hs *clientHandshakeState) readSessionTicket() error { serverCertificates: c.peerCertificates, verifiedChains: c.verifiedChains, receivedAt: c.config.time(), + ocspResponse: c.ocspResponse, + scts: c.scts, } return nil diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 1cda90190c..12b0254123 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -19,6 +19,7 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "strconv" "strings" "testing" @@ -2430,3 +2431,83 @@ func TestDowngradeCanary(t *testing.T) { t.Errorf("client unexpectedly reacted to a canary in TLS 1.0") } } + +func TestResumptionKeepsOCSPAndSCT(t *testing.T) { + t.Run("TLSv12", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS12) }) + t.Run("TLSv13", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS13) }) +} + +func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) { + issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + if err != nil { + t.Fatalf("failed to parse test issuer") + } + roots := x509.NewCertPool() + roots.AddCert(issuer) + clientConfig := &Config{ + MaxVersion: ver, + ClientSessionCache: NewLRUClientSessionCache(32), + ServerName: "example.golang", + RootCAs: roots, + } + serverConfig := testConfig.Clone() + serverConfig.MaxVersion = ver + serverConfig.Certificates[0].OCSPStaple = []byte{1, 2, 3} + serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{4, 5, 6}} + + _, ccs, err := testHandshake(t, clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + // after a new session we expect to see OCSPResponse and + // SignedCertificateTimestamps populated as usual + if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) { + t.Errorf("client ConnectionState contained unexpected OCSPResponse: wanted %v, got %v", + serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse) + } + if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) { + t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps: wanted %v, got %v", + serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps) + } + + // if the server doesn't send any SCTs, repopulate the old SCTs + oldSCTs := serverConfig.Certificates[0].SignedCertificateTimestamps + serverConfig.Certificates[0].SignedCertificateTimestamps = nil + _, ccs, err = testHandshake(t, clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if !ccs.DidResume { + t.Fatalf("expected session to be resumed") + } + // after a resumed session we also expect to see OCSPResponse + // and SignedCertificateTimestamps populated + if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) { + t.Errorf("client ConnectionState contained unexpected OCSPResponse after resumption: wanted %v, got %v", + serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse) + } + if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, oldSCTs) { + t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v", + oldSCTs, ccs.SignedCertificateTimestamps) + } + + // Only test overriding the SCTs for TLS 1.2, since in 1.3 + // the server won't send the message containing them + if ver == VersionTLS13 { + return + } + + // if the server changes the SCTs it sends, they should override the saved SCTs + serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{7, 8, 9}} + _, ccs, err = testHandshake(t, clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if !ccs.DidResume { + t.Fatalf("expected session to be resumed") + } + if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) { + t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v", + serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps) + } +} diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go index 35a00f2f3a..9c61105cf7 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -334,6 +334,8 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { c.didResume = true c.peerCertificates = hs.session.serverCertificates c.verifiedChains = hs.session.verifiedChains + c.ocspResponse = hs.session.ocspResponse + c.scts = hs.session.scts return nil } @@ -666,6 +668,8 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error { nonce: msg.nonce, useBy: c.config.time().Add(lifetime), ageAdd: msg.ageAdd, + ocspResponse: c.ocspResponse, + scts: c.scts, } cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 288c9c666f..338b48861c 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -2129,16 +2129,13 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv authorityKeyId = parent.SubjectKeyId } - encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} - pki := publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey} subjectKeyId := template.SubjectKeyId if len(subjectKeyId) == 0 && template.IsCA { - // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2 - b, err := asn1.Marshal(pki) - if err != nil { - return nil, err - } - h := sha1.Sum(b) + // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: + // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + // value of the BIT STRING subjectPublicKey (excluding the tag, + // length, and number of unused bits). + h := sha1.Sum(publicKeyBytes) subjectKeyId = h[:] } @@ -2147,6 +2144,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return } + encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} c := tbsCertificate{ Version: 2, SerialNumber: template.SerialNumber, @@ -2154,7 +2152,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, - PublicKey: pki, + PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, Extensions: extensions, } diff --git a/src/go/internal/srcimporter/srcimporter.go b/src/go/internal/srcimporter/srcimporter.go index daef27c8b9..90bb3a9bc1 100644 --- a/src/go/internal/srcimporter/srcimporter.go +++ b/src/go/internal/srcimporter/srcimporter.go @@ -20,6 +20,7 @@ import ( "path/filepath" "strings" "sync" + _ "unsafe" // for go:linkname ) // An Importer provides the context for importing packages from source code. @@ -133,7 +134,7 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type // build.Context's VFS. conf.FakeImportC = true } else { - conf.UsesCgo = true + setUsesCgo(&conf) file, err := p.cgo(bp) if err != nil { return nil, err @@ -260,3 +261,6 @@ func (p *Importer) joinPath(elem ...string) string { } return filepath.Join(elem...) } + +//go:linkname setUsesCgo go/types.srcimporter_setUsesCgo +func setUsesCgo(conf *types.Config) diff --git a/src/go/types/api.go b/src/go/types/api.go index 7787b88906..1abcd9d951 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -105,14 +105,14 @@ type Config struct { // Do not use casually! FakeImportC bool - // If UsesCgo is set, the type checker expects the + // If go115UsesCgo is set, the type checker expects the // _cgo_gotypes.go file generated by running cmd/cgo to be // provided as a package source file. Qualified identifiers // referring to package C will be resolved to cgo-provided // declarations within _cgo_gotypes.go. // - // It is an error to set both FakeImportC and UsesCgo. - UsesCgo bool + // It is an error to set both FakeImportC and go115UsesCgo. + go115UsesCgo bool // If Error != nil, it is called with each error found // during type checking; err has dynamic type Error. @@ -140,6 +140,10 @@ type Config struct { DisableUnusedImportCheck bool } +func srcimporter_setUsesCgo(conf *Config) { + conf.go115UsesCgo = true +} + // Info holds result type information for a type-checked package. // Only the information for which a map is provided is collected. // If the package has type errors, the collected information may diff --git a/src/go/types/check.go b/src/go/types/check.go index a94770ffef..007babdf9d 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -248,10 +248,10 @@ func (check *Checker) handleBailout(err *error) { // Files checks the provided files as part of the checker's package. func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) } -var errBadCgo = errors.New("cannot use FakeImportC and UsesCgo together") +var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together") func (check *Checker) checkFiles(files []*ast.File) (err error) { - if check.conf.FakeImportC && check.conf.UsesCgo { + if check.conf.FakeImportC && check.conf.go115UsesCgo { return errBadCgo } diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index f80b4ec784..078adc5ec7 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -141,10 +141,10 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package { } // no package yet => import it - if path == "C" && (check.conf.FakeImportC || check.conf.UsesCgo) { + if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) { imp = NewPackage("C", "C") imp.fake = true // package scope is not populated - imp.cgo = check.conf.UsesCgo + imp.cgo = check.conf.go115UsesCgo } else { // ordinary import var err error diff --git a/src/html/template/html.go b/src/html/template/html.go index 13a0cd0436..356b8298ae 100644 --- a/src/html/template/html.go +++ b/src/html/template/html.go @@ -240,8 +240,7 @@ func htmlNameFilter(args ...interface{}) string { } s = strings.ToLower(s) if t := attrType(s); t != contentTypePlain { - // TODO: Split attr and element name part filters so we can whitelist - // attributes. + // TODO: Split attr and element name part filters so we can recognize known attributes. return filterFailsafe } for _, r := range s { diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index 85c79bbebb..4872fa9851 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -479,7 +479,7 @@ func DupCloseOnExec(fd int) (int, string, error) { return dupCloseOnExecOld(fd) } -// dupCloseOnExecUnixOld is the traditional way to dup an fd and +// dupCloseOnExecOld is the traditional way to dup an fd and // set its O_CLOEXEC bit, using two system calls. func dupCloseOnExecOld(fd int) (int, string, error) { syscall.ForkLock.RLock() diff --git a/src/make.bat b/src/make.bat index f7955ec88a..277a34d5d7 100644 --- a/src/make.bat +++ b/src/make.bat @@ -1,153 +1,152 @@ -:: Copyright 2012 The Go Authors. All rights reserved. -:: Use of this source code is governed by a BSD-style -:: license that can be found in the LICENSE file. - -:: Environment variables that control make.bat: -:: -:: GOROOT_FINAL: The expected final Go root, baked into binaries. -:: The default is the location of the Go tree during the build. -:: -:: GOHOSTARCH: The architecture for host tools (compilers and -:: binaries). Binaries of this type must be executable on the current -:: system, so the only common reason to set this is to set -:: GOHOSTARCH=386 on an amd64 machine. -:: -:: GOARCH: The target architecture for installed packages and tools. -:: -:: GOOS: The target operating system for installed packages and tools. -:: -:: GO_GCFLAGS: Additional go tool compile arguments to use when -:: building the packages and commands. -:: -:: GO_LDFLAGS: Additional go tool link arguments to use when -:: building the commands. -:: -:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1 -:: to include all cgo related files, .c and .go file with "cgo" -:: build directive, in the build. Set it to 0 to ignore them. -:: -:: CC: Command line to run to compile C code for GOHOSTARCH. -:: Default is "gcc". -:: -:: CC_FOR_TARGET: Command line to run compile C code for GOARCH. -:: This is used by cgo. Default is CC. -:: -:: FC: Command line to run to compile Fortran code. -:: This is used by cgo. Default is "gfortran". - -@echo off - -:: Keep environment variables within this script -:: unless invoked with --no-local. -if x%1==x--no-local goto nolocal -if x%2==x--no-local goto nolocal -if x%3==x--no-local goto nolocal -if x%4==x--no-local goto nolocal -setlocal -:nolocal - -set GOENV=off -set GOBUILDFAIL=0 -set GOFLAGS= -set GO111MODULE= - -if exist make.bat goto ok -echo Must run make.bat from Go src directory. -goto fail -:ok - -:: Clean old generated file that will cause problems in the build. -del /F ".\pkg\runtime\runtime_defs.go" 2>NUL - -:: Set GOROOT for build. -cd .. -set GOROOT_TEMP=%CD% -set GOROOT= -cd src -set vflag= -if x%1==x-v set vflag=-v -if x%2==x-v set vflag=-v -if x%3==x-v set vflag=-v -if x%4==x-v set vflag=-v - -if not exist ..\bin\tool mkdir ..\bin\tool - -:: Calculating GOROOT_BOOTSTRAP -if not "x%GOROOT_BOOTSTRAP%"=="x" goto bootstrapset -for /f "tokens=*" %%g in ('where go 2^>nul') do ( - if "x%GOROOT_BOOTSTRAP%"=="x" ( - for /f "tokens=*" %%i in ('%%g env GOROOT 2^>nul') do ( - if /I not %%i==%GOROOT_TEMP% ( - set GOROOT_BOOTSTRAP=%%i - ) - ) - ) -) -if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4 - -:bootstrapset -if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail -set GOROOT=%GOROOT_TEMP% -set GOROOT_TEMP= - -echo Building Go cmd/dist using %GOROOT_BOOTSTRAP% -if x%vflag==x-v echo cmd/dist -setlocal -set GOROOT=%GOROOT_BOOTSTRAP% -set GOOS= -set GOARCH= -set GOBIN= -set GO111MODULE=off -"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist -endlocal -if errorlevel 1 goto fail -.\cmd\dist\dist.exe env -w -p >env.bat -if errorlevel 1 goto fail -call env.bat -del env.bat -if x%vflag==x-v echo. - -if x%1==x--dist-tool goto copydist -if x%2==x--dist-tool goto copydist -if x%3==x--dist-tool goto copydist -if x%4==x--dist-tool goto copydist - -set buildall=-a -if x%1==x--no-clean set buildall= -if x%2==x--no-clean set buildall= -if x%3==x--no-clean set buildall= -if x%4==x--no-clean set buildall= -if x%1==x--no-banner set buildall=%buildall% --no-banner -if x%2==x--no-banner set buildall=%buildall% --no-banner -if x%3==x--no-banner set buildall=%buildall% --no-banner -if x%4==x--no-banner set buildall=%buildall% --no-banner - -:: Run dist bootstrap to complete make.bash. -:: Bootstrap installs a proper cmd/dist, built with the new toolchain. -:: Throw ours, built with Go 1.4, away after bootstrap. -.\cmd\dist\dist.exe bootstrap %vflag% %buildall% -if errorlevel 1 goto fail -del .\cmd\dist\dist.exe -goto end - -:: DO NOT ADD ANY NEW CODE HERE. -:: The bootstrap+del above are the final step of make.bat. -:: If something must be added, add it to cmd/dist's cmdbootstrap, -:: to avoid needing three copies in three different shell languages -:: (make.bash, make.bat, make.rc). - -:copydist -mkdir "%GOTOOLDIR%" 2>NUL -copy cmd\dist\dist.exe "%GOTOOLDIR%\" -goto end - -:bootstrapfail -echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe -echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go 1.4. - -:fail -set GOBUILDFAIL=1 -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% - -:end - +:: Copyright 2012 The Go Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style +:: license that can be found in the LICENSE file. + +:: Environment variables that control make.bat: +:: +:: GOROOT_FINAL: The expected final Go root, baked into binaries. +:: The default is the location of the Go tree during the build. +:: +:: GOHOSTARCH: The architecture for host tools (compilers and +:: binaries). Binaries of this type must be executable on the current +:: system, so the only common reason to set this is to set +:: GOHOSTARCH=386 on an amd64 machine. +:: +:: GOARCH: The target architecture for installed packages and tools. +:: +:: GOOS: The target operating system for installed packages and tools. +:: +:: GO_GCFLAGS: Additional go tool compile arguments to use when +:: building the packages and commands. +:: +:: GO_LDFLAGS: Additional go tool link arguments to use when +:: building the commands. +:: +:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1 +:: to include all cgo related files, .c and .go file with "cgo" +:: build directive, in the build. Set it to 0 to ignore them. +:: +:: CC: Command line to run to compile C code for GOHOSTARCH. +:: Default is "gcc". +:: +:: CC_FOR_TARGET: Command line to run compile C code for GOARCH. +:: This is used by cgo. Default is CC. +:: +:: FC: Command line to run to compile Fortran code. +:: This is used by cgo. Default is "gfortran". + +@echo off + +:: Keep environment variables within this script +:: unless invoked with --no-local. +if x%1==x--no-local goto nolocal +if x%2==x--no-local goto nolocal +if x%3==x--no-local goto nolocal +if x%4==x--no-local goto nolocal +setlocal +:nolocal + +set GOENV=off +set GOBUILDFAIL=0 +set GOFLAGS= +set GO111MODULE= + +if exist make.bat goto ok +echo Must run make.bat from Go src directory. +goto fail +:ok + +:: Clean old generated file that will cause problems in the build. +del /F ".\pkg\runtime\runtime_defs.go" 2>NUL + +:: Set GOROOT for build. +cd .. +set GOROOT_TEMP=%CD% +set GOROOT= +cd src +set vflag= +if x%1==x-v set vflag=-v +if x%2==x-v set vflag=-v +if x%3==x-v set vflag=-v +if x%4==x-v set vflag=-v + +if not exist ..\bin\tool mkdir ..\bin\tool + +:: Calculating GOROOT_BOOTSTRAP +if not "x%GOROOT_BOOTSTRAP%"=="x" goto bootstrapset +for /f "tokens=*" %%g in ('where go 2^>nul') do ( + if "x%GOROOT_BOOTSTRAP%"=="x" ( + for /f "tokens=*" %%i in ('%%g env GOROOT 2^>nul') do ( + if /I not %%i==%GOROOT_TEMP% ( + set GOROOT_BOOTSTRAP=%%i + ) + ) + ) +) +if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4 + +:bootstrapset +if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail +set GOROOT=%GOROOT_TEMP% +set GOROOT_TEMP= + +echo Building Go cmd/dist using %GOROOT_BOOTSTRAP% +if x%vflag==x-v echo cmd/dist +setlocal +set GOROOT=%GOROOT_BOOTSTRAP% +set GOOS= +set GOARCH= +set GOBIN= +set GO111MODULE=off +"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist +endlocal +if errorlevel 1 goto fail +.\cmd\dist\dist.exe env -w -p >env.bat +if errorlevel 1 goto fail +call env.bat +del env.bat +if x%vflag==x-v echo. + +if x%1==x--dist-tool goto copydist +if x%2==x--dist-tool goto copydist +if x%3==x--dist-tool goto copydist +if x%4==x--dist-tool goto copydist + +set buildall=-a +if x%1==x--no-clean set buildall= +if x%2==x--no-clean set buildall= +if x%3==x--no-clean set buildall= +if x%4==x--no-clean set buildall= +if x%1==x--no-banner set buildall=%buildall% --no-banner +if x%2==x--no-banner set buildall=%buildall% --no-banner +if x%3==x--no-banner set buildall=%buildall% --no-banner +if x%4==x--no-banner set buildall=%buildall% --no-banner + +:: Run dist bootstrap to complete make.bash. +:: Bootstrap installs a proper cmd/dist, built with the new toolchain. +:: Throw ours, built with Go 1.4, away after bootstrap. +.\cmd\dist\dist.exe bootstrap %vflag% %buildall% +if errorlevel 1 goto fail +del .\cmd\dist\dist.exe +goto end + +:: DO NOT ADD ANY NEW CODE HERE. +:: The bootstrap+del above are the final step of make.bat. +:: If something must be added, add it to cmd/dist's cmdbootstrap, +:: to avoid needing three copies in three different shell languages +:: (make.bash, make.bat, make.rc). + +:copydist +mkdir "%GOTOOLDIR%" 2>NUL +copy cmd\dist\dist.exe "%GOTOOLDIR%\" +goto end + +:bootstrapfail +echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe +echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go 1.4. + +:fail +set GOBUILDFAIL=1 +if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% + +:end diff --git a/src/net/http/request.go b/src/net/http/request.go index e924e2a07f..fe6b60982c 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -503,7 +503,7 @@ func valueOrDefault(value, def string) string { // NOTE: This is not intended to reflect the actual Go version being used. // It was changed at the time of Go 1.1 release because the former User-Agent -// had ended up on a blacklist for some intrusion detection systems. +// had ended up blocked by some intrusion detection systems. // See https://codereview.appspot.com/7532043. const defaultUserAgent = "Go-http-client/1.1" diff --git a/src/net/http/server.go b/src/net/http/server.go index b613c21f16..a995a50658 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1698,9 +1698,9 @@ func (c *conn) closeWriteAndWait() { time.Sleep(rstAvoidanceDelay) } -// validNextProto reports whether the proto is not a blacklisted ALPN -// protocol name. Empty and built-in protocol types are blacklisted -// and can't be overridden with alternate implementations. +// validNextProto reports whether the proto is a valid ALPN protocol name. +// Everything is valid except the empty string and built-in protocol types, +// so that those can't be overridden with alternate implementations. func validNextProto(proto string) bool { switch proto { case "", "http/1.1", "http/1.0": diff --git a/src/os/file_unix.go b/src/os/file_unix.go index b93e2bd56a..f2c00ae0cb 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -202,10 +202,8 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { break } - // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause - // open(2) to be restarted for regular files. This is easy to reproduce on - // fuse file systems (see https://golang.org/issue/11180). - if runtime.GOOS == "darwin" && e == syscall.EINTR { + // We have to check EINTR here, per issues 11180 and 39237. + if e == syscall.EINTR { continue } diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go index e619851f9c..37bf1b8f2f 100644 --- a/src/os/removeall_at.go +++ b/src/os/removeall_at.go @@ -9,7 +9,6 @@ package os import ( "internal/syscall/unix" "io" - "runtime" "syscall" ) @@ -178,7 +177,7 @@ func openFdAt(dirfd int, name string) (*File, error) { } // See comment in openFileNolog. - if runtime.GOOS == "darwin" && e == syscall.EINTR { + if e == syscall.EINTR { continue } diff --git a/src/os/signal/internal/pty/pty.go b/src/os/signal/internal/pty/pty.go index fb3ee1ea7a..f8813ce6be 100644 --- a/src/os/signal/internal/pty/pty.go +++ b/src/os/signal/internal/pty/pty.go @@ -40,8 +40,8 @@ func (e *PtyError) Error() string { func (e *PtyError) Unwrap() error { return e.Errno } -// Open returns a master pty and the name of the linked slave tty. -func Open() (master *os.File, slave string, err error) { +// Open returns a control pty and the name of the linked process tty. +func Open() (pty *os.File, processTTY string, err error) { m, err := C.posix_openpt(C.O_RDWR) if err != nil { return nil, "", ptyError("posix_openpt", err) @@ -54,6 +54,6 @@ func Open() (master *os.File, slave string, err error) { C.close(m) return nil, "", ptyError("unlockpt", err) } - slave = C.GoString(C.ptsname(m)) - return os.NewFile(uintptr(m), "pty-master"), slave, nil + processTTY = C.GoString(C.ptsname(m)) + return os.NewFile(uintptr(m), "pty"), processTTY, nil } diff --git a/src/os/signal/signal_cgo_test.go b/src/os/signal/signal_cgo_test.go index 849a96ec0e..a117221400 100644 --- a/src/os/signal/signal_cgo_test.go +++ b/src/os/signal/signal_cgo_test.go @@ -19,7 +19,7 @@ import ( "io" "os" "os/exec" - "os/signal/internal/pty" + ptypkg "os/signal/internal/pty" "strconv" "strings" "sync" @@ -71,20 +71,20 @@ func TestTerminalSignal(t *testing.T) { // The test only fails when using a "slow device," in this // case a pseudo-terminal. - master, sname, err := pty.Open() + pty, procTTYName, err := ptypkg.Open() if err != nil { - ptyErr := err.(*pty.PtyError) + ptyErr := err.(*ptypkg.PtyError) if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES { t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping") } t.Fatal(err) } - defer master.Close() - slave, err := os.OpenFile(sname, os.O_RDWR, 0) + defer pty.Close() + procTTY, err := os.OpenFile(procTTYName, os.O_RDWR, 0) if err != nil { t.Fatal(err) } - defer slave.Close() + defer procTTY.Close() // Start an interactive shell. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -92,9 +92,9 @@ func TestTerminalSignal(t *testing.T) { cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i") // Clear HISTFILE so that we don't read or clobber the user's bash history. cmd.Env = append(os.Environ(), "HISTFILE=") - cmd.Stdin = slave - cmd.Stdout = slave - cmd.Stderr = slave + cmd.Stdin = procTTY + cmd.Stdout = procTTY + cmd.Stderr = procTTY cmd.SysProcAttr = &syscall.SysProcAttr{ Setsid: true, Setctty: true, @@ -105,21 +105,21 @@ func TestTerminalSignal(t *testing.T) { t.Fatal(err) } - if err := slave.Close(); err != nil { - t.Errorf("closing slave: %v", err) + if err := procTTY.Close(); err != nil { + t.Errorf("closing procTTY: %v", err) } progReady := make(chan bool) sawPrompt := make(chan bool, 10) const prompt = "prompt> " - // Read data from master in the background. + // Read data from pty in the background. var wg sync.WaitGroup wg.Add(1) defer wg.Wait() go func() { defer wg.Done() - input := bufio.NewReader(master) + input := bufio.NewReader(pty) var line, handled []byte for { b, err := input.ReadByte() @@ -130,11 +130,11 @@ func TestTerminalSignal(t *testing.T) { if perr, ok := err.(*os.PathError); ok { err = perr.Err } - // EOF means master is closed. + // EOF means pty is closed. // EIO means child process is done. - // "file already closed" means deferred close of master has happened. + // "file already closed" means deferred close of pty has happened. if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") { - t.Logf("error reading from master: %v", err) + t.Logf("error reading from pty: %v", err) } return } @@ -161,7 +161,7 @@ func TestTerminalSignal(t *testing.T) { }() // Set the bash prompt so that we can see it. - if _, err := master.Write([]byte("PS1='" + prompt + "'\n")); err != nil { + if _, err := pty.Write([]byte("PS1='" + prompt + "'\n")); err != nil { t.Fatalf("setting prompt: %v", err) } select { @@ -172,7 +172,7 @@ func TestTerminalSignal(t *testing.T) { // Start a small program that reads from stdin // (namely the code at the top of this function). - if _, err := master.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil { + if _, err := pty.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil { t.Fatal(err) } @@ -190,7 +190,7 @@ func TestTerminalSignal(t *testing.T) { time.Sleep(pause) // Send a ^Z to stop the program. - if _, err := master.Write([]byte{26}); err != nil { + if _, err := pty.Write([]byte{26}); err != nil { t.Fatalf("writing ^Z to pty: %v", err) } @@ -202,7 +202,7 @@ func TestTerminalSignal(t *testing.T) { } // Restart the stopped program. - if _, err := master.Write([]byte("fg\n")); err != nil { + if _, err := pty.Write([]byte("fg\n")); err != nil { t.Fatalf("writing %q to pty: %v", "fg", err) } @@ -217,7 +217,7 @@ func TestTerminalSignal(t *testing.T) { // Write some data for the program to read, // which should cause it to exit. - if _, err := master.Write([]byte{'\n'}); err != nil { + if _, err := pty.Write([]byte{'\n'}); err != nil { t.Fatalf("writing %q to pty: %v", "\n", err) } @@ -229,7 +229,7 @@ func TestTerminalSignal(t *testing.T) { } // Exit the shell with the program's exit status. - if _, err := master.Write([]byte("exit $?\n")); err != nil { + if _, err := pty.Write([]byte("exit $?\n")); err != nil { t.Fatalf("writing %q to pty: %v", "exit", err) } diff --git a/src/race.bat b/src/race.bat index d26f3180a3..8f0355612c 100644 --- a/src/race.bat +++ b/src/race.bat @@ -1,51 +1,51 @@ -:: Copyright 2013 The Go Authors. All rights reserved. -:: Use of this source code is governed by a BSD-style -:: license that can be found in the LICENSE file. - -:: race.bash tests the standard library under the race detector. -:: https://golang.org/doc/articles/race_detector.html - -@echo off - -setlocal - -if exist make.bat goto ok -echo race.bat must be run from go\src -:: cannot exit: would kill parent command interpreter -goto end -:ok - -set GOROOT=%CD%\.. -call make.bat --dist-tool >NUL -if errorlevel 1 goto fail -.\cmd\dist\dist.exe env -w -p >env.bat -if errorlevel 1 goto fail -call env.bat -del env.bat - -if %GOHOSTARCH% == amd64 goto continue -echo Race detector is only supported on windows/amd64. -goto fail - -:continue -call make.bat --no-banner --no-local -if %GOBUILDFAIL%==1 goto end -echo # go install -race std -go install -race std -if errorlevel 1 goto fail - -go tool dist test -race - -if errorlevel 1 goto fail -goto succ - -:fail -set GOBUILDFAIL=1 -echo Fail. -goto end - -:succ -echo All tests passed. - -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +:: Copyright 2013 The Go Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style +:: license that can be found in the LICENSE file. + +:: race.bash tests the standard library under the race detector. +:: https://golang.org/doc/articles/race_detector.html + +@echo off + +setlocal + +if exist make.bat goto ok +echo race.bat must be run from go\src +:: cannot exit: would kill parent command interpreter +goto end +:ok + +set GOROOT=%CD%\.. +call make.bat --dist-tool >NUL +if errorlevel 1 goto fail +.\cmd\dist\dist.exe env -w -p >env.bat +if errorlevel 1 goto fail +call env.bat +del env.bat + +if %GOHOSTARCH% == amd64 goto continue +echo Race detector is only supported on windows/amd64. +goto fail + +:continue +call make.bat --no-banner --no-local +if %GOBUILDFAIL%==1 goto end +echo # go install -race std +go install -race std +if errorlevel 1 goto fail + +go tool dist test -race + +if errorlevel 1 goto fail +goto succ + +:fail +set GOBUILDFAIL=1 +echo Fail. +goto end + +:succ +echo All tests passed. + +:end +if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% diff --git a/src/run.bat b/src/run.bat index 69c181854b..c299671c13 100644 --- a/src/run.bat +++ b/src/run.bat @@ -1,59 +1,54 @@ -:: Copyright 2012 The Go Authors. All rights reserved. -:: Use of this source code is governed by a BSD-style -:: license that can be found in the LICENSE file. - -@echo off - -if exist ..\bin\go.exe goto ok -echo Must run run.bat from Go src directory after installing cmd/go. -goto fail -:ok - -:: Keep environment variables within this script -:: unless invoked with --no-local. -if x%1==x--no-local goto nolocal -if x%2==x--no-local goto nolocal -setlocal -:nolocal - -set GOBUILDFAIL=0 - -:: we disallow local import for non-local packages, if %GOROOT% happens -:: to be under %GOPATH%, then some tests below will fail -set GOPATH= -:: Issue 14340: ignore GOBIN during all.bat. -set GOBIN= -set GOFLAGS= -set GO111MODULE= - -rem TODO avoid rebuild if possible - -if x%1==x--no-rebuild goto norebuild -echo ##### Building packages and commands. -..\bin\go install -a -v std cmd -if errorlevel 1 goto fail -echo. -:norebuild - -:: we must unset GOROOT_FINAL before tests, because runtime/debug requires -:: correct access to source code, so if we have GOROOT_FINAL in effect, -:: at least runtime/debug test will fail. -set GOROOT_FINAL= - -:: get CGO_ENABLED -..\bin\go env > env.bat -if errorlevel 1 goto fail -call env.bat -del env.bat -echo. - -..\bin\go tool dist test -if errorlevel 1 goto fail -echo. - -goto end - -:fail -set GOBUILDFAIL=1 - -:end +:: Copyright 2012 The Go Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style +:: license that can be found in the LICENSE file. + +@echo off + +if exist ..\bin\go.exe goto ok +echo Must run run.bat from Go src directory after installing cmd/go. +goto fail +:ok + +:: Keep environment variables within this script +:: unless invoked with --no-local. +if x%1==x--no-local goto nolocal +if x%2==x--no-local goto nolocal +setlocal +:nolocal + +set GOBUILDFAIL=0 + +:: we disallow local import for non-local packages, if %GOROOT% happens +:: to be under %GOPATH%, then some tests below will fail +set GOPATH= +:: Issue 14340: ignore GOBIN during all.bat. +set GOBIN= +set GOFLAGS= +set GO111MODULE= + +rem TODO avoid rebuild if possible + +if x%1==x--no-rebuild goto norebuild +echo ##### Building packages and commands. +..\bin\go install -a -v std cmd +if errorlevel 1 goto fail +echo. +:norebuild + +:: get CGO_ENABLED +..\bin\go env > env.bat +if errorlevel 1 goto fail +call env.bat +del env.bat +echo. + +..\bin\go tool dist test +if errorlevel 1 goto fail +echo. + +goto end + +:fail +set GOBUILDFAIL=1 + +:end diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go index bc5e0786d9..de634dc957 100644 --- a/src/runtime/cgo_sigaction.go +++ b/src/runtime/cgo_sigaction.go @@ -18,12 +18,12 @@ var _cgo_sigaction unsafe.Pointer //go:nosplit //go:nowritebarrierrec func sigaction(sig uint32, new, old *sigactiont) { - // The runtime package is explicitly blacklisted from sanitizer - // instrumentation in racewalk.go, but we might be calling into instrumented C - // functions here — so we need the pointer parameters to be properly marked. + // racewalk.go avoids adding sanitizing instrumentation to package runtime, + // but we might be calling into instrumented C functions here, + // so we need the pointer parameters to be properly marked. // - // Mark the input as having been written before the call and the output as - // read after. + // Mark the input as having been written before the call + // and the output as read after. if msanenabled && new != nil { msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new)) } diff --git a/src/runtime/debugcall.go b/src/runtime/debugcall.go index 5cbe382ce7..6c285ec829 100644 --- a/src/runtime/debugcall.go +++ b/src/runtime/debugcall.go @@ -61,7 +61,7 @@ func debugCallCheck(pc uintptr) string { "debugCall16384", "debugCall32768", "debugCall65536": - // These functions are whitelisted so that the debugger can initiate multiple function calls. + // These functions are allowed so that the debugger can initiate multiple function calls. // See: https://golang.org/cl/161137/ return } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 77a5a38768..eaf8db7220 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -976,6 +976,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { throw("malloc called with no P") } } + var span *mspan var x unsafe.Pointer noscan := typ == nil || typ.ptrdata == 0 if size <= maxSmallSize { @@ -1028,10 +1029,10 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return x } // Allocate a new maxTinySize block. - span := c.alloc[tinySpanClass] + span = c.alloc[tinySpanClass] v := nextFreeFast(span) if v == 0 { - v, _, shouldhelpgc = c.nextFree(tinySpanClass) + v, span, shouldhelpgc = c.nextFree(tinySpanClass) } x = unsafe.Pointer(v) (*[2]uint64)(x)[0] = 0 @@ -1052,7 +1053,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { } size = uintptr(class_to_size[sizeclass]) spc := makeSpanClass(sizeclass, noscan) - span := c.alloc[spc] + span = c.alloc[spc] v := nextFreeFast(span) if v == 0 { v, span, shouldhelpgc = c.nextFree(spc) @@ -1063,15 +1064,14 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { } } } else { - var s *mspan shouldhelpgc = true systemstack(func() { - s = largeAlloc(size, needzero, noscan) + span = largeAlloc(size, needzero, noscan) }) - s.freeindex = 1 - s.allocCount = 1 - x = unsafe.Pointer(s.base()) - size = s.elemsize + span.freeindex = 1 + span.allocCount = 1 + x = unsafe.Pointer(span.base()) + size = span.elemsize } var scanSize uintptr @@ -1112,7 +1112,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { // This may be racing with GC so do it atomically if there can be // a race marking the bit. if gcphase != _GCoff { - gcmarknewobject(uintptr(x), size, scanSize) + gcmarknewobject(span, uintptr(x), size, scanSize) } if raceenabled { diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index dafb4634b4..fe988c46d9 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -1627,11 +1627,21 @@ func gcDumpObject(label string, obj, off uintptr) { // //go:nowritebarrier //go:nosplit -func gcmarknewobject(obj, size, scanSize uintptr) { +func gcmarknewobject(span *mspan, obj, size, scanSize uintptr) { if useCheckmark { // The world should be stopped so this should not happen. throw("gcmarknewobject called while doing checkmark") } - markBitsForAddr(obj).setMarked() + + // Mark object. + objIndex := span.objIndex(obj) + span.markBitsForIndex(objIndex).setMarked() + + // Mark span. + arena, pageIdx, pageMask := pageIndexOf(span.base()) + if arena.pageMarks[pageIdx]&pageMask == 0 { + atomic.Or8(&arena.pageMarks[pageIdx], pageMask) + } + gcw := &getg().m.p.ptr().gcw gcw.bytesMarked += uint64(size) gcw.scanWork += int64(scanSize) diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index ba508729c5..6a8a34d1ed 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -529,7 +529,7 @@ func updatememstats() { // Calculate memory allocator stats. // During program execution we only count number of frees and amount of freed memory. - // Current number of alive object in the heap and amount of alive heap memory + // Current number of alive objects in the heap and amount of alive heap memory // are calculated by scanning all spans. // Total number of mallocs is calculated as number of frees plus number of alive objects. // Similarly, total amount of allocated memory is calculated as amount of freed memory diff --git a/src/runtime/mwbbuf.go b/src/runtime/mwbbuf.go index f444452bab..632769c114 100644 --- a/src/runtime/mwbbuf.go +++ b/src/runtime/mwbbuf.go @@ -296,6 +296,13 @@ func wbBufFlush1(_p_ *p) { continue } mbits.setMarked() + + // Mark span. + arena, pageIdx, pageMask := pageIndexOf(span.base()) + if arena.pageMarks[pageIdx]&pageMask == 0 { + atomic.Or8(&arena.pageMarks[pageIdx], pageMask) + } + if span.spanclass.noscan() { gcw.bytesMarked += uint64(span.elemsize) continue diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index ce2ec6dd1d..1e86662adc 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -563,8 +563,8 @@ func moduledataverify1(datap *moduledata) { // given program counter address, or else nil. // // If pc represents multiple functions because of inlining, it returns -// the a *Func describing the innermost function, but with an entry -// of the outermost function. +// the *Func describing the innermost function, but with an entry of +// the outermost function. func FuncForPC(pc uintptr) *Func { f := findfunc(pc) if !f.valid() { diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index eb2f3317c9..90808573c2 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -253,6 +253,8 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 { // 'comparing to zero' expressions // var + const +// 'x-const' might be canonicalized to 'x+(-const)', so we check both +// CMN and CMP for subtraction expressions to make the pattern robust. func CmpToZero_ex1(a int64, e int32) int { // arm64:`CMN`,-`ADD`,`(BMI|BPL)` if a+3 < 0 { @@ -269,37 +271,41 @@ func CmpToZero_ex1(a int64, e int32) int { return 2 } - // arm64:`CMP`,-`SUB`,`(BMI|BPL)` + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)` if a-7 < 0 { return 3 } - // arm64:`CMP`,-`SUB`,`(BMI|BPL)` + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)` if a-11 >= 0 { return 4 } - // arm64:`CMP`,-`SUB`,`BEQ`,`(BMI|BPL)` + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`BEQ`,`(BMI|BPL)` if a-19 > 0 { return 4 } // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` if e+3 < 0 { return 5 } // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` if e+13 >= 0 { return 6 } - // arm64:`CMPW`,-`SUBW`,`(BMI|BPL)` + // arm64:`CMPW|CMNW`,`(BMI|BPL)` + // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)` if e-7 < 0 { return 7 } - // arm64:`CMPW`,-`SUBW`,`(BMI|BPL)` + // arm64:`CMPW|CMNW`,`(BMI|BPL)` + // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)` if e-11 >= 0 { return 8 } @@ -326,11 +332,13 @@ func CmpToZero_ex2(a, b, c int64, e, f, g int32) int { } // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` if e+f < 0 { return 5 } // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` if f+g >= 0 { return 6 } @@ -350,11 +358,13 @@ func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int { } // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)` + // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)` if e+f*g > 0 { return 5 } // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)` + // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)` if f+g*h <= 0 { return 6 } @@ -384,3 +394,16 @@ func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int { } return 0 } + +func CmpToZero_ex5(e, f int32, u uint32) int { + // arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)` + if e+f<<1 > 0 { + return 1 + } + + // arm:`CMP`,-`SUB`,`(BMI|BPL)` + if f-int32(u>>2) >= 0 { + return 2 + } + return 0 +} diff --git a/test/fixedbugs/issue39472.go b/test/fixedbugs/issue39472.go new file mode 100644 index 0000000000..61444a28b9 --- /dev/null +++ b/test/fixedbugs/issue39472.go @@ -0,0 +1,12 @@ +// compile -N + +// 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 p + +func f(x float64) bool { + x += 1 + return (x != 0) == (x != 0) +} diff --git a/test/winbatch.go b/test/winbatch.go index 30e0e3c982..c3b48d385c 100644 --- a/test/winbatch.go +++ b/test/winbatch.go @@ -4,8 +4,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Check that batch files are maintained as CRLF files (consistent behaviour -// on all operating systems). See https://github.com/golang/go/issues/37791 +// Check that batch files are maintained as CRLF files (consistent +// behavior on all operating systems). See golang.org/issue/37791. package main @@ -13,18 +13,56 @@ import ( "bytes" "fmt" "io/ioutil" + "log" "os" "path/filepath" "runtime" + "strings" ) func main() { - batches, _ := filepath.Glob(runtime.GOROOT() + "/src/*.bat") - for _, bat := range batches { - body, _ := ioutil.ReadFile(bat) - if !bytes.Contains(body, []byte("\r\n")) { - fmt.Printf("Windows batch file %s does not contain CRLF line termination.\nTry running git checkout src/*.bat to fix this.\n", bat) - os.Exit(1) + // Ensure that the GOROOT/src/all.bat file exists and has strict CRLF line endings. + enforceBatchStrictCRLF(filepath.Join(runtime.GOROOT(), "src", "all.bat")) + + // Walk the entire Go repository source tree (without GOROOT/pkg), + // skipping directories that start with "." and named "testdata", + // and ensure all .bat files found have exact CRLF line endings. + err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err } + if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") { + return filepath.SkipDir + } + if path == filepath.Join(runtime.GOROOT(), "pkg") { + // GOROOT/pkg is known to contain generated artifacts, not source code. + // Skip it to avoid false positives. (Also see golang.org/issue/37929.) + return filepath.SkipDir + } + if filepath.Ext(fi.Name()) == ".bat" { + enforceBatchStrictCRLF(path) + } + return nil + }) + if err != nil { + log.Fatalln(err) + } +} + +func enforceBatchStrictCRLF(path string) { + b, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalln(err) + } + cr, lf := bytes.Count(b, []byte{13}), bytes.Count(b, []byte{10}) + crlf := bytes.Count(b, []byte{13, 10}) + if cr != crlf || lf != crlf { + if rel, err := filepath.Rel(runtime.GOROOT(), path); err == nil { + // Make the test failure more readable by showing a path relative to GOROOT. + path = rel + } + fmt.Printf("Windows batch file %s does not use strict CRLF line termination.\n", path) + fmt.Printf("Please convert it to CRLF before checking it in due to golang.org/issue/37791.\n") + os.Exit(1) } }