From 023c46676db26e75d244b1d38ccc4a4b8bfe3eef Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 14 Feb 2021 17:14:41 -0800 Subject: [release-branch.go1.15] internal/poll: if copy_file_range returns 0, assume it failed On current Linux kernels copy_file_range does not correctly handle files in certain special file systems, such as /proc. For those file systems it fails to copy any data and returns zero. This breaks Go's io.Copy for those files. Fix the problem by assuming that if copy_file_range returns 0 the first time it is called on a file, that that file is not supported. In that case fall back to just using read. This will force an extra system call when using io.Copy to copy a zero-sized normal file, but at least it will work correctly. For #36817 For #44272 Fixes #44273 Change-Id: I02e81872cb70fda0ce5485e2ea712f219132e614 Reviewed-on: https://go-review.googlesource.com/c/go/+/291989 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Russ Cox (cherry picked from commit 30641e36aa5b547eee48565caa3078b0a2e7c185) Reviewed-on: https://go-review.googlesource.com/c/go/+/292289 --- src/internal/poll/copy_file_range_linux.go | 10 +++++++++- src/os/readfrom_linux_test.go | 32 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go index fc34aef4cb..01b242a4ea 100644 --- a/src/internal/poll/copy_file_range_linux.go +++ b/src/internal/poll/copy_file_range_linux.go @@ -112,7 +112,15 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err return 0, false, nil case nil: if n == 0 { - // src is at EOF, which means we are done. + // If we did not read any bytes at all, + // then this file may be in a file system + // where copy_file_range silently fails. + // https://lore.kernel.org/linux-fsdevel/20210126233840.GG4626@dread.disaster.area/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0 + if written == 0 { + return 0, false, nil + } + // Otherwise src is at EOF, which means + // we are done. return written, true, nil } remain -= n diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go index 00faf39fe5..aa3f050667 100644 --- a/src/os/readfrom_linux_test.go +++ b/src/os/readfrom_linux_test.go @@ -361,3 +361,35 @@ func (h *copyFileRangeHook) install() { func (h *copyFileRangeHook) uninstall() { *PollCopyFileRangeP = h.original } + +// On some kernels copy_file_range fails on files in /proc. +func TestProcCopy(t *testing.T) { + const cmdlineFile = "/proc/self/cmdline" + cmdline, err := ioutil.ReadFile(cmdlineFile) + if err != nil { + t.Skipf("can't read /proc file: %v", err) + } + in, err := Open(cmdlineFile) + if err != nil { + t.Fatal(err) + } + defer in.Close() + outFile := filepath.Join(t.TempDir(), "cmdline") + out, err := Create(outFile) + if err != nil { + t.Fatal(err) + } + if _, err := io.Copy(out, in); err != nil { + t.Fatal(err) + } + if err := out.Close(); err != nil { + t.Fatal(err) + } + copy, err := ioutil.ReadFile(outFile) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(cmdline, copy) { + t.Errorf("copy of %q got %q want %q\n", cmdlineFile, copy, cmdline) + } +} -- cgit v1.2.3-54-g00ecf From 30357d6ef6513b18fade686a629ab8d49987260f Mon Sep 17 00:00:00 2001 From: Wei Fu Date: Sun, 24 Jan 2021 18:21:06 +0800 Subject: [release-branch.go1.15] internal/poll: netpollcheckerr before sendfile In net/http package, the ServeContent/ServeFile doesn't check the I/O timeout error from chunkWriter or *net.TCPConn, which means that both HTTP status and headers might be missing when WriteTimeout happens. If the poll.SendFile() doesn't check the *poll.FD state before sending data, the client will only receive the response body with status and report "malformed http response/status code". This patch is to enable netpollcheckerr before sendfile, which should align with normal *poll.FD.Write() and Splice(). For #43822 Fixes #44294 Change-Id: I32517e3f261bab883a58b577b813ef189214b954 Reviewed-on: https://go-review.googlesource.com/c/go/+/285914 Reviewed-by: Emmanuel Odeke Trust: Emmanuel Odeke Trust: Bryan C. Mills Run-TryBot: Emmanuel Odeke (cherry picked from commit f0d23c9dbb2142b975fa8fb13a57213d0c15bdd1) Reviewed-on: https://go-review.googlesource.com/c/go/+/296530 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot --- src/internal/poll/sendfile_bsd.go | 4 +++ src/internal/poll/sendfile_linux.go | 3 ++ src/internal/poll/sendfile_solaris.go | 3 ++ src/net/sendfile_test.go | 64 +++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go index a24e41dcaa..66005a9f5c 100644 --- a/src/internal/poll/sendfile_bsd.go +++ b/src/internal/poll/sendfile_bsd.go @@ -18,6 +18,10 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } + dst := int(dstFD.Sysfd) var written int64 var err error diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go index d64283007d..d6442e8666 100644 --- a/src/internal/poll/sendfile_linux.go +++ b/src/internal/poll/sendfile_linux.go @@ -16,6 +16,9 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } dst := int(dstFD.Sysfd) var written int64 diff --git a/src/internal/poll/sendfile_solaris.go b/src/internal/poll/sendfile_solaris.go index 762992e9eb..748c85131e 100644 --- a/src/internal/poll/sendfile_solaris.go +++ b/src/internal/poll/sendfile_solaris.go @@ -20,6 +20,9 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } dst := int(dstFD.Sysfd) var written int64 diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index 13842a1261..0e344b3649 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -10,6 +10,7 @@ import ( "bytes" "crypto/sha256" "encoding/hex" + "errors" "fmt" "io" "io/ioutil" @@ -314,3 +315,66 @@ func TestSendfilePipe(t *testing.T) { wg.Wait() } + +// Issue 43822: tests that returns EOF when conn write timeout. +func TestSendfileOnWriteTimeoutExceeded(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + errc := make(chan error, 1) + go func(ln Listener) (retErr error) { + defer func() { + errc <- retErr + close(errc) + }() + + conn, err := ln.Accept() + if err != nil { + return err + } + defer conn.Close() + + // Set the write deadline in the past(1h ago). It makes + // sure that it is always write timeout. + if err := conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)); err != nil { + return err + } + + f, err := os.Open(newton) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(conn, f) + if errors.Is(err, os.ErrDeadlineExceeded) { + return nil + } + + if err == nil { + err = fmt.Errorf("expected ErrDeadlineExceeded, but got nil") + } + return err + }(ln) + + conn, err := Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + n, err := io.Copy(ioutil.Discard, conn) + if err != nil { + t.Fatalf("expected nil error, but got %v", err) + } + if n != 0 { + t.Fatalf("expected receive zero, but got %d byte(s)", n) + } + + if err := <-errc; err != nil { + t.Fatal(err) + } +} -- cgit v1.2.3-54-g00ecf From d9b4ef591c2b058004545eccf10a538aa7597adb Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 30 Nov 2020 10:41:46 +0100 Subject: [release-branch.go1.15] 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. Updates #42876. Fixes #42930. Change-Id: I13c62c88d18574247ad002b671b38d2d0b0fc6fa Reviewed-on: https://go-review.googlesource.com/c/go/+/282432 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- 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 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 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 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 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 + } +} -- cgit v1.2.3-54-g00ecf From 4fda89d4201fc9f0c1e192bbcc95dd8d660e9122 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 23 Feb 2021 13:29:40 +0100 Subject: [release-branch.go1.15] syscall: do not overflow key memory in GetQueuedCompletionStatus The third argument to GetQueuedCompletionStatus is a pointer to a uintptr, not a uint32. Users of this functions have therefore been corrupting their memory every time they used it. Either that memory corruption was silent (dangerous), or their programs didn't work so they chose a different API to use. This fixes the problem by passing through an intermediate buffer. Updates #44538. Fixes #44592. Change-Id: Icacd71f705b36e41e52bd8c4d74898559a27522f Reviewed-on: https://go-review.googlesource.com/c/go/+/296151 Trust: Jason A. Donenfeld Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- src/syscall/syscall_windows.go | 34 +++++++++++++++++++++++++++++++--- src/syscall/zsyscall_windows.go | 6 +++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index f62c00d72f..fbb11a89ca 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -213,9 +213,9 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetEndOfFile(handle Handle) (err error) //sys GetSystemTimeAsFileTime(time *Filetime) //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] -//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) -//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) -//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) +//sys createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) = PostQueuedCompletionStatus //sys CancelIo(s Handle) (err error) //sys CancelIoEx(s Handle, o *Overlapped) (err error) //sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW @@ -1209,3 +1209,31 @@ func Readlink(path string, buf []byte) (n int, err error) { return n, nil } + +// Deprecated: CreateIoCompletionPort has the wrong function signature. Use x/sys/windows.CreateIoCompletionPort. +func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (Handle, error) { + return createIoCompletionPort(filehandle, cphandle, uintptr(key), threadcnt) +} + +// Deprecated: GetQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.GetQueuedCompletionStatus. +func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) error { + var ukey uintptr + var pukey *uintptr + if key != nil { + ukey = uintptr(*key) + pukey = &ukey + } + err := getQueuedCompletionStatus(cphandle, qty, pukey, overlapped, timeout) + if key != nil { + *key = uint32(ukey) + if uintptr(*key) != ukey && err == nil { + err = errorspkg.New("GetQueuedCompletionStatus returned key overflow") + } + } + return err +} + +// Deprecated: PostQueuedCompletionStatus has the wrong function signature. Use x/sys/windows.PostQueuedCompletionStatus. +func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) error { + return postQueuedCompletionStatus(cphandle, qty, uintptr(key), overlapped) +} diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 2348f6534f..2762fb3b74 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -539,7 +539,7 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) { return } -func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) { +func createIoCompletionPort(filehandle Handle, cphandle Handle, key uintptr, threadcnt uint32) (handle Handle, err error) { r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) handle = Handle(r0) if handle == 0 { @@ -552,7 +552,7 @@ func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, thre return } -func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) { +func getQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uintptr, overlapped **Overlapped, timeout uint32) (err error) { r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) if r1 == 0 { if e1 != 0 { @@ -564,7 +564,7 @@ func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overla return } -func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) { +func postQueuedCompletionStatus(cphandle Handle, qty uint32, key uintptr, overlapped *Overlapped) (err error) { r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0) if r1 == 0 { if e1 != 0 { -- cgit v1.2.3-54-g00ecf From 6bb96000b3215a84d0a5193e387cf809d2fa2800 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 25 Feb 2021 10:01:56 -0800 Subject: [release-branch.go1.15] time: correct unusual extension string cases This fixes two uncommon cases. First, the tzdata code permits timezone offsets up to 24 * 7, although the POSIX TZ parsing does not. The tzdata code uses this to specify a day of week in some cases. Second, we incorrectly rejected a negative time offset for when a time zone change comes into effect. For #44385 Fixes #44617 Change-Id: I5f2efc1d385e9bfa974a0de3fa81e7a94b827602 Reviewed-on: https://go-review.googlesource.com/c/go/+/296392 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Tobias Klauser (cherry picked from commit d9fd38e68ba00a51c2c7363150688d0e7687ef84) Reviewed-on: https://go-review.googlesource.com/c/go/+/297229 --- src/time/zoneinfo.go | 6 +++-- src/time/zoneinfo_test.go | 60 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go index c3662297c7..6db9443474 100644 --- a/src/time/zoneinfo.go +++ b/src/time/zoneinfo.go @@ -377,8 +377,10 @@ func tzsetOffset(s string) (offset int, rest string, ok bool) { neg = true } + // The tzdata code permits values up to 24 * 7 here, + // although POSIX does not. var hours int - hours, s, ok = tzsetNum(s, 0, 24) + hours, s, ok = tzsetNum(s, 0, 24*7) if !ok { return 0, "", false } @@ -487,7 +489,7 @@ func tzsetRule(s string) (rule, string, bool) { } offset, s, ok := tzsetOffset(s[1:]) - if !ok || offset < 0 { + if !ok { return rule{}, "", false } r.time = offset diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index 277b68f798..d043e1e9f1 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -183,22 +183,50 @@ func TestMalformedTZData(t *testing.T) { } } -func TestLoadLocationFromTZDataSlim(t *testing.T) { - // A 2020b slim tzdata for Europe/Berlin - tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#3<-02>,M3.5.0/-2,M10.5.0/-1\n", + wantName: "-03", + wantOffset: -10800, + }, + { + // 2021a slim tzdata for Asia/Gaza. + zoneName: "Asia/Gaza", + tzData: "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xffͬ\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xffϏ\x83\x00\xff\xff\xff\xffЩ\xa4\x00\xff\xff\xff\xffф}\x00\xff\xff\xff\xffҊ׀\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\v\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\v\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\u007f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xffﰳp\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\b|\x8b\xe0\x00\x00\x00\x00\b\xfd\xb0\xd0\x00\x00\x00\x00\t\xf6\xea`\x00\x00\x00\x00\n\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\"^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\v\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\a\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\n`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\u007f\x05\xe0\x00\x00\x00\x00A\\\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\\`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00Xդ\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[ӎ`\x00\x00\x00\x00\\\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\t\x00\x00*0\x01\r\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\nEET-2EEST,M3.4.4/48,M10.4.4/49\n", + wantName: "EET", + wantOffset: 7200, + }, +} - reference, err := time.LoadLocationFromTZData("Europe/Berlin", []byte(tzData)) - if err != nil { - t.Fatal(err) - } +func TestLoadLocationFromTZDataSlim(t *testing.T) { + for _, test := range slimTests { + reference, err := time.LoadLocationFromTZData(test.zoneName, []byte(test.tzData)) + if err != nil { + t.Fatal(err) + } - d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference) - tzName, tzOffset := d.Zone() - if want := "CET"; tzName != want { - t.Errorf("Zone name == %s, want %s", tzName, want) - } - if want := 3600; tzOffset != want { - t.Errorf("Zone offset == %d, want %d", tzOffset, want) + d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference) + tzName, tzOffset := d.Zone() + if tzName != test.wantName { + t.Errorf("Zone name == %s, want %s", tzName, test.wantName) + } + if tzOffset != test.wantOffset { + t.Errorf("Zone offset == %d, want %d", tzOffset, test.wantOffset) + } } } @@ -263,7 +291,8 @@ func TestTzsetOffset(t *testing.T) { {"+08", 8 * 60 * 60, "", true}, {"-01:02:03", -1*60*60 - 2*60 - 3, "", true}, {"01", 1 * 60 * 60, "", true}, - {"100", 0, "", false}, + {"100", 100 * 60 * 60, "", true}, + {"1000", 0, "", false}, {"8PDT", 8 * 60 * 60, "PDT", true}, } { off, out, ok := time.TzsetOffset(test.in) @@ -288,6 +317,7 @@ func TestTzsetRule(t *testing.T) { {"30/03:00:00", time.Rule{Kind: time.RuleDOY, Day: 30, Time: 3 * 60 * 60}, "", true}, {"M4.5.6/03:00:00", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: 3 * 60 * 60}, "", true}, {"M4.5.7/03:00:00", time.Rule{}, "", false}, + {"M4.5.6/-04", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: -4 * 60 * 60}, "", true}, } { r, out, ok := time.TzsetRule(test.in) if r != test.r || out != test.out || ok != test.ok { -- cgit v1.2.3-54-g00ecf From f75ab2d5a61f1a5aabaffe7752110e2dcd581236 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 27 Feb 2021 09:41:19 -0800 Subject: [release-branch.go1.15] cmd/compile: fix escape analysis of heap-allocated results One of escape analysis's responsibilities is to summarize whether/how each function parameter flows to the heap so we can correctly incorporate those flows into callers' escape analysis data flow graphs. As an optimization, we separately record when parameters flow to result parameters, so that we can more precisely analyze parameter flows based on how the results are used at the call site. However, if a named result parameter itself needs to be heap allocated, this optimization isn't safe and the parameter needs to be recorded as flowing to heap rather than flowing to result. Escape analysis used to get this correct because it conservatively rewalked the data-flow graph multiple times. So even though it would incorrectly record the result parameter flow, it would separately find a flow to the heap. However, CL 196811 (specifically, case 3) optimized the walking logic to reduce unnecessary rewalks causing us to stop finding the extra heap flow. This CL fixes the issue by correcting location.leakTo to be sensitive to sink.escapes and not record result-flows when the result parameter escapes to the heap. Fixes #44658. Change-Id: I48742ed35a6cab591094e2d23a439e205bd65c50 Reviewed-on: https://go-review.googlesource.com/c/go/+/297289 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall Reviewed-on: https://go-review.googlesource.com/c/go/+/297291 --- src/cmd/compile/internal/gc/escape.go | 7 ++++--- test/escape5.go | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index 08000dd374..2c55163100 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -1379,9 +1379,10 @@ func containsClosure(f, c *Node) bool { // leak records that parameter l leaks to sink. func (l *EscLocation) leakTo(sink *EscLocation, derefs int) { - // If sink is a result parameter and we can fit return bits - // into the escape analysis tag, then record a return leak. - if sink.isName(PPARAMOUT) && sink.curfn == l.curfn { + // If sink is a result parameter that doesn't escape (#44614) + // and we can fit return bits into the escape analysis tag, + // then record as a result leak. + if !sink.escapes && sink.isName(PPARAMOUT) && sink.curfn == l.curfn { // TODO(mdempsky): Eliminate dependency on Vargen here. ri := int(sink.n.Name.Vargen) - 1 if ri < numEscResults { diff --git a/test/escape5.go b/test/escape5.go index 061e57a069..145c5dd900 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -262,3 +262,14 @@ func f28369(n int) int { return 1 + f28369(n-1) } + +// Issue 44614: parameters that flow to a heap-allocated result +// parameter must be recorded as a heap-flow rather than a +// result-flow. + +// N.B., must match "leaking param: p", +// but *not* "leaking param: p to result r level=0". +func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r" + sink4 = &r + return p +} -- cgit v1.2.3-54-g00ecf From 5de8d3bfcb060bbc61b9b9c945055fd3fb5b9607 Mon Sep 17 00:00:00 2001 From: Michael Fraenkel Date: Sat, 26 Sep 2020 09:20:16 -0600 Subject: [release-branch.go1.15] net/http: ignore connection closes once done with the connection Once the connection is put back into the idle pool, the request should not take any action if the connection is closed. For #42935. Updates #41600. Change-Id: I5e4ddcdc03cd44f5197ecfbe324638604961de84 Reviewed-on: https://go-review.googlesource.com/c/go/+/257818 Reviewed-by: Brad Fitzpatrick Trust: Damien Neil (cherry picked from commit 212d385a2f723a8dd5e7d2e83efb478ddd139349) Reviewed-on: https://go-review.googlesource.com/c/go/+/297909 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov Reviewed-by: Damien Neil --- src/net/http/transport.go | 13 +++++++---- src/net/http/transport_test.go | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index d37b52b13d..6fb2ea5663 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -2560,6 +2560,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err var respHeaderTimer <-chan time.Time cancelChan := req.Request.Cancel ctxDoneChan := req.Context().Done() + pcClosed := pc.closech for { testHookWaitResLoop() select { @@ -2579,11 +2580,15 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err defer timer.Stop() // prevent leaks respHeaderTimer = timer.C } - case <-pc.closech: - if debugRoundTrip { - req.logf("closech recv: %T %#v", pc.closed, pc.closed) + case <-pcClosed: + pcClosed = nil + // check if we are still using the connection + if pc.t.replaceReqCanceler(req.cancelKey, nil) { + if debugRoundTrip { + req.logf("closech recv: %T %#v", pc.closed, pc.closed) + } + return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) } - return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) case <-respHeaderTimer: if debugRoundTrip { req.logf("timeout waiting for response headers.") diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 0a47687d9a..3c7b9eb4de 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -6289,3 +6289,54 @@ func TestTransportRejectsSignInContentLength(t *testing.T) { t.Fatalf("Error mismatch\nGot: %q\nWanted substring: %q", got, want) } } + +// Issue 41600 +// Test that a new request which uses the connection of an active request +// cannot cause it to be canceled as well. +func TestCancelRequestWhenSharingConnection(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) { + w.Header().Add("Content-Length", "0") + })) + defer ts.Close() + + client := ts.Client() + transport := client.Transport.(*Transport) + transport.MaxIdleConns = 1 + transport.MaxConnsPerHost = 1 + + var wg sync.WaitGroup + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for ctx.Err() == nil { + reqctx, reqcancel := context.WithCancel(ctx) + go reqcancel() + req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil) + res, err := client.Do(req) + if err == nil { + res.Body.Close() + } + } + }() + } + + for ctx.Err() == nil { + req, _ := NewRequest("GET", ts.URL, nil) + if res, err := client.Do(req); err != nil { + t.Errorf("unexpected: %p %v", req, err) + break + } else { + res.Body.Close() + } + } + + cancel() + wg.Wait() +} -- cgit v1.2.3-54-g00ecf From 1c60e0d928764b1b755c494d4a760eb51b99bc90 Mon Sep 17 00:00:00 2001 From: Michael Fraenkel Date: Wed, 2 Dec 2020 17:07:27 -0700 Subject: [release-branch.go1.15] net/http: add connections back that haven't been canceled Issue #41600 fixed the issue when a second request canceled a connection while the first request was still in roundTrip. This uncovered a second issue where a request was being canceled (in roundtrip) but the connection was put back into the idle pool for a subsequent request. The fix is the similar except its now in readLoop instead of roundTrip. A persistent connection is only added back if it successfully removed the cancel function; otherwise we know the roundTrip has started cancelRequest. Fixes #42935. Updates #42942. Change-Id: Ia56add20880ccd0c1ab812d380d8628e45f6f44c Reviewed-on: https://go-review.googlesource.com/c/go/+/274973 Trust: Dmitri Shuralyov Trust: Damien Neil Reviewed-by: Damien Neil (cherry picked from commit 854a2f8e01a554d8052445563863775406a04b71) Reviewed-on: https://go-review.googlesource.com/c/go/+/297910 Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot --- src/net/http/transport.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 6fb2ea5663..6e430b9885 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -766,7 +766,8 @@ func (t *Transport) CancelRequest(req *Request) { } // Cancel an in-flight request, recording the error value. -func (t *Transport) cancelRequest(key cancelKey, err error) { +// Returns whether the request was canceled. +func (t *Transport) cancelRequest(key cancelKey, err error) bool { t.reqMu.Lock() cancel := t.reqCanceler[key] delete(t.reqCanceler, key) @@ -774,6 +775,8 @@ func (t *Transport) cancelRequest(key cancelKey, err error) { if cancel != nil { cancel(err) } + + return cancel != nil } // @@ -2087,18 +2090,17 @@ func (pc *persistConn) readLoop() { } if !hasBody || bodyWritable { - pc.t.setReqCanceler(rc.cancelKey, nil) + replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // Put the idle conn back into the pool before we send the response // so if they process it quickly and make another request, they'll // get this same conn. But we use the unbuffered channel 'rc' // to guarantee that persistConn.roundTrip got out of its select // potentially waiting for this persistConn to close. - // but after alive = alive && !pc.sawEOF && pc.wroteRequest() && - tryPutIdleConn(trace) + replaced && tryPutIdleConn(trace) if bodyWritable { closeErr = errCallerOwnsConn @@ -2160,12 +2162,12 @@ func (pc *persistConn) readLoop() { // reading the response body. (or for cancellation or death) select { case bodyEOF := <-waitForBodyRead: - pc.t.setReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool + replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool alive = alive && bodyEOF && !pc.sawEOF && pc.wroteRequest() && - tryPutIdleConn(trace) + replaced && tryPutIdleConn(trace) if bodyEOF { eofc <- struct{}{} } @@ -2561,6 +2563,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err cancelChan := req.Request.Cancel ctxDoneChan := req.Context().Done() pcClosed := pc.closech + canceled := false for { testHookWaitResLoop() select { @@ -2582,8 +2585,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err } case <-pcClosed: pcClosed = nil - // check if we are still using the connection - if pc.t.replaceReqCanceler(req.cancelKey, nil) { + if canceled || pc.t.replaceReqCanceler(req.cancelKey, nil) { if debugRoundTrip { req.logf("closech recv: %T %#v", pc.closed, pc.closed) } @@ -2607,10 +2609,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err } return re.res, nil case <-cancelChan: - pc.t.cancelRequest(req.cancelKey, errRequestCanceled) + canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled) cancelChan = nil case <-ctxDoneChan: - pc.t.cancelRequest(req.cancelKey, req.Context().Err()) + canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err()) cancelChan = nil ctxDoneChan = nil } -- cgit v1.2.3-54-g00ecf From ba3dc70dc5c9f2162024b09d6b13bda1f4575b01 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Thu, 4 Mar 2021 11:50:31 -0500 Subject: [release-branch.go1.15] cmd/go: don't report missing std import errors for tidy and vendor 'go mod tidy' and 'go mod vendor' normally report errors when a package can't be imported, even if the import appears in a file that wouldn't be compiled by the current version of Go. These errors are common for packages introduced in higher versions of Go, like "embed" in 1.16. This change causes 'go mod tidy' and 'go mod vendor' to ignore missing package errors if the import path appears to come from the standard library because it lacks a dot in the first path element. NOTE: This change is not a clean cherry-pick of CL 298749 because parts of modload were substantially rewritten after 1.15. Fixes #44792 Updates #27063 Change-Id: I61d6443e77ab95fd8c0d1514f57ef4c8885a77cc Reviewed-on: https://go-review.googlesource.com/c/go/+/298749 Trust: Jay Conrod Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot (cherry picked from commit 56d52e661114be60fb1893b034ac0c5976b622af) Reviewed-on: https://go-review.googlesource.com/c/go/+/298950 --- src/cmd/go/internal/modcmd/tidy.go | 1 + src/cmd/go/internal/modcmd/vendor.go | 1 + src/cmd/go/internal/modload/init.go | 6 ++++++ src/cmd/go/internal/modload/load.go | 5 +++++ src/cmd/go/testdata/script/mod_tidy_error.txt | 4 ++-- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go index af2b04c0c2..5ff847485c 100644 --- a/src/cmd/go/internal/modcmd/tidy.go +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -42,6 +42,7 @@ func runTidy(cmd *base.Command, args []string) { base.Fatalf("go mod tidy: no arguments allowed") } + modload.SilenceMissingStdImports = true modload.LoadALL() modload.TidyBuildList() modTidyGoSum() // updates memory copy; WriteGoMod on next line flushes it out diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index 8509ceb7a8..5a5bb943a5 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -47,6 +47,7 @@ func runVendor(cmd *base.Command, args []string) { if len(args) != 0 { base.Fatalf("go mod vendor: vendor takes no arguments") } + modload.SilenceMissingStdImports = true pkgs := modload.LoadVendor() vdir := filepath.Join(modload.ModRoot(), "vendor") diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 664a2a1594..2360feef04 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -56,6 +56,12 @@ var ( CmdModModule string // module argument for 'go mod init' allowMissingModuleImports bool + + // SilenceMissingStdImports indicates that LoadALL should not print an error + // or terminate the process if an imported package is missing, and the import + // path looks like it might be in the standard library (perhaps in a future + // Go version). + SilenceMissingStdImports bool ) // ModFile returns the parsed go.mod file. diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 30992e0cc2..e5ea1a6c23 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -433,6 +433,11 @@ func loadAll(testAll bool) []string { var paths []string for _, pkg := range loaded.pkgs { if pkg.err != nil { + if impErr := (*ImportMissingError)(nil); SilenceMissingStdImports && + errors.As(pkg.err, &impErr) && + search.IsStandardImportPath(impErr.Path) { + continue + } base.Errorf("%s: %v", pkg.stackText(), pkg.err) continue } diff --git a/src/cmd/go/testdata/script/mod_tidy_error.txt b/src/cmd/go/testdata/script/mod_tidy_error.txt index b6c24ceaf7..395537b1a7 100644 --- a/src/cmd/go/testdata/script/mod_tidy_error.txt +++ b/src/cmd/go/testdata/script/mod_tidy_error.txt @@ -4,12 +4,12 @@ env GO111MODULE=on # 'go mod tidy' and 'go mod vendor' should not hide loading errors. ! go mod tidy -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' ! go mod vendor -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' -- cgit v1.2.3-54-g00ecf From dcffdac515a1d409bcb61783d57ddb137b4741b9 Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Thu, 11 Mar 2021 11:22:22 -0500 Subject: [release-branch.go1.15] go1.15.10 Change-Id: Ib4e90da6307bb80be8b9d67e0efa35d9dd5dd463 Reviewed-on: https://go-review.googlesource.com/c/go/+/300970 Run-TryBot: Carlos Amedee Reviewed-by: Dmitri Shuralyov Trust: Carlos Amedee --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3c734acd99..b22abb18df 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.15.9 \ No newline at end of file +go1.15.10 \ No newline at end of file -- cgit v1.2.3-54-g00ecf