aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--build.bat1
-rw-r--r--go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch2
-rw-r--r--go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch2
-rw-r--r--go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch2
-rw-r--r--go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch2
-rw-r--r--go-patches/0005-cmd-link-handle-grouped-resource-sections.patch2
-rw-r--r--go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch2
-rw-r--r--go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch2
-rw-r--r--go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch2
-rw-r--r--go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch2
-rw-r--r--go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch2
-rw-r--r--go-patches/0011-cmd-link-windows-arm-is-all-pie-so-mark-it-as-such.patch2
-rw-r--r--go-patches/0012-runtime-adjust-address-calculation-in-identifying-ab.patch2
-rw-r--r--go-patches/0013-cmd-compile-do-not-assume-TST-and-TEQ-set-V-on-arm.patch1275
15 files changed, 1289 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index e626cf85..d6665a14 100644
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@ $(eval $(call download,wintun.zip,https://www.wintun.net/builds/wintun-0.9.2.zip
tar -C .deps -xzf .distfiles/go.tar.gz
chmod -R +w .deps/go
cat $(filter %.patch,$^) | patch -f -N -r- -p1 -d .deps/go
+ cd .deps/go/src && GOARCH=amd64 GOOS=linux go build -v -o ../pkg/tool/linux_amd64/compile cmd/compile
cd .deps/go/src && GOARCH=amd64 GOOS=linux go build -v -o ../pkg/tool/linux_amd64/link cmd/link
touch $@
diff --git a/build.bat b/build.bat
index ae960de0..f1e3d0b5 100644
--- a/build.bat
+++ b/build.bat
@@ -27,6 +27,7 @@ if exist .deps\prepared goto :render
echo [+] Patching go
for %%a in ("..\go-patches\*.patch") do .\patch.exe -f -N -r- -d go -p1 --binary < "%%a" || goto :error
cd go\src || goto :error
+ ..\bin\go build -v -o ..\pkg\tool\windows_amd64\compile.exe cmd/compile || goto :error
..\bin\go build -v -o ..\pkg\tool\windows_amd64\link.exe cmd/link || goto :error
cd ..\.. || goto :error
copy /y NUL prepared > NUL || goto :error
diff --git a/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
index ae337f18..514103e7 100644
--- a/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
+++ b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch
@@ -1,7 +1,7 @@
From fde4a13eb5eba28ac546b10752b38a80f389cc5a Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 02:48:09 +0100
-Subject: [PATCH 01/12] cmd/link: recognize arm header of PE objects
+Subject: [PATCH 01/13] cmd/link: recognize arm header of PE objects
The linker recognizes headers for 386 and amd64 PE objects, but not arm
objects. This is easily overlooked, since its the same as the 386 header
diff --git a/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
index 3bdaa2f4..9c4bf226 100644
--- a/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
+++ b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch
@@ -1,7 +1,7 @@
From a0a59fc25f4d8aef3c7bce38c84f04c504745f0e Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 03:09:42 +0100
-Subject: [PATCH 02/12] cmd/link: deal with ADDR32NB relocations the same way
+Subject: [PATCH 02/13] cmd/link: deal with ADDR32NB relocations the same way
as ADDR32 on arm
As far as I can tell, the addend is the same for both of these, and in
diff --git a/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
index 60fed7f8..02d5ff31 100644
--- a/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
+++ b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch
@@ -1,7 +1,7 @@
From e8142ab5e3b3a513683a8e3792e6197644547981 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 03:20:36 +0100
-Subject: [PATCH 03/12] cmd/link: ignore SEH marking on PE objects
+Subject: [PATCH 03/13] cmd/link: ignore SEH marking on PE objects
Microsoft's linker looks at whether all input objects have an empty
section called @feat.00. If all of them do, then it enables SEH;
diff --git a/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
index 722283df..cb1f82a3 100644
--- a/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
+++ b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch
@@ -1,7 +1,7 @@
From 8255e115f325a58fd4746741f9f35c2f54d70d63 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 11:11:27 +0100
-Subject: [PATCH 04/12] cmd/link: do not mark resource section as writable
+Subject: [PATCH 04/13] cmd/link: do not mark resource section as writable
Resources are immutable, and all other linkers set this section to be
read-only and not read-write. Fix this oversight by rmoving the writable
diff --git a/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
index b0de26fb..9e11d775 100644
--- a/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
+++ b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch
@@ -1,7 +1,7 @@
From 5d5d74f35dd3375cda8ef2ba8257547aad107ecb Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 8 Nov 2020 11:57:42 +0100
-Subject: [PATCH 05/12] cmd/link: handle grouped resource sections
+Subject: [PATCH 05/13] cmd/link: handle grouped resource sections
The Go PE linker does not support enough generalized PE logic to
properly handle .rsrc sections gracefully. Instead a few things are
diff --git a/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch b/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
index 635d3553..3cb0bdd2 100644
--- a/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
+++ b/go-patches/0006-Revert-release-branch.go1.15-runtime-detect-services.patch
@@ -1,7 +1,7 @@
From e6b4c1b3beb4f843ed40abead27c8132d29a0db8 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 11 Sep 2020 13:04:11 +0200
-Subject: [PATCH 06/12] Revert "[release-branch.go1.15] runtime: detect
+Subject: [PATCH 06/13] Revert "[release-branch.go1.15] runtime: detect
services in signal handler"
This reverts commit b1253d24e159129c778377c3a2a0bde15904a417.
diff --git a/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch b/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
index e1c35658..8479c1cc 100644
--- a/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
+++ b/go-patches/0007-runtime-do-not-explicitly-exit-on-ctrl-handler.patch
@@ -1,7 +1,7 @@
From af4eb34d920c0c727041ebf587e0de608068ed59 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 14 Jul 2020 01:41:03 -0600
-Subject: [PATCH 07/12] runtime: do not explicitly exit on ctrl handler
+Subject: [PATCH 07/13] runtime: do not explicitly exit on ctrl handler
The default ctrl+c handler should process exits in situations where it
makes sense, like console apps, but not in situations where it doesn't,
diff --git a/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch b/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
index 0ef3f508..186610ae 100644
--- a/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
+++ b/go-patches/0008-runtime-allow-callback-functions-with-up-to-8-argume.patch
@@ -1,7 +1,7 @@
From 5a7c808cbacb8c0477395c5656c1eba3ef38cd6e Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 10 Nov 2020 21:42:36 +0100
-Subject: [PATCH 08/12] runtime: allow callback functions with up to 8
+Subject: [PATCH 08/13] runtime: allow callback functions with up to 8
arguments on windows/arm
Previously, windows/arm programs would abort when trying to use
diff --git a/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch b/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch
index 55e11376..90604341 100644
--- a/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch
+++ b/go-patches/0009-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch
@@ -1,7 +1,7 @@
From 1a163f2e676e4664f2db3f614eb4168bda9d4fd8 Mon Sep 17 00:00:00 2001
From: Alex Brainman <alex.brainman@gmail.com>
Date: Sun, 19 Jul 2020 16:06:48 +1000
-Subject: [PATCH 09/12] runtime: use CreateWaitableTimerEx to implement usleep
+Subject: [PATCH 09/13] runtime: use CreateWaitableTimerEx to implement usleep
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
diff --git a/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch b/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch
index 66397a53..3fe6935e 100644
--- a/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch
+++ b/go-patches/0010-runtime-allow-for-usleep2HighRes-to-run-without-TLS-.patch
@@ -1,7 +1,7 @@
From 1edac4879e2d4a36d339353c151cb7b9871e135f Mon Sep 17 00:00:00 2001
From: Alex Brainman <alex.brainman@gmail.com>
Date: Sat, 21 Nov 2020 14:56:26 +1100
-Subject: [PATCH 10/12] runtime: allow for usleep2HighRes to run without TLS
+Subject: [PATCH 10/13] runtime: allow for usleep2HighRes to run without TLS
setup
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
diff --git a/go-patches/0011-cmd-link-windows-arm-is-all-pie-so-mark-it-as-such.patch b/go-patches/0011-cmd-link-windows-arm-is-all-pie-so-mark-it-as-such.patch
index b1ed0b30..72cbb000 100644
--- a/go-patches/0011-cmd-link-windows-arm-is-all-pie-so-mark-it-as-such.patch
+++ b/go-patches/0011-cmd-link-windows-arm-is-all-pie-so-mark-it-as-such.patch
@@ -1,7 +1,7 @@
From fee7906e1a7e62b655bea0f25c921572ee29fc44 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 26 Nov 2020 22:38:45 +0100
-Subject: [PATCH 11/12] cmd/link: windows/arm is all pie, so mark it as such
+Subject: [PATCH 11/13] cmd/link: windows/arm is all pie, so mark it as such
If the linker thinks that it's making an exe instead of a pie object, it
won't apply relocations to the pclntab and we wind up with crashes like:
diff --git a/go-patches/0012-runtime-adjust-address-calculation-in-identifying-ab.patch b/go-patches/0012-runtime-adjust-address-calculation-in-identifying-ab.patch
index f0e60ad6..2f3954db 100644
--- a/go-patches/0012-runtime-adjust-address-calculation-in-identifying-ab.patch
+++ b/go-patches/0012-runtime-adjust-address-calculation-in-identifying-ab.patch
@@ -1,7 +1,7 @@
From 8ec41fee1e6ef074ef74e56fe079c70c8a1d0548 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 27 Nov 2020 22:07:23 +0100
-Subject: [PATCH 12/12] runtime: adjust address calculation in identifying
+Subject: [PATCH 12/13] runtime: adjust address calculation in identifying
abort on windows/arm
Apparently we're being called on arm 1 byte off, just like on 386 and
diff --git a/go-patches/0013-cmd-compile-do-not-assume-TST-and-TEQ-set-V-on-arm.patch b/go-patches/0013-cmd-compile-do-not-assume-TST-and-TEQ-set-V-on-arm.patch
new file mode 100644
index 00000000..296ca4a2
--- /dev/null
+++ b/go-patches/0013-cmd-compile-do-not-assume-TST-and-TEQ-set-V-on-arm.patch
@@ -0,0 +1,1275 @@
+From 58e426bb8175959d7bf32ea7c87e51f4706b309b Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 30 Nov 2020 10:41:46 +0100
+Subject: [PATCH 13/13] cmd/compile: do not assume TST and TEQ set V on arm
+
+These replacement rules assume that TST and TEQ set V. But TST and
+TEQ do not set V. This is a problem because instructions like LT are
+actually checking for N!=V. But with TST and TEQ not setting V, LT
+doesn't do anything meaningful. It's possible to construct trivial
+miscompilations from this, such as:
+
+ package main
+
+ var x = [4]int32{-0x7fffffff, 0x7fffffff, 2, 4}
+
+ func main() {
+ if x[0] > x[1] {
+ panic("fail 1")
+ }
+ if x[2]&x[3] < 0 {
+ panic("fail 2") // Fails here
+ }
+ }
+
+That first comparison sets V, via the CMP that subtracts the values
+causing the overflow. Then the second comparison operation thinks that
+it uses the result of TST, when it actually uses the V from CMP.
+
+Before this fix:
+
+ TST R0, R1
+ BLT loc_6C164
+
+After this fix:
+
+ TST R0, R1
+ BMI loc_6C164
+
+The BMI instruction checks the N flag, which TST sets. This commit
+fixes the issue by using [LG][TE]noov instead of vanilla [LG][TE], and
+also adds a test case for the direct issue.
+
+Fixes #42876.
+
+Change-Id: I13c62c88d18574247ad002b671b38d2d0b0fc6fa
+Reviewed-on: https://go-review.googlesource.com/c/go/+/274026
+Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
+TryBot-Result: Go Bot <gobot@golang.org>
+Reviewed-by: Cherry Zhang <cherryyz@google.com>
+Trust: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ src/cmd/compile/internal/ssa/gen/ARM.rules | 128 ++++-----
+ src/cmd/compile/internal/ssa/rewriteARM.go | 306 ++++++++++-----------
+ test/fixedbugs/issue42876.go | 18 ++
+ 3 files changed, 235 insertions(+), 217 deletions(-)
+ create mode 100644 test/fixedbugs/issue42876.go
+
+diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
+index ab8bd0e81e..c69084a701 100644
+--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
++++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
+@@ -1369,38 +1369,38 @@
+ (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)
+-(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftRL x y [c]) yes no)
+-(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftRA x y [c]) yes no)
+-(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftLLreg x y z) yes no)
+-(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftRLreg x y z) yes no)
+-(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftRAreg x y z) yes no)
+-(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LE (TST x y) yes no)
+-(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LE (TSTconst [c] x) yes no)
+-(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftLL x y [c]) yes no)
+-(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftRL x y [c]) yes no)
+-(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftRA x y [c]) yes no)
+-(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftLLreg x y z) yes no)
+-(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftRLreg x y z) yes no)
+-(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftRAreg x y z) yes no)
+-(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LT (TEQ x y) yes no)
+-(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LT (TEQconst [c] x) yes no)
+-(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftLL x y [c]) yes no)
+-(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftRL x y [c]) yes no)
+-(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftRA x y [c]) yes no)
+-(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftLLreg x y z) yes no)
+-(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftRLreg x y z) yes no)
+-(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftRAreg x y z) yes no)
+-(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LE (TEQ x y) yes no)
+-(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LE (TEQconst [c] x) yes no)
+-(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftLL x y [c]) yes no)
+-(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftRL x y [c]) yes no)
+-(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftRA x y [c]) yes no)
+-(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)
++(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LTnoov (TST x y) yes no)
++(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (TSTconst [c] x) yes no)
++(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (TSTshiftLL x y [c]) yes no)
++(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (TSTshiftRL x y [c]) yes no)
++(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (TSTshiftRA x y [c]) yes no)
++(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TSTshiftLLreg x y z) yes no)
++(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TSTshiftRLreg x y z) yes no)
++(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TSTshiftRAreg x y z) yes no)
++(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LEnoov (TST x y) yes no)
++(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (TSTconst [c] x) yes no)
++(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (TSTshiftLL x y [c]) yes no)
++(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (TSTshiftRL x y [c]) yes no)
++(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (TSTshiftRA x y [c]) yes no)
++(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TSTshiftLLreg x y z) yes no)
++(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TSTshiftRLreg x y z) yes no)
++(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TSTshiftRAreg x y z) yes no)
++(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LTnoov (TEQ x y) yes no)
++(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (TEQconst [c] x) yes no)
++(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (TEQshiftLL x y [c]) yes no)
++(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (TEQshiftRL x y [c]) yes no)
++(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (TEQshiftRA x y [c]) yes no)
++(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TEQshiftLLreg x y z) yes no)
++(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TEQshiftRLreg x y z) yes no)
++(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (TEQshiftRAreg x y z) yes no)
++(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LEnoov (TEQ x y) yes no)
++(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (TEQconst [c] x) yes no)
++(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (TEQshiftLL x y [c]) yes no)
++(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (TEQshiftRL x y [c]) yes no)
++(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (TEQshiftRA x y [c]) yes no)
++(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TEQshiftLLreg x y z) yes no)
++(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TEQshiftRLreg x y z) yes no)
++(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (TEQshiftRAreg 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)
+@@ -1436,39 +1436,39 @@
+ (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 -> (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)
+-(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRA x y [c]) yes no)
+-(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftLLreg x y z) yes no)
+-(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftRLreg x y z) yes no)
+-(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftRAreg x y z) yes no)
+-(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GE (TST x y) yes no)
+-(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GE (TSTconst [c] x) yes no)
+-(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftLL x y [c]) yes no)
+-(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftRL x y [c]) yes no)
+-(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftRA x y [c]) yes no)
+-(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftLLreg x y z) yes no)
+-(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftRLreg x y z) yes no)
+-(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftRAreg x y z) yes no)
+-(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GT (TEQ x y) yes no)
+-(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GT (TEQconst [c] x) yes no)
+-(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftLL x y [c]) yes no)
+-(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftRL x y [c]) yes no)
+-(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftRA x y [c]) yes no)
+-(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftLLreg x y z) yes no)
+-(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftRLreg x y z) yes no)
+-(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftRAreg x y z) yes no)
+-(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GE (TEQ x y) yes no)
+-(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GE (TEQconst [c] x) yes no)
+-(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftLL x y [c]) yes no)
+-(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftRL x y [c]) yes no)
+-(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftRA x y [c]) yes no)
+-(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftLLreg x y z) yes no)
+-(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRLreg x y z) yes no)
+-(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRAreg x y z) yes no)
++(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GTnoov (TST x y) yes no)
++(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (TSTconst [c] x) yes no)
++(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (TSTshiftLL x y [c]) yes no)
++(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (TSTshiftRL x y [c]) yes no)
++(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (TSTshiftRA x y [c]) yes no)
++(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TSTshiftLLreg x y z) yes no)
++(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TSTshiftRLreg x y z) yes no)
++(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TSTshiftRAreg x y z) yes no)
++(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GEnoov (TST x y) yes no)
++(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (TSTconst [c] x) yes no)
++(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (TSTshiftLL x y [c]) yes no)
++(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (TSTshiftRL x y [c]) yes no)
++(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (TSTshiftRA x y [c]) yes no)
++(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TSTshiftLLreg x y z) yes no)
++(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TSTshiftRLreg x y z) yes no)
++(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TSTshiftRAreg x y z) yes no)
++(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GTnoov (TEQ x y) yes no)
++(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (TEQconst [c] x) yes no)
++(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (TEQshiftLL x y [c]) yes no)
++(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (TEQshiftRL x y [c]) yes no)
++(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (TEQshiftRA x y [c]) yes no)
++(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TEQshiftLLreg x y z) yes no)
++(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TEQshiftRLreg x y z) yes no)
++(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (TEQshiftRAreg x y z) yes no)
++(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GEnoov (TEQ x y) yes no)
++(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (TEQconst [c] x) yes no)
++(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (TEQshiftLL x y [c]) yes no)
++(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (TEQshiftRL x y [c]) yes no)
++(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (TEQshiftRA x y [c]) yes no)
++(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TEQshiftLLreg x y z) yes no)
++(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TEQshiftRLreg x y z) yes no)
++(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (TEQshiftRAreg x y z) yes no)
+
+ (MOVBUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read8(sym, off))])
+ (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read16(sym, off, config.ctxt.Arch.ByteOrder))])
+diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
+index f55e542505..07653b78f8 100644
+--- a/src/cmd/compile/internal/ssa/rewriteARM.go
++++ b/src/cmd/compile/internal/ssa/rewriteARM.go
+@@ -17278,7 +17278,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ // match: (GE (CMPconst [0] l:(AND x y)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TST x y) yes no)
++ // result: (GEnoov (TST x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17299,14 +17299,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTconst [c] x) yes no)
++ // result: (GEnoov (TSTconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17324,12 +17324,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftLL x y [c]) yes no)
++ // result: (GEnoov (TSTshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17348,12 +17348,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftRL x y [c]) yes no)
++ // result: (GEnoov (TSTshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17372,12 +17372,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftRA x y [c]) yes no)
++ // result: (GEnoov (TSTshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17396,12 +17396,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftLLreg x y z) yes no)
++ // result: (GEnoov (TSTshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17419,12 +17419,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftRLreg x y z) yes no)
++ // result: (GEnoov (TSTshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17442,12 +17442,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TSTshiftRAreg x y z) yes no)
++ // result: (GEnoov (TSTshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17465,12 +17465,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XOR x y)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQ x y) yes no)
++ // result: (GEnoov (TEQ x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17491,14 +17491,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQconst [c] x) yes no)
++ // result: (GEnoov (TEQconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17516,12 +17516,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftLL x y [c]) yes no)
++ // result: (GEnoov (TEQshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17540,12 +17540,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftRL x y [c]) yes no)
++ // result: (GEnoov (TEQshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17564,12 +17564,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftRA x y [c]) yes no)
++ // result: (GEnoov (TEQshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17588,12 +17588,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftLLreg x y z) yes no)
++ // result: (GEnoov (TEQshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17611,12 +17611,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftRLreg x y z) yes no)
++ // result: (GEnoov (TEQshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17634,12 +17634,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ // match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GE (TEQshiftRAreg x y z) yes no)
++ // result: (GEnoov (TEQshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -17657,7 +17657,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGE, v0)
++ b.resetWithControl(BlockARMGEnoov, v0)
+ return true
+ }
+ case BlockARMGEnoov:
+@@ -18131,9 +18131,34 @@ func rewriteBlockARM(b *Block) bool {
+ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
++ // match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
++ // cond: l.Uses==1
++ // 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 {
++ break
++ }
++ l := v_0.Args[0]
++ if l.Op != OpARMMULA {
++ break
++ }
++ a := l.Args[2]
++ x := l.Args[0]
++ y := l.Args[1]
++ if !(l.Uses == 1) {
++ break
++ }
++ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
++ v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
++ v1.AddArg2(x, y)
++ v0.AddArg2(a, v1)
++ b.resetWithControl(BlockARMGTnoov, v0)
++ return true
++ }
+ // match: (GT (CMPconst [0] l:(AND x y)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TST x y) yes no)
++ // result: (GTnoov (TST x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18154,39 +18179,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ break
+ }
+- // match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
+- // cond: l.Uses==1
+- // 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 {
+- break
+- }
+- l := v_0.Args[0]
+- if l.Op != OpARMMULA {
+- break
+- }
+- a := l.Args[2]
+- x := l.Args[0]
+- y := l.Args[1]
+- if !(l.Uses == 1) {
+- break
+- }
+- v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+- v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
+- v1.AddArg2(x, y)
+- v0.AddArg2(a, v1)
+- b.resetWithControl(BlockARMGTnoov, v0)
+- return true
+- }
+ // match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTconst [c] x) yes no)
++ // result: (GTnoov (TSTconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18204,12 +18204,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftLL x y [c]) yes no)
++ // result: (GTnoov (TSTshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18228,12 +18228,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftRL x y [c]) yes no)
++ // result: (GTnoov (TSTshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18252,12 +18252,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftRA x y [c]) yes no)
++ // result: (GTnoov (TSTshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18276,12 +18276,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftLLreg x y z) yes no)
++ // result: (GTnoov (TSTshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18299,12 +18299,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftRLreg x y z) yes no)
++ // result: (GTnoov (TSTshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18322,12 +18322,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TSTshiftRAreg x y z) yes no)
++ // result: (GTnoov (TSTshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18345,12 +18345,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XOR x y)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQ x y) yes no)
++ // result: (GTnoov (TEQ x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18371,14 +18371,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQconst [c] x) yes no)
++ // result: (GTnoov (TEQconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18396,12 +18396,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftLL x y [c]) yes no)
++ // result: (GTnoov (TEQshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18420,12 +18420,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftRL x y [c]) yes no)
++ // result: (GTnoov (TEQshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18444,12 +18444,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftRA x y [c]) yes no)
++ // result: (GTnoov (TEQshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18468,12 +18468,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftLLreg x y z) yes no)
++ // result: (GTnoov (TEQshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18491,12 +18491,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftRLreg x y z) yes no)
++ // result: (GTnoov (TEQshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18514,12 +18514,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ // match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (GT (TEQshiftRAreg x y z) yes no)
++ // result: (GTnoov (TEQshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -18537,7 +18537,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMGT, v0)
++ b.resetWithControl(BlockARMGTnoov, v0)
+ return true
+ }
+ case BlockARMGTnoov:
+@@ -19129,7 +19129,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ // match: (LE (CMPconst [0] l:(AND x y)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TST x y) yes no)
++ // result: (LEnoov (TST x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19150,14 +19150,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTconst [c] x) yes no)
++ // result: (LEnoov (TSTconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19175,12 +19175,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftLL x y [c]) yes no)
++ // result: (LEnoov (TSTshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19199,12 +19199,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftRL x y [c]) yes no)
++ // result: (LEnoov (TSTshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19223,12 +19223,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftRA x y [c]) yes no)
++ // result: (LEnoov (TSTshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19247,12 +19247,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftLLreg x y z) yes no)
++ // result: (LEnoov (TSTshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19270,12 +19270,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftRLreg x y z) yes no)
++ // result: (LEnoov (TSTshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19293,12 +19293,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TSTshiftRAreg x y z) yes no)
++ // result: (LEnoov (TSTshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19316,12 +19316,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XOR x y)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQ x y) yes no)
++ // result: (LEnoov (TEQ x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19342,14 +19342,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQconst [c] x) yes no)
++ // result: (LEnoov (TEQconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19367,12 +19367,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftLL x y [c]) yes no)
++ // result: (LEnoov (TEQshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19391,12 +19391,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftRL x y [c]) yes no)
++ // result: (LEnoov (TEQshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19415,12 +19415,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftRA x y [c]) yes no)
++ // result: (LEnoov (TEQshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19439,12 +19439,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftLLreg x y z) yes no)
++ // result: (LEnoov (TEQshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19462,12 +19462,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftRLreg x y z) yes no)
++ // result: (LEnoov (TEQshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19485,12 +19485,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ // match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LE (TEQshiftRAreg x y z) yes no)
++ // result: (LEnoov (TEQshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -19508,7 +19508,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLE, v0)
++ b.resetWithControl(BlockARMLEnoov, v0)
+ return true
+ }
+ case BlockARMLEnoov:
+@@ -20009,7 +20009,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ // match: (LT (CMPconst [0] l:(AND x y)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TST x y) yes no)
++ // result: (LTnoov (TST x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20030,14 +20030,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTconst [c] x) yes no)
++ // result: (LTnoov (TSTconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20055,12 +20055,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftLL x y [c]) yes no)
++ // result: (LTnoov (TSTshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20079,12 +20079,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftRL x y [c]) yes no)
++ // result: (LTnoov (TSTshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20103,12 +20103,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftRA x y [c]) yes no)
++ // result: (LTnoov (TSTshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20127,12 +20127,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftLLreg x y z) yes no)
++ // result: (LTnoov (TSTshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20150,12 +20150,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftRLreg x y z) yes no)
++ // result: (LTnoov (TSTshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20173,12 +20173,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TSTshiftRAreg x y z) yes no)
++ // result: (LTnoov (TSTshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20196,12 +20196,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XOR x y)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQ x y) yes no)
++ // result: (LTnoov (TEQ x y) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20222,14 +20222,14 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags)
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ break
+ }
+ // match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQconst [c] x) yes no)
++ // result: (LTnoov (TEQconst [c] x) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20247,12 +20247,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftLL x y [c]) yes no)
++ // result: (LTnoov (TEQshiftLL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20271,12 +20271,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftRL x y [c]) yes no)
++ // result: (LTnoov (TEQshiftRL x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20295,12 +20295,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftRA x y [c]) yes no)
++ // result: (LTnoov (TEQshiftRA x y [c]) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20319,12 +20319,12 @@ func rewriteBlockARM(b *Block) bool {
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg2(x, y)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftLLreg x y z) yes no)
++ // result: (LTnoov (TEQshiftLLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20342,12 +20342,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftRLreg x y z) yes no)
++ // result: (LTnoov (TEQshiftRLreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20365,12 +20365,12 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ // match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no)
+ // cond: l.Uses==1
+- // result: (LT (TEQshiftRAreg x y z) yes no)
++ // result: (LTnoov (TEQshiftRAreg x y z) yes no)
+ for b.Controls[0].Op == OpARMCMPconst {
+ v_0 := b.Controls[0]
+ if v_0.AuxInt != 0 {
+@@ -20388,7 +20388,7 @@ func rewriteBlockARM(b *Block) bool {
+ }
+ v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags)
+ v0.AddArg3(x, y, z)
+- b.resetWithControl(BlockARMLT, v0)
++ b.resetWithControl(BlockARMLTnoov, v0)
+ return true
+ }
+ case BlockARMLTnoov:
+diff --git a/test/fixedbugs/issue42876.go b/test/fixedbugs/issue42876.go
+new file mode 100644
+index 0000000000..67cf4919ac
+--- /dev/null
++++ b/test/fixedbugs/issue42876.go
+@@ -0,0 +1,18 @@
++// run
++
++// Copyright 2020 The Go Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++package main
++
++var x = [4]int32{-0x7fffffff, 0x7fffffff, 2, 4}
++
++func main() {
++ if x[0] > x[1] {
++ panic("fail 1")
++ }
++ if x[2]&x[3] < 0 {
++ panic("fail 2") // Fails here
++ }
++}
+--
+2.29.2
+