[dev.link] all: merge branch 'master' into dev.link

Change-Id: I446db56b20ef2189e23e225a91a17736c1d11e4c
diff --git a/.gitattributes b/.gitattributes
index bcea029..cabbb17 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 69e35a1..80c79fe 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1397,6 +1397,7 @@
 Uriel Mangado <uriel@berlinblue.org>
 Vadim Grek <vadimprog@gmail.com>
 Vadim Vygonets <unixdj@gmail.com>
+Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
 Vendasta
 Veselkov Konstantin <kostozyb@gmail.com>
 Victor Vrantchan <vrancean+github@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 934834f..6b6ee09 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -2195,6 +2195,7 @@
 Vadim Vygonets <unixdj@gmail.com>
 Val Polouchkine <vpolouch@justin.tv>
 Valentin Vidic <vvidic@valentin-vidic.from.hr>
+Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
 Vega Garcia Luis Alfonso <vegacom@gmail.com>
 Venil Noronha <veniln@vmware.com>
 Veselkov Konstantin <kostozyb@gmail.com>
diff --git a/api/go1.15.txt b/api/go1.15.txt
new file mode 100644
index 0000000..b51837c
--- /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 442c29a..e69de29 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 41db36a..853f874 100644
--- a/doc/go1.10.html
+++ b/doc/go1.10.html
@@ -30,7 +30,7 @@
 runs <a href="#test-vet">vet automatically during tests</a>,
 and
 permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
-A new <a href="#cgo">compiler option whitelist</a> may cause
+A new <a href="#cgo">hard-coded set of safe compiler options</a> may cause
 unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
 flag</code></a> errors in code that built successfully with older
 releases.
@@ -267,7 +267,7 @@
 
 <p>
 Options specified by cgo using <code>#cgo CFLAGS</code> 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
 <span style="white-space: nowrap"><code>-fplugin</code></span>
diff --git a/doc/go1.15.html b/doc/go1.15.html
index 492cac0..dd25b27 100644
--- a/doc/go1.15.html
+++ b/doc/go1.15.html
@@ -55,6 +55,13 @@
   on Windows.
 </p>
 
+<p><!-- CL 227003 -->
+  The <code>-race</code> and <code>-msan</code> flags now always
+  enable <code>-d=checkptr</code>, which checks uses
+  of <code>unsafe.Pointer</code>. This was previously the case on all
+  OSes except Windows.
+</p>
+
 <p><!-- CL 211139 -->
   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 @@
 
 <h2 id="runtime">Runtime</h2>
 
-<p><!-- CL 232862 -->
-  Go now retries system calls that return <code>EINTR</code>. This
-  became more common in Go 1.14 with the addition of asynchronous
-  preemption, but is now handled transparently.
+<p><!-- CL 221779 -->
+  If <code>panic</code> is invoked with a value whose type is derived from any
+  of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
+  <code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
+  <code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
+  then the value will be printed, instead of just its address.
+  Previously, this was only true for values of exactly these types.
+</p>
+
+<p><!-- CL 228900 -->
+  On a Unix system, if the <code>kill</code> command
+  or <code>kill</code> system call is used to send
+  a <code>SIGSEGV</code>, <code>SIGBUS</code>,
+  or <code>SIGFPE</code> signal to a Go program, and if the signal
+  is not being handled via
+  <a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
+  the Go program will now reliably crash with a stack trace.
+  In earlier releases the behavior was unpredictable.
 </p>
 
 <p><!-- CL 221182, CL 229998 -->
@@ -222,8 +243,14 @@
   counts, and has lower worst-case latency.
 </p>
 
-<p>
-TODO
+<p><!-- CL 216401 -->
+  Converting a small integer value into an interface value no longer
+  causes allocation.
+</p>
+
+<p><!-- CL 216818 -->
+  Non-blocking receives on closed channels now perform as well as
+  non-blocking receives on open channels.
 </p>
 
 <h2 id="compiler">Compiler</h2>
@@ -245,6 +272,15 @@
   aggressively eliminating unused type metadata.
 </p>
 
+<p><!-- CL 219357, CL 231600 -->
+  The toolchain now mitigates
+  <a href="https://www.intel.com/content/www/us/en/support/articles/000055650/processors.html">Intel
+  CPU erratum SKX102</a> on <code>GOARCH=amd64</code> 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.
+</p>
+
 <p><!-- CL 222661 -->
   Go 1.15 adds a <code>-spectre</code> flag to both the
   compiler and the assembler, to allow enabling Spectre mitigations.
@@ -253,6 +289,19 @@
   See the <a href="https://github.com/golang/go/wiki/Spectre">Spectre wiki page</a> for details.
 </p>
 
+<p><!-- CL 228578 -->
+  The compiler now rejects <code>//go:</code> 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.
+</p>
+
+<p><!-- CL 206658, CL 205066 -->
+  The compiler's <code>-json</code> optimization logging now reports
+  large (>= 128 byte) copies and includes explanations of escape
+  analysis decisions.
+</p>
+
 <h2 id="linker">Linker</h2>
 
 <p>
@@ -283,6 +332,14 @@
   improvements expected in future releases.
 </p>
 
+<h2 id="objdump">Objdump</h2>
+
+<p><!-- CL 225459 -->
+  The <a href="/cmd/objdump/">objdump</a> tool now supports
+  disassembling in GNU assembler syntax with the <code>-gnu</code>
+  flag.
+</p>
+
 <h2 id="library">Core library</h2>
 
 <h3 id="time/tzdata">New embedded tzdata package</h3>
@@ -299,10 +356,6 @@
   Either approach increases the size of the program by about 800 KB.
 </p>
 
-<p>
-TODO
-</p>
-
 <h3 id="cgo">Cgo</h3>
 
 <p><!-- CL 235817 -->
@@ -321,10 +374,6 @@
   in mind.
 </p>
 
-<p>
-TODO
-</p>
-
 <dl id="debug/pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
   <dd>
     <p><!-- CL 222637 -->
@@ -336,10 +385,53 @@
   </dd>
 </dl><!-- debug/pe -->
 
+<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
+  <dd>
+    <p><!-- CL 231417, CL 225460 -->
+      The <code>PrivateKey</code> and <code>PublicKey</code> types in the
+      <a href="/pkg/crypto/rsa"><code>crypto/rsa</code></a>,
+      <a href="/pkg/crypto/ecdsa"><code>crypto/ecdsa</code></a>, and
+      <a href="/pkg/crypto/ed25519"><code>crypto/ed25519</code></a> packages
+      now have an <code>Equal</code> method to compare keys for equivalence
+      or to make type-safe interfaces for public keys. The method signature
+      is compatible with
+      <a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal"><code>go-cmp</code>'s
+      definition of equality</a>.
+    </p>
+
+    <p><!-- CL 224937 -->
+      <a href="/pkg/crypto/#Hash"><code>Hash</code></a> now implements
+      <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
+    </p>
+  </dd>
+</dl><!-- crypto -->
+
+<dl id="crypto/ecdsa"><dt><a href="/pkg/crypto/ecdsa/">crypto/ecdsa</a></dt>
+  <dd>
+    <p><!-- CL 217940 -->
+      The new <a href="/pkg/crypto/ecdsa/#SignASN1"><code>SignASN1</code></a>
+      and <a href="/pkg/crypto/ecdsa/#VerifyASN1"><code>VerifyASN1</code></a>
+      functions allow generating and verifying ECDSA signatures in the standard
+      ASN.1 DER encoding.
+    </p>
+  </dd>
+</dl><!-- crypto/ecdsa -->
+
+<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
+  <dd>
+    <p><!-- CL 202819 -->
+      The new <a href="/pkg/crypto/elliptic/#MarshalCompressed"><code>MarshalCompressed</code></a>
+      and <a href="/pkg/crypto/elliptic/#UnmarshalCompressed"><code>UnmarshalCompressed</code></a>
+      functions allow encoding and decoding NIST elliptic curve points in compressed format.
+    </p>
+  </dd>
+</dl><!-- crypto/elliptic -->
+
 <dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
   <dd>
     <p><!-- CL 226203 -->
-      VerifyPKCS1v15 now rejects invalid short signatures with missing leading zeroes.
+      <a href="/pkg/crypto/rsa/#VerifyPKCS1v15"><code>VerifyPKCS1v15</code></a>
+      now rejects invalid short signatures with missing leading zeroes, according to RFC 8017.
     </p>
   </dd>
 </dl><!-- crypto/rsa -->
@@ -353,21 +445,137 @@
       <a href="/pkg/crypto/tls/#Dialer.DialContext"><code>DialContext</code></a>
       method permits using a context to both connect and handshake with a TLS server.
     </p>
+
+    <p><!-- CL 229122 -->
+      The new
+      <a href="/pkg/crypto/tls/#Config.VerifyConnection"><code>VerifyConnection</code></a>
+      callback on the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> type
+      allows custom verification logic for every connection. It has access to the
+      <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+      which includes peer certificates, SCTs, and stapled OCSP responses.
+    </p>
+
+    <p><!-- CL 230679 -->
+      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.
+    </p>
+
+    <p><!-- CL 231317 -->
+      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.
+    </p>
+
+    <p><!-- CL 231038 -->
+      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.
+    </p>
+
+    <p><!-- CL 208226 -->
+      <a href="/pkg/crypto/tls/#SignatureScheme"><code>SignatureScheme</code></a>,
+      <a href="/pkg/crypto/tls/#CurveID"><code>CurveID</code></a>, and
+      <a href="/pkg/crypto/tls/#ClientAuthType"><code>ClientAuthType</code></a>
+      now implement <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
+    </p>
+
+    <p><!-- CL 236737 -->
+      The <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+      fields <code>OCSPResponse</code> and <code>SignedCertificateTimestamps</code>
+      are now repopulated on client-side resumed connections.
+    </p>
   </dd>
-</dl>
+</dl><!-- crypto/tls -->
 
 <dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
   <dd>
+    <p><!-- CL 231378, CL 231380, CL 231381 -->
+      If either the name on the certificate or the name being verified (with
+      <a href="/pkg/crypto/x509/#VerifyOptions.DNSName"><code>VerifyOptions.DNSName</code></a>
+      or <a href="/pkg/crypto/x509/#Certificate.VerifyHostname"><code>VerifyHostname</code></a>)
+      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.
+    </p>
+
+    <p><!-- CL 231379 -->
+      The deprecated, legacy behavior of treating the <code>CommonName</code>
+      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
+      <code>x509ignoreCN=0</code> to the <code>GODEBUG</code> environment
+      variable. If the <code>CommonName</code> is an invalid hostname, it's
+      always ignored.
+    </p>
+
+    <p><!-- CL 217298 -->
+      The new <a href="/pkg/crypto/x509/#CreateRevocationList"><code>CreateRevocationList</code></a>
+      function and <a href="/pkg/crypto/x509/#RevocationList"><code>RevocationList</code></a> type
+      allow creating RFC 5280-compliant X.509 v2 Certificate Revocation Lists.
+    </p>
+
+    <p><!-- CL 227098 -->
+      <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+      now automatically generates the <code>SubjectKeyId</code> if the template
+      is a CA and doesn't explicitly specify one.
+    </p>
+
+    <p><!-- CL 228777 -->
+      <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+      now returns an error if the template specifies <code>MaxPathLen</code> but is not a CA.
+    </p>
+
     <p><!-- CL 205237 -->
-      TODO: <a href="https://golang.org/cl/205237">https://golang.org/cl/205237</a>: load roots from colon separated SSL_CERT_DIR in loadSystemRoots
+      On Unix systems other than macOS, the <code>SSL_CERT_DIR</code>
+      environment variable can now be a colon-separated list.
+    </p>
+
+    <p><!-- CL 227037 -->
+      On macOS, binaries are now always linked against
+      <code>Security.framework</code> to extract the system trust roots,
+      regardless of whether cgo is available. The resulting behavior should be
+      more consistent with the OS verifier.
     </p>
   </dd>
 </dl><!-- crypto/x509 -->
 
+<dl id="crypto/x509/pkix"><dt><a href="/pkg/crypto/x509/pkix/">crypto/x509/pkix</a></dt>
+  <dd>
+    <p><!-- CL 229864 -->
+      <a href="/pkg/crypto/x509/pkix/#Name.String"><code>Name.String</code></a>
+      now prints non-standard attributes from
+      <a href="/pkg/crypto/x509/pkix/#Name.Names"><code>Names</code></a> if
+      <a href="/pkg/crypto/x509/pkix/#Name.ExtraNames"><code>ExtraNames</code></a> is empty.
+    </p>
+  </dd>
+</dl><!-- crypto/x509/pkix -->
+
+<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
+  <dd>
+    <p><!-- CL 191783 -->
+      Decoding a JSON array into a slice no longer reuses any existing slice elements,
+      following the rules that the package documentation already stated.
+    </p>
+
+    <p><!-- CL 199837 -->
+      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.
+    </p>
+  </dd>
+</dl><!-- encoding/json -->
+
 <dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
   <dd>
     <p><!-- CL 203417 -->
-      TODO: <a href="https://golang.org/cl/203417">https://golang.org/cl/203417</a>: fix reserved namespace check to be case-insensitive
+      The encoder has always taken care to avoid using namespace prefixes beginning with
+      <code>xml</code>,
+      which are reserved by the XML specification.
+      Now, following the specification more closely,
+      that check is case-insensitive, so that prefixes beginning with
+      <code>XML</code>, <code>XmL</code>,
+      and so on are also avoided.
     </p>
   </dd>
 </dl><!-- encoding/xml -->
@@ -390,7 +598,8 @@
 <dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
   <dd>
     <p><!-- CL 215001 -->
-      TODO: <a href="https://golang.org/cl/215001">https://golang.org/cl/215001</a>: do not remove trailing zeros for %g and %G with #(sharp) flag
+      The printing verbs <code>%#g</code> and <code>%#G</code> now preserve
+      trailing zeros for floating-point values.
     </p>
   </dd>
 </dl><!-- fmt -->
@@ -410,7 +619,8 @@
 <dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
   <dd>
     <p><!-- CL 230397 -->
-      TODO: <a href="https://golang.org/cl/230397">https://golang.org/cl/230397</a>: add (*Int).FillBytes
+      The new <a href="/pkg/math/big/#Int.FillBytes"><code>Int.FillBytes</code></a>
+      method allows serializing to fixed-size pre-allocated byte slices.
     </p>
   </dd>
 </dl><!-- math/big -->
@@ -441,8 +651,10 @@
 
 <dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
   <dd>
-    <p><!-- CL 231418 -->
-      TODO: <a href="https://golang.org/cl/231418">https://golang.org/cl/231418</a>: only support &#34;chunked&#34; in inbound Transfer-Encoding headers
+    <p><!-- CL 231418, CL 231419 -->
+      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
+      "<code>identity</code>" <code>Transfer-Encoding</code> was dropped.
     </p>
   </dd>
 </dl><!-- net/http -->
@@ -457,7 +669,9 @@
     </p>
 
     <p><!-- CL 224897 -->
-      TODO: <a href="https://golang.org/cl/224897">https://golang.org/cl/224897</a>: make Switching Protocol requests (e.g. Websockets) cancelable
+      When a Switching Protocol (like WebSocket) request handled by
+      <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
+      is canceled, the backend connection is now correctly closed.
     </p>
   </dd>
 </dl>
@@ -506,6 +720,14 @@
       which <code>Timeout</code> returns <code>true</code> although a
       deadline has not been exceeded.
     </p>
+
+    <p><!-- CL 232862 -->
+      Packages <code>os</code> and <code>net</code> now automatically
+      retry system calls that fail with <code>EINTR</code>. 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.
+    </p>
   </dd>
 </dl>
 
@@ -525,7 +747,7 @@
 <dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
   <dd>
     <p><!-- CL 228902 -->
-      Package reflect now disallows accessing methods of all
+      Package <code>reflect</code> 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 @@
 
 <dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
   <dd>
-    <p><!-- CL 221779 -->
-      If <code>panic</code> is invoked with a value whose type is derived from any
-      of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
-      <code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
-      <code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
-      then the value will be printed, instead of just its address.
-      Previously, this was only true for values of exactly these types.
-    </p>
-
-    <p><!-- CL -->
-      On a Unix system, if the <code>kill</code> command
-      or <code>kill</code> system call is used to send
-      a <code>SIGSEGV</code>, <code>SIGBUS</code>,
-      or <code>SIGFPE</code> signal to a Go program, and if the signal
-      is not being handled via
-      <a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
-      the Go program will now reliably crash with a stack trace.
-      In earlier releases the behavior was unpredictable.
-    </p>
-
     <p><!-- CL 216557 -->
       Several functions, including
       <a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
@@ -573,16 +775,6 @@
       <a href="/pkg/runtime/#GoroutineProfile"><code>GoroutineProfile</code></a>,
       no longer block if a garbage collection is in progress.
     </p>
-
-    <p><!-- CL 216401 -->
-      Converting small integer values into an interface value no
-      longer causes allocation.
-    </p>
-
-    <p><!-- CL 216818 -->
-      Non-blocking receives on closed channels now perform as well as
-      non-blocking receives on open channels.
-    </p>
   </dd>
 </dl>
 
diff --git a/src/all.bat b/src/all.bat
index 8bbd6b1..ae835d9 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 0954dcd..c957353 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 22bf137..578d88e 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -73,19 +73,29 @@
 	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 a483c73..56cf51c 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64enc.s
@@ -420,6 +420,7 @@
    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 4366df4..ca18c45 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -990,7 +990,7 @@
 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 f1af647..e372259 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -96,7 +96,7 @@
 			}
 
 			importPath := filepath.Join("cmd/compile", path)
-			if blacklistedPackages[filepath.ToSlash(importPath)] {
+			if ignoredPackages[filepath.ToSlash(importPath)] {
 				return filepath.SkipDir
 			}
 
@@ -344,8 +344,7 @@
 	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 @@
 						// 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 @@
 	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 6f69abf..cb7a7d9 100644
--- a/src/cmd/compile/fmtmap_test.go
+++ b/src/cmd/compile/fmtmap_test.go
@@ -140,6 +140,7 @@
 	"float64 %.3f":                                    "",
 	"float64 %.6g":                                    "",
 	"float64 %g":                                      "",
+	"int %#x":                                         "",
 	"int %-12d":                                       "",
 	"int %-6d":                                        "",
 	"int %-8o":                                        "",
@@ -203,6 +204,7 @@
 	"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 9935616..1da72aa 100644
--- a/src/cmd/compile/internal/arm/ssa.go
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -888,16 +888,30 @@
 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 @@
 		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 @@
 			}
 		}
 
+	case ssa.BlockARMLEnoov:
+		s.CombJump(b, next, &leJumps)
+
+	case ssa.BlockARMGTnoov:
+		s.CombJump(b, next, &gtJumps)
+
 	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 8e781a7..f3e9ab7 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -141,13 +141,13 @@
 	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 2dbe9cf..dbdd027 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -451,6 +451,7 @@
 	{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 @@
 	{"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 6bfd296..3b4f2be 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -223,60 +223,6 @@
 		}
 	}
 
-	// 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 a8cea68..5b3179a 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> 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.Type> x y)) yes no)
+(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL <x.Type> 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 4abe5c9..14407fe 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -584,6 +584,10 @@
 		{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 4a83a46..7f6bf3e 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -61,6 +61,10 @@
 	BlockARMULE
 	BlockARMUGT
 	BlockARMUGE
+	BlockARMLTnoov
+	BlockARMLEnoov
+	BlockARMGTnoov
+	BlockARMGEnoov
 
 	BlockARM64EQ
 	BlockARM64NE
@@ -185,16 +189,20 @@
 	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 5c8dd0f..be5f56a 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -17514,7 +17514,7 @@
 		}
 		// 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 @@
 			}
 			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.Type> x y)) yes no)
+		// result: (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -17556,12 +17556,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 				}
 				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.Type> x y)) yes no)
+		// result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -17773,12 +17773,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			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 @@
 		}
 		// 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 @@
 			}
 			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.Type> x y)) yes no)
+		// result: (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -18410,12 +18419,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 				}
 				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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 		}
 		// match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
 		// cond: l.Uses==1
-		// result: (GT (CMN a (MUL <x.Type> x y)) yes no)
+		// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -18819,7 +18828,7 @@
 			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 @@
 			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 @@
 		}
 		// 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 @@
 			}
 			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.Type> x y)) yes no)
+		// result: (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -19354,12 +19372,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 				}
 				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.Type> x y)) yes no)
+		// result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -19571,12 +19589,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			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 @@
 		}
 		// 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 @@
 			}
 			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.Type> x y)) yes no)
+		// result: (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -20208,12 +20235,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 				}
 				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.Type> x y)) yes no)
+		// result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
 		for b.Controls[0].Op == OpARMCMPconst {
 			v_0 := b.Controls[0]
 			if v_0.AuxInt != 0 {
@@ -20425,12 +20452,12 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			}
 			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 @@
 			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 6536d3a..2c26fdf 100644
--- a/src/cmd/compile/internal/ssa/rewriteCond_test.go
+++ b/src/cmd/compile/internal/ssa/rewriteCond_test.go
@@ -7,24 +7,26 @@
 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 @@
 	{"MAddVar32", testMAddVar32},
 	{"MSubVar64", testMSubVar64},
 	{"MSubVar32", testMSubVar32},
+	{"AddShift32", testAddShift32},
+	{"SubShift32", testSubShift32},
 }
 
 var crBenches = []struct {
@@ -58,9 +62,6 @@
 // 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 @@
 	}
 }
 
+// 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<<uz >= 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 {
+		t.Errorf("'%#x - %#x<<%#x < 0' failed", y32, v32, uz)
+	}
+
+	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 0000000..38deabf
--- /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 08ef056..e1cd496 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -178,15 +178,6 @@
 		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 4c30de4..021930a 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -124,7 +124,6 @@
 		fmt.Printf("SKIP\n")
 		return
 	}
-	os.Unsetenv("GOROOT_FINAL")
 
 	flag.Parse()
 
@@ -180,6 +179,11 @@
 		}
 		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 @@
 		}
 		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 beb80c5..e050980 100644
--- a/src/cmd/go/internal/web/http.go
+++ b/src/cmd/go/internal/web/http.go
@@ -13,6 +13,7 @@
 
 import (
 	"crypto/tls"
+	"errors"
 	"fmt"
 	"mime"
 	"net/http"
@@ -47,6 +48,13 @@
 			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 318d688..f1d08e0 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -168,7 +168,7 @@
 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 8214488..2a4d293 100644
--- a/src/cmd/go/proxy_test.go
+++ b/src/cmd/go/proxy_test.go
@@ -174,6 +174,25 @@
 		return
 	}
 
+	// Request for $GOPROXY/redirect/<count>/... 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/<name>/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 a49a705..2e8f18a 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -130,6 +130,7 @@
 		"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 c7fa7cf..76d6651 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -34,6 +34,7 @@
 	GOPATH=$WORK/gopath
 	GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
 	GOROOT=<actual GOROOT>
+	GOROOT_FINAL=<actual GOROOT_FINAL>
 	TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT>
 	HOME=/no-home
 	PATH=<actual PATH>
diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt
index cfab807..ad78bcf 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 4e04bad..fdbcde0 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 267c90e..ad22aca 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 @@
 ! 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 0000000..9cbe0d2
--- /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 5d73edd..2e61673 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -36,7 +36,7 @@
 			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 7f5cba6..df17729 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -460,7 +460,6 @@
 	{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 @@
 			oprangeset(AVSRI, t)
 
 		case AVREV32:
+			oprangeset(AVCNT, t)
 			oprangeset(AVRBIT, t)
 			oprangeset(AVREV64, t)
 			oprangeset(AVREV16, t)
@@ -4523,7 +4523,7 @@
 			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 2f94ec6..f7873a4 100644
--- a/src/cmd/internal/objabi/util.go
+++ b/src/cmd/internal/objabi/util.go
@@ -134,7 +134,7 @@
 }
 
 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 326f493..ac6937c 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -33,8 +33,8 @@
 		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 9b4214b..f87776e 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -616,15 +616,15 @@
 	}
 	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 c974d67..a9dc7d1 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -138,7 +138,11 @@
 	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 fd21ae8..3a5ca22 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -278,6 +278,8 @@
 	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 40c8e02..46b0a77 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -728,10 +728,17 @@
 		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 @@
 		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 1cda901..12b0254 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -19,6 +19,7 @@
 	"os"
 	"os/exec"
 	"path/filepath"
+	"reflect"
 	"strconv"
 	"strings"
 	"testing"
@@ -2430,3 +2431,83 @@
 		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 35a00f2..9c61105 100644
--- a/src/crypto/tls/handshake_client_tls13.go
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -334,6 +334,8 @@
 	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 @@
 		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 288c9c6..338b488 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -2129,16 +2129,13 @@
 		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 @@
 		return
 	}
 
+	encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
 	c := tbsCertificate{
 		Version:            2,
 		SerialNumber:       template.SerialNumber,
@@ -2154,7 +2152,7 @@
 		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 daef27c..90bb3a9 100644
--- a/src/go/internal/srcimporter/srcimporter.go
+++ b/src/go/internal/srcimporter/srcimporter.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"strings"
 	"sync"
+	_ "unsafe" // for go:linkname
 )
 
 // An Importer provides the context for importing packages from source code.
@@ -133,7 +134,7 @@
 			// 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 @@
 	}
 	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 7787b88..1abcd9d 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -105,14 +105,14 @@
 	//          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 @@
 	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 a94770f..007babd 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -248,10 +248,10 @@
 // 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 f80b4ec..078adc5 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -141,10 +141,10 @@
 	}
 
 	// 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 13a0cd0..356b829 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -240,8 +240,7 @@
 	}
 	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 85c79bb..4872fa9 100644
--- a/src/internal/poll/fd_unix.go
+++ b/src/internal/poll/fd_unix.go
@@ -479,7 +479,7 @@
 	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 f7955ec..277a34d 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 e924e2a..fe6b609 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -503,7 +503,7 @@
 
 // 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 b613c21..a995a50 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -1698,9 +1698,9 @@
 	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 b93e2bd..f2c00ae 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -202,10 +202,8 @@
 			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 e619851..37bf1b8 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -9,7 +9,6 @@
 import (
 	"internal/syscall/unix"
 	"io"
-	"runtime"
 	"syscall"
 )
 
@@ -178,7 +177,7 @@
 		}
 
 		// 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 fb3ee1e..f8813ce 100644
--- a/src/os/signal/internal/pty/pty.go
+++ b/src/os/signal/internal/pty/pty.go
@@ -40,8 +40,8 @@
 
 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 @@
 		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 849a96e..a117221 100644
--- a/src/os/signal/signal_cgo_test.go
+++ b/src/os/signal/signal_cgo_test.go
@@ -19,7 +19,7 @@
 	"io"
 	"os"
 	"os/exec"
-	"os/signal/internal/pty"
+	ptypkg "os/signal/internal/pty"
 	"strconv"
 	"strings"
 	"sync"
@@ -71,20 +71,20 @@
 	// 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 @@
 	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 @@
 		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 @@
 				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 @@
 	}()
 
 	// 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 @@
 
 	// 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 @@
 	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 @@
 	}
 
 	// 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 @@
 
 	// 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 @@
 	}
 
 	// 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 d26f318..8f03556 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 69c1818..c299671 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 bc5e078..de634dc 100644
--- a/src/runtime/cgo_sigaction.go
+++ b/src/runtime/cgo_sigaction.go
@@ -18,12 +18,12 @@
 //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 5cbe382..6c285ec 100644
--- a/src/runtime/debugcall.go
+++ b/src/runtime/debugcall.go
@@ -61,7 +61,7 @@
 			"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 77a5a38..eaf8db7 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -976,6 +976,7 @@
 			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 @@
 				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 @@
 			}
 			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 @@
 			}
 		}
 	} 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 @@
 	// 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 dafb463..fe988c4 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -1627,11 +1627,21 @@
 //
 //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 ba50872..6a8a34d 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -529,7 +529,7 @@
 
 	// 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 f444452..632769c 100644
--- a/src/runtime/mwbbuf.go
+++ b/src/runtime/mwbbuf.go
@@ -296,6 +296,13 @@
 			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 ce2ec6d..1e86662 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -563,8 +563,8 @@
 // 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 eb2f331..9080857 100644
--- a/test/codegen/comparisons.go
+++ b/test/codegen/comparisons.go
@@ -253,6 +253,8 @@
 // '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 @@
 		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 @@
 	}
 
 	// 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 @@
 	}
 
 	// 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 @@
 	}
 	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 0000000..61444a2
--- /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 30e0e3c..c3b48d3 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 @@
 	"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)
 	}
 }