[dev.boringcrypto.go1.16] all: merge go1.16.14 into dev.boringcrypto.go1.16

Change-Id: I186a567b3e76df7ecf1842634a3851eab7c9dfce
diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go
index 8869528..7b4df3f 100644
--- a/misc/cgo/testplugin/plugin_test.go
+++ b/misc/cgo/testplugin/plugin_test.go
@@ -216,3 +216,31 @@
 	goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
 	run(t, "./issue44956.exe")
 }
+
+func TestForkExec(t *testing.T) {
+	// Issue 38824: importing the plugin package causes it hang in forkExec on darwin.
+
+	t.Parallel()
+	goCmd(t, "build", "-o", "forkexec.exe", "./forkexec/main.go")
+
+	var cmd *exec.Cmd
+	done := make(chan int, 1)
+
+	go func() {
+		for i := 0; i < 100; i++ {
+			cmd = exec.Command("./forkexec.exe", "1")
+			err := cmd.Run()
+			if err != nil {
+				t.Errorf("running command failed: %v", err)
+				break
+			}
+		}
+		done <- 1
+	}()
+	select {
+	case <-done:
+	case <-time.After(5 * time.Minute):
+		cmd.Process.Kill()
+		t.Fatalf("subprocess hang")
+	}
+}
diff --git a/misc/cgo/testplugin/testdata/forkexec/main.go b/misc/cgo/testplugin/testdata/forkexec/main.go
new file mode 100644
index 0000000..3169ff5
--- /dev/null
+++ b/misc/cgo/testplugin/testdata/forkexec/main.go
@@ -0,0 +1,30 @@
+// Copyright 2021 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
+
+import (
+	"os"
+	"os/exec"
+	_ "plugin"
+	"sync"
+)
+
+func main() {
+	if os.Args[1] != "1" {
+		return
+	}
+
+	var wg sync.WaitGroup
+	for i := 0; i < 8; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			// does not matter what we exec, just exec itself
+			cmd := exec.Command("./forkexec.exe", "0")
+			cmd.Run()
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go
index 2727c4d..b0e0165 100644
--- a/src/cmd/compile/internal/mips64/ssa.go
+++ b/src/cmd/compile/internal/mips64/ssa.go
@@ -321,7 +321,10 @@
 		for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
 			a = a.Args[0]
 		}
-		if a.Op == ssa.OpLoadReg {
+		if a.Op == ssa.OpLoadReg && mips.REG_R0 <= a.Reg() && a.Reg() <= mips.REG_R31 {
+			// LoadReg from a narrower type does an extension, except loading
+			// to a floating point register. So only eliminate the extension
+			// if it is loaded to an integer register.
 			t := a.Type
 			switch {
 			case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 69989b0..2a30f9c 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -1263,8 +1263,8 @@
 (SRLconst (SLLconst x [c]) [d]) && objabi.GOARM==7 && uint64(d)>=uint64(c) && uint64(d)<=31 => (BFXU [(d-c)|(32-d)<<8] x)
 
 // comparison simplification
-((LT|LE|EQ|NE|GE|GT) (CMP x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMN x y)) // sense of carry bit not preserved
-((LT|LE|EQ|NE|GE|GT) (CMN x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMP x y)) // sense of carry bit not preserved
+((EQ|NE) (CMP x (RSBconst [0] y))) => ((EQ|NE) (CMN x y)) // sense of carry bit not preserved; see also #50854
+((EQ|NE) (CMN x (RSBconst [0] y))) => ((EQ|NE) (CMP x y)) // sense of carry bit not preserved; see also #50864
 (EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (EQ (CMP x y) yes no)
 (EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
 (EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (EQ (CMPconst [c] x) yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 80b4005..3c66494 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -643,19 +643,13 @@
 (GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMNW x y) yes no)
 (GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMNW x y) yes no)
 
+// CMP(x,-y) -> CMN(x,y) is only valid for unordered comparison, if y can be -1<<63
 (EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
 (NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
-(LT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMN x y) yes no)
-(LE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMN x y) yes no)
-(GT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMN x y) yes no)
-(GE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMN x y) yes no)
 
+// CMPW(x,-y) -> CMNW(x,y) is only valid for unordered comparison, if y can be -1<<31
 (EQ (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
 (NE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
-(LT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMNW x y) yes no)
-(LE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMNW x y) yes no)
-(GT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMNW x y) yes no)
-(GE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMNW x y) yes no)
 
 (EQ (CMPconst [0] x) yes no) => (Z x yes no)
 (NE (CMPconst [0] x) yes no) => (NZ x yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index 4d1d14e..fc3dcce 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -281,9 +281,9 @@
 		{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"},   // arg0 compare to auxInt
 		{name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"},                    // arg0 compare to arg1, 32 bit
 		{name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit
-		{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true},   // arg0 compare to -arg1
+		{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true},   // arg0 compare to -arg1, provided arg1 is not 1<<63
 		{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"},   // arg0 compare to -auxInt
-		{name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit
+		{name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit, provided arg1 is not 1<<31
 		{name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit
 		{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true},   // arg0 & arg1 compare to 0
 		{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int64", typ: "Flags"},   // arg0 & auxInt compare to 0
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index 1a7eefa..7516c4f 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -329,7 +329,7 @@
 		// comparisons
 		{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"},                    // arg0 compare to arg1
 		{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt
-		{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1
+		{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1, provided arg1 is not 1<<63
 		{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt
 		{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
 		{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 1f25005..8da5b40 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -17123,42 +17123,6 @@
 			b.resetWithControl(BlockARMLE, cmp)
 			return true
 		}
-		// match: (GE (CMP x (RSBconst [0] y)))
-		// result: (GE (CMN x y))
-		for b.Controls[0].Op == OpARMCMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-				break
-			}
-			y := v_0_1.Args[0]
-			v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARMGE, v0)
-			return true
-		}
-		// match: (GE (CMN x (RSBconst [0] y)))
-		// result: (GE (CMP x y))
-		for b.Controls[0].Op == OpARMCMN {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			v_0_0 := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
-				x := v_0_0
-				if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-					continue
-				}
-				y := v_0_1.Args[0]
-				v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
-				v0.AddArg2(x, y)
-				b.resetWithControl(BlockARMGE, v0)
-				return true
-			}
-			break
-		}
 		// match: (GE (CMPconst [0] l:(SUB x y)) yes no)
 		// cond: l.Uses==1
 		// result: (GEnoov (CMP x y) yes no)
@@ -18039,42 +18003,6 @@
 			b.resetWithControl(BlockARMLT, cmp)
 			return true
 		}
-		// match: (GT (CMP x (RSBconst [0] y)))
-		// result: (GT (CMN x y))
-		for b.Controls[0].Op == OpARMCMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-				break
-			}
-			y := v_0_1.Args[0]
-			v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARMGT, v0)
-			return true
-		}
-		// match: (GT (CMN x (RSBconst [0] y)))
-		// result: (GT (CMP x y))
-		for b.Controls[0].Op == OpARMCMN {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			v_0_0 := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
-				x := v_0_0
-				if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-					continue
-				}
-				y := v_0_1.Args[0]
-				v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
-				v0.AddArg2(x, y)
-				b.resetWithControl(BlockARMGT, v0)
-				return true
-			}
-			break
-		}
 		// match: (GT (CMPconst [0] l:(SUB x y)) yes no)
 		// cond: l.Uses==1
 		// result: (GTnoov (CMP x y) yes no)
@@ -19046,42 +18974,6 @@
 			b.resetWithControl(BlockARMGE, cmp)
 			return true
 		}
-		// match: (LE (CMP x (RSBconst [0] y)))
-		// result: (LE (CMN x y))
-		for b.Controls[0].Op == OpARMCMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-				break
-			}
-			y := v_0_1.Args[0]
-			v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARMLE, v0)
-			return true
-		}
-		// match: (LE (CMN x (RSBconst [0] y)))
-		// result: (LE (CMP x y))
-		for b.Controls[0].Op == OpARMCMN {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			v_0_0 := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
-				x := v_0_0
-				if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-					continue
-				}
-				y := v_0_1.Args[0]
-				v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
-				v0.AddArg2(x, y)
-				b.resetWithControl(BlockARMLE, v0)
-				return true
-			}
-			break
-		}
 		// match: (LE (CMPconst [0] l:(SUB x y)) yes no)
 		// cond: l.Uses==1
 		// result: (LEnoov (CMP x y) yes no)
@@ -19962,42 +19854,6 @@
 			b.resetWithControl(BlockARMGT, cmp)
 			return true
 		}
-		// match: (LT (CMP x (RSBconst [0] y)))
-		// result: (LT (CMN x y))
-		for b.Controls[0].Op == OpARMCMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-				break
-			}
-			y := v_0_1.Args[0]
-			v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARMLT, v0)
-			return true
-		}
-		// match: (LT (CMN x (RSBconst [0] y)))
-		// result: (LT (CMP x y))
-		for b.Controls[0].Op == OpARMCMN {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			v_0_0 := v_0.Args[0]
-			v_0_1 := v_0.Args[1]
-			for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
-				x := v_0_0
-				if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
-					continue
-				}
-				y := v_0_1.Args[0]
-				v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
-				v0.AddArg2(x, y)
-				b.resetWithControl(BlockARMLT, v0)
-				return true
-			}
-			break
-		}
 		// match: (LT (CMPconst [0] l:(SUB x y)) yes no)
 		// cond: l.Uses==1
 		// result: (LTnoov (CMP x y) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index e61d899..5afccf1 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -26214,46 +26214,6 @@
 			}
 			break
 		}
-		// match: (GE (CMP x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (GE (CMN x y) yes no)
-		for b.Controls[0].Op == OpARM64CMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64GE, v0)
-			return true
-		}
-		// match: (GE (CMPW x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (GE (CMNW x y) yes no)
-		for b.Controls[0].Op == OpARM64CMPW {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64GE, v0)
-			return true
-		}
 		// match: (GE (CMPconst [0] z:(MADD a x y)) yes no)
 		// cond: z.Uses==1
 		// result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -26650,46 +26610,6 @@
 			}
 			break
 		}
-		// match: (GT (CMP x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (GT (CMN x y) yes no)
-		for b.Controls[0].Op == OpARM64CMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64GT, v0)
-			return true
-		}
-		// match: (GT (CMPW x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (GT (CMNW x y) yes no)
-		for b.Controls[0].Op == OpARM64CMPW {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64GT, v0)
-			return true
-		}
 		// match: (GT (CMPconst [0] z:(MADD a x y)) yes no)
 		// cond: z.Uses==1
 		// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -27182,46 +27102,6 @@
 			}
 			break
 		}
-		// match: (LE (CMP x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (LE (CMN x y) yes no)
-		for b.Controls[0].Op == OpARM64CMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64LE, v0)
-			return true
-		}
-		// match: (LE (CMPW x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (LE (CMNW x y) yes no)
-		for b.Controls[0].Op == OpARM64CMPW {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64LE, v0)
-			return true
-		}
 		// match: (LE (CMPconst [0] z:(MADD a x y)) yes no)
 		// cond: z.Uses==1
 		// result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -27594,46 +27474,6 @@
 			}
 			break
 		}
-		// match: (LT (CMP x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (LT (CMN x y) yes no)
-		for b.Controls[0].Op == OpARM64CMP {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64LT, v0)
-			return true
-		}
-		// match: (LT (CMPW x z:(NEG y)) yes no)
-		// cond: z.Uses == 1
-		// result: (LT (CMNW x y) yes no)
-		for b.Controls[0].Op == OpARM64CMPW {
-			v_0 := b.Controls[0]
-			_ = v_0.Args[1]
-			x := v_0.Args[0]
-			z := v_0.Args[1]
-			if z.Op != OpARM64NEG {
-				break
-			}
-			y := z.Args[0]
-			if !(z.Uses == 1) {
-				break
-			}
-			v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
-			v0.AddArg2(x, y)
-			b.resetWithControl(BlockARM64LT, v0)
-			return true
-		}
 		// match: (LT (CMPconst [0] z:(MADD a x y)) yes no)
 		// cond: z.Uses==1
 		// result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index 2dcbb99..db7496f 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -298,16 +298,13 @@
 // If statVers is a valid module version, it is used for the Version field.
 // Otherwise, the Version is derived from the passed-in info and recent tags.
 func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
-	info2 := &RevInfo{
-		Name:  info.Name,
-		Short: info.Short,
-		Time:  info.Time,
-	}
-
 	// If this is a plain tag (no dir/ prefix)
 	// and the module path is unversioned,
 	// and if the underlying file tree has no go.mod,
 	// then allow using the tag with a +incompatible suffix.
+	//
+	// (If the version is +incompatible, then the go.mod file must not exist:
+	// +incompatible is not an ongoing opt-out from semantic import versioning.)
 	var canUseIncompatible func() bool
 	canUseIncompatible = func() bool {
 		var ok bool
@@ -321,19 +318,12 @@
 		return ok
 	}
 
-	invalidf := func(format string, args ...interface{}) error {
-		return &module.ModuleError{
-			Path: r.modPath,
-			Err: &module.InvalidVersionError{
-				Version: info2.Version,
-				Err:     fmt.Errorf(format, args...),
-			},
-		}
-	}
-
-	// checkGoMod verifies that the go.mod file for the module exists or does not
-	// exist as required by info2.Version and the module path represented by r.
-	checkGoMod := func() (*RevInfo, error) {
+	// checkCanonical verifies that the canonical version v is compatible with the
+	// module path represented by r, adding a "+incompatible" suffix if needed.
+	//
+	// If statVers is also canonical, checkCanonical also verifies that v is
+	// either statVers or statVers with the added "+incompatible" suffix.
+	checkCanonical := func(v string) (*RevInfo, error) {
 		// If r.codeDir is non-empty, then the go.mod file must exist: the module
 		// author — not the module consumer, — gets to decide how to carve up the repo
 		// into modules.
@@ -344,73 +334,91 @@
 		// r.findDir verifies both of these conditions. Execute it now so that
 		// r.Stat will correctly return a notExistError if the go.mod location or
 		// declared module path doesn't match.
-		_, _, _, err := r.findDir(info2.Version)
+		_, _, _, err := r.findDir(v)
 		if err != nil {
 			// TODO: It would be nice to return an error like "not a module".
 			// Right now we return "missing go.mod", which is a little confusing.
 			return nil, &module.ModuleError{
 				Path: r.modPath,
 				Err: &module.InvalidVersionError{
-					Version: info2.Version,
+					Version: v,
 					Err:     notExistError{err: err},
 				},
 			}
 		}
 
-		// If the version is +incompatible, then the go.mod file must not exist:
-		// +incompatible is not an ongoing opt-out from semantic import versioning.
-		if strings.HasSuffix(info2.Version, "+incompatible") {
-			if !canUseIncompatible() {
-				if r.pathMajor != "" {
-					return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match")
-				} else {
-					return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required")
-				}
-			}
-
-			if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil {
-				return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version))
+		invalidf := func(format string, args ...interface{}) error {
+			return &module.ModuleError{
+				Path: r.modPath,
+				Err: &module.InvalidVersionError{
+					Version: v,
+					Err:     fmt.Errorf(format, args...),
+				},
 			}
 		}
 
-		return info2, nil
+		// Add the +incompatible suffix if needed or requested explicitly, and
+		// verify that its presence or absence is appropriate for this version
+		// (which depends on whether it has an explicit go.mod file).
+
+		if v == strings.TrimSuffix(statVers, "+incompatible") {
+			v = statVers
+		}
+		base := strings.TrimSuffix(v, "+incompatible")
+		var errIncompatible error
+		if !module.MatchPathMajor(base, r.pathMajor) {
+			if canUseIncompatible() {
+				v = base + "+incompatible"
+			} else {
+				if r.pathMajor != "" {
+					errIncompatible = invalidf("module path includes a major version suffix, so major version must match")
+				} else {
+					errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v)))
+				}
+			}
+		} else if strings.HasSuffix(v, "+incompatible") {
+			errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v))
+		}
+
+		if statVers != "" && statVers == module.CanonicalVersion(statVers) {
+			// Since the caller-requested version is canonical, it would be very
+			// confusing to resolve it to anything but itself, possibly with a
+			// "+incompatible" suffix. Error out explicitly.
+			if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base {
+				return nil, &module.ModuleError{
+					Path: r.modPath,
+					Err: &module.InvalidVersionError{
+						Version: statVers,
+						Err:     fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase),
+					},
+				}
+			}
+		}
+
+		if errIncompatible != nil {
+			return nil, errIncompatible
+		}
+
+		return &RevInfo{
+			Name:    info.Name,
+			Short:   info.Short,
+			Time:    info.Time,
+			Version: v,
+		}, nil
 	}
 
 	// Determine version.
-	//
-	// If statVers is canonical, then the original call was repo.Stat(statVers).
-	// Since the version is canonical, we must not resolve it to anything but
-	// itself, possibly with a '+incompatible' annotation: we do not need to do
-	// the work required to look for an arbitrary pseudo-version.
-	if statVers != "" && statVers == module.CanonicalVersion(statVers) {
-		info2.Version = statVers
 
-		if IsPseudoVersion(info2.Version) {
-			if err := r.validatePseudoVersion(info, info2.Version); err != nil {
-				return nil, err
-			}
-			return checkGoMod()
+	if IsPseudoVersion(statVers) {
+		if err := r.validatePseudoVersion(info, statVers); err != nil {
+			return nil, err
 		}
-
-		if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil {
-			if canUseIncompatible() {
-				info2.Version += "+incompatible"
-				return checkGoMod()
-			} else {
-				if vErr, ok := err.(*module.InvalidVersionError); ok {
-					// We're going to describe why the version is invalid in more detail,
-					// so strip out the existing “invalid version” wrapper.
-					err = vErr.Err
-				}
-				return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err)
-			}
-		}
-
-		return checkGoMod()
+		return checkCanonical(statVers)
 	}
 
-	// statVers is empty or non-canonical, so we need to resolve it to a canonical
-	// version or pseudo-version.
+	// statVers is not a pseudo-version, so we need to either resolve it to a
+	// canonical version or verify that it is already a canonical tag
+	// (not a branch).
 
 	// Derive or verify a version from a code repo tag.
 	// Tag must have a prefix matching codeDir.
@@ -441,71 +449,62 @@
 		if v == "" || !strings.HasPrefix(trimmed, v) {
 			return "", false // Invalid or incomplete version (just vX or vX.Y).
 		}
-		if isRetracted(v) {
-			return "", false
-		}
 		if v == trimmed {
 			tagIsCanonical = true
 		}
-
-		if err := module.CheckPathMajor(v, r.pathMajor); err != nil {
-			if canUseIncompatible() {
-				return v + "+incompatible", tagIsCanonical
-			}
-			return "", false
-		}
-
 		return v, tagIsCanonical
 	}
 
 	// If the VCS gave us a valid version, use that.
 	if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical {
-		info2.Version = v
-		return checkGoMod()
+		if info, err := checkCanonical(v); err == nil {
+			return info, err
+		}
 	}
 
 	// Look through the tags on the revision for either a usable canonical version
 	// or an appropriate base for a pseudo-version.
-	var pseudoBase string
+	var (
+		highestCanonical string
+		pseudoBase       string
+	)
 	for _, pathTag := range info.Tags {
 		v, tagIsCanonical := tagToVersion(pathTag)
-		if tagIsCanonical {
-			if statVers != "" && semver.Compare(v, statVers) == 0 {
-				// The user requested a non-canonical version, but the tag for the
-				// canonical equivalent refers to the same revision. Use it.
-				info2.Version = v
-				return checkGoMod()
+		if statVers != "" && semver.Compare(v, statVers) == 0 {
+			// The tag is equivalent to the version requested by the user.
+			if tagIsCanonical {
+				// This tag is the canonical form of the requested version,
+				// not some other form with extra build metadata.
+				// Use this tag so that the resolved version will match exactly.
+				// (If it isn't actually allowed, we'll error out in checkCanonical.)
+				return checkCanonical(v)
 			} else {
-				// Save the highest canonical tag for the revision. If we don't find a
-				// better match, we'll use it as the canonical version.
+				// The user explicitly requested something equivalent to this tag. We
+				// can't use the version from the tag directly: since the tag is not
+				// canonical, it could be ambiguous. For example, tags v0.0.1+a and
+				// v0.0.1+b might both exist and refer to different revisions.
 				//
-				// NOTE: Do not replace this with semver.Max. Despite the name,
-				// semver.Max *also* canonicalizes its arguments, which uses
-				// semver.Canonical instead of module.CanonicalVersion and thereby
-				// strips our "+incompatible" suffix.
-				if semver.Compare(info2.Version, v) < 0 {
-					info2.Version = v
-				}
+				// The tag is otherwise valid for the module, so we can at least use it as
+				// the base of an unambiguous pseudo-version.
+				//
+				// If multiple tags match, tagToVersion will canonicalize them to the same
+				// base version.
+				pseudoBase = v
 			}
-		} else if v != "" && semver.Compare(v, statVers) == 0 {
-			// The user explicitly requested something equivalent to this tag. We
-			// can't use the version from the tag directly: since the tag is not
-			// canonical, it could be ambiguous. For example, tags v0.0.1+a and
-			// v0.0.1+b might both exist and refer to different revisions.
-			//
-			// The tag is otherwise valid for the module, so we can at least use it as
-			// the base of an unambiguous pseudo-version.
-			//
-			// If multiple tags match, tagToVersion will canonicalize them to the same
-			// base version.
-			pseudoBase = v
+		}
+		// Save the highest non-retracted canonical tag for the revision.
+		// If we don't find a better match, we'll use it as the canonical version.
+		if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
+			if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
+				highestCanonical = v
+			}
 		}
 	}
 
-	// If we found any canonical tag for the revision, return it.
+	// If we found a valid canonical tag for the revision, return it.
 	// Even if we found a good pseudo-version base, a canonical version is better.
-	if info2.Version != "" {
-		return checkGoMod()
+	if highestCanonical != "" {
+		return checkCanonical(highestCanonical)
 	}
 
 	// Find the highest tagged version in the revision's history, subject to
@@ -528,11 +527,10 @@
 				tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0"))
 			}
 		}
-		pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid
+		pseudoBase, _ = tagToVersion(tag)
 	}
 
-	info2.Version = PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short)
-	return checkGoMod()
+	return checkCanonical(PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short))
 }
 
 // validatePseudoVersion checks that version has a major version compatible with
@@ -556,10 +554,6 @@
 		}
 	}()
 
-	if err := module.CheckPathMajor(version, r.pathMajor); err != nil {
-		return err
-	}
-
 	rev, err := PseudoVersionRev(version)
 	if err != nil {
 		return err
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
index 02e399f..d98ea87 100644
--- a/src/cmd/go/internal/modfetch/coderepo_test.go
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -418,171 +418,204 @@
 		zipSum:      "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=",
 		zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5",
 	},
+	{
+		// Git branch with a semver name, +incompatible version, and no go.mod file.
+		vcs:  "git",
+		path: "vcs-test.golang.org/go/mod/gitrepo1",
+		rev:  "v2.3.4+incompatible",
+		err:  `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`,
+	},
+	{
+		// Git branch with a semver name, matching go.mod file, and compatible version.
+		vcs:  "git",
+		path: "vcs-test.golang.org/git/semver-branch.git",
+		rev:  "v1.0.0",
+		err:  `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`,
+	},
+	{
+		// Git branch with a semver name, matching go.mod file, and disallowed +incompatible version.
+		// The version/tag mismatch takes precedence over the +incompatible mismatched.
+		vcs:  "git",
+		path: "vcs-test.golang.org/git/semver-branch.git",
+		rev:  "v2.0.0+incompatible",
+		err:  `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
+	},
+	{
+		// Git branch with a semver name, matching go.mod file, and mismatched version.
+		// The version/tag mismatch takes precedence over the +incompatible mismatched.
+		vcs:  "git",
+		path: "vcs-test.golang.org/git/semver-branch.git",
+		rev:  "v2.0.0",
+		err:  `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
+	},
+	{
+		// v3.0.0-devel is the same as tag v4.0.0-beta.1, but v4.0.0-beta.1 would
+		// not be allowed because it is incompatible and a go.mod file exists.
+		// The error message should refer to a valid pseudo-version, not the
+		// unusable semver tag.
+		vcs:  "git",
+		path: "vcs-test.golang.org/git/semver-branch.git",
+		rev:  "v3.0.0-devel",
+		err:  `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
+	},
 }
 
 func TestCodeRepo(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
+	tmpdir := t.TempDir()
 
-	tmpdir, err := os.MkdirTemp("", "modfetch-test-")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tmpdir)
+	for _, tt := range codeRepoTests {
+		f := func(tt codeRepoTest) func(t *testing.T) {
+			return func(t *testing.T) {
+				t.Parallel()
+				if tt.vcs != "mod" {
+					testenv.MustHaveExecPath(t, tt.vcs)
+				}
 
-	t.Run("parallel", func(t *testing.T) {
-		for _, tt := range codeRepoTests {
-			f := func(tt codeRepoTest) func(t *testing.T) {
-				return func(t *testing.T) {
-					t.Parallel()
-					if tt.vcs != "mod" {
-						testenv.MustHaveExecPath(t, tt.vcs)
-					}
+				repo := Lookup("direct", tt.path)
 
-					repo := Lookup("direct", tt.path)
+				if tt.mpath == "" {
+					tt.mpath = tt.path
+				}
+				if mpath := repo.ModulePath(); mpath != tt.mpath {
+					t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
+				}
 
-					if tt.mpath == "" {
-						tt.mpath = tt.path
-					}
-					if mpath := repo.ModulePath(); mpath != tt.mpath {
-						t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
-					}
-
-					info, err := repo.Stat(tt.rev)
-					if err != nil {
-						if tt.err != "" {
-							if !strings.Contains(err.Error(), tt.err) {
-								t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
-							}
-							return
-						}
-						t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
-					}
+				info, err := repo.Stat(tt.rev)
+				if err != nil {
 					if tt.err != "" {
-						t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
+						if !strings.Contains(err.Error(), tt.err) {
+							t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
+						}
+						return
 					}
-					if info.Version != tt.version {
-						t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
-					}
-					if info.Name != tt.name {
-						t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
-					}
-					if info.Short != tt.short {
-						t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
-					}
-					if !info.Time.Equal(tt.time) {
-						t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
-					}
+					t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
+				}
+				if tt.err != "" {
+					t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
+				}
+				if info.Version != tt.version {
+					t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
+				}
+				if info.Name != tt.name {
+					t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
+				}
+				if info.Short != tt.short {
+					t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
+				}
+				if !info.Time.Equal(tt.time) {
+					t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
+				}
 
-					if tt.gomod != "" || tt.gomodErr != "" {
-						data, err := repo.GoMod(tt.version)
-						if err != nil && tt.gomodErr == "" {
-							t.Errorf("repo.GoMod(%q): %v", tt.version, err)
-						} else if err != nil && tt.gomodErr != "" {
-							if err.Error() != tt.gomodErr {
-								t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
-							}
-						} else if tt.gomodErr != "" {
-							t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
-						} else if string(data) != tt.gomod {
-							t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
+				if tt.gomod != "" || tt.gomodErr != "" {
+					data, err := repo.GoMod(tt.version)
+					if err != nil && tt.gomodErr == "" {
+						t.Errorf("repo.GoMod(%q): %v", tt.version, err)
+					} else if err != nil && tt.gomodErr != "" {
+						if err.Error() != tt.gomodErr {
+							t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
 						}
-					}
-
-					needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
-					if tt.zip != nil || tt.zipErr != "" || needHash {
-						f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
-						if err != nil {
-							t.Fatalf("os.CreateTemp: %v", err)
-						}
-						zipfile := f.Name()
-						defer func() {
-							f.Close()
-							os.Remove(zipfile)
-						}()
-
-						var w io.Writer
-						var h hash.Hash
-						if needHash {
-							h = sha256.New()
-							w = io.MultiWriter(f, h)
-						} else {
-							w = f
-						}
-						err = repo.Zip(w, tt.version)
-						f.Close()
-						if err != nil {
-							if tt.zipErr != "" {
-								if err.Error() == tt.zipErr {
-									return
-								}
-								t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
-							}
-							t.Fatalf("repo.Zip(%q): %v", tt.version, err)
-						}
-						if tt.zipErr != "" {
-							t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
-						}
-
-						if tt.zip != nil {
-							prefix := tt.path + "@" + tt.version + "/"
-							z, err := zip.OpenReader(zipfile)
-							if err != nil {
-								t.Fatalf("open zip %s: %v", zipfile, err)
-							}
-							var names []string
-							for _, file := range z.File {
-								if !strings.HasPrefix(file.Name, prefix) {
-									t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
-									continue
-								}
-								names = append(names, file.Name[len(prefix):])
-							}
-							z.Close()
-							if !reflect.DeepEqual(names, tt.zip) {
-								t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
-							}
-						}
-
-						if needHash {
-							sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
-							if err != nil {
-								t.Errorf("repo.Zip(%q): %v", tt.version, err)
-							} else if sum != tt.zipSum {
-								t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
-							} else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
-								t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
-							}
-						}
+					} else if tt.gomodErr != "" {
+						t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
+					} else if string(data) != tt.gomod {
+						t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
 					}
 				}
-			}
-			t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
-			if strings.HasPrefix(tt.path, vgotest1git) {
-				for vcs, alt := range altVgotests {
-					altTest := tt
-					altTest.vcs = vcs
-					altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
-					if strings.HasPrefix(altTest.mpath, vgotest1git) {
-						altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
+
+				needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
+				if tt.zip != nil || tt.zipErr != "" || needHash {
+					f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
+					if err != nil {
+						t.Fatalf("os.CreateTemp: %v", err)
 					}
-					var m map[string]string
-					if alt == vgotest1hg {
-						m = hgmap
+					zipfile := f.Name()
+					defer func() {
+						f.Close()
+						os.Remove(zipfile)
+					}()
+
+					var w io.Writer
+					var h hash.Hash
+					if needHash {
+						h = sha256.New()
+						w = io.MultiWriter(f, h)
+					} else {
+						w = f
 					}
-					altTest.version = remap(altTest.version, m)
-					altTest.name = remap(altTest.name, m)
-					altTest.short = remap(altTest.short, m)
-					altTest.rev = remap(altTest.rev, m)
-					altTest.err = remap(altTest.err, m)
-					altTest.gomodErr = remap(altTest.gomodErr, m)
-					altTest.zipErr = remap(altTest.zipErr, m)
-					altTest.zipSum = ""
-					altTest.zipFileHash = ""
-					t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
+					err = repo.Zip(w, tt.version)
+					f.Close()
+					if err != nil {
+						if tt.zipErr != "" {
+							if err.Error() == tt.zipErr {
+								return
+							}
+							t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
+						}
+						t.Fatalf("repo.Zip(%q): %v", tt.version, err)
+					}
+					if tt.zipErr != "" {
+						t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
+					}
+
+					if tt.zip != nil {
+						prefix := tt.path + "@" + tt.version + "/"
+						z, err := zip.OpenReader(zipfile)
+						if err != nil {
+							t.Fatalf("open zip %s: %v", zipfile, err)
+						}
+						var names []string
+						for _, file := range z.File {
+							if !strings.HasPrefix(file.Name, prefix) {
+								t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
+								continue
+							}
+							names = append(names, file.Name[len(prefix):])
+						}
+						z.Close()
+						if !reflect.DeepEqual(names, tt.zip) {
+							t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
+						}
+					}
+
+					if needHash {
+						sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
+						if err != nil {
+							t.Errorf("repo.Zip(%q): %v", tt.version, err)
+						} else if sum != tt.zipSum {
+							t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
+						} else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
+							t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
+						}
+					}
 				}
 			}
 		}
-	})
+		t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
+		if strings.HasPrefix(tt.path, vgotest1git) {
+			for vcs, alt := range altVgotests {
+				altTest := tt
+				altTest.vcs = vcs
+				altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
+				if strings.HasPrefix(altTest.mpath, vgotest1git) {
+					altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
+				}
+				var m map[string]string
+				if alt == vgotest1hg {
+					m = hgmap
+				}
+				altTest.version = remap(altTest.version, m)
+				altTest.name = remap(altTest.name, m)
+				altTest.short = remap(altTest.short, m)
+				altTest.rev = remap(altTest.rev, m)
+				altTest.err = remap(altTest.err, m)
+				altTest.gomodErr = remap(altTest.gomodErr, m)
+				altTest.zipErr = remap(altTest.zipErr, m)
+				altTest.zipSum = ""
+				altTest.zipFileHash = ""
+				t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
+			}
+		}
+	}
 }
 
 var hgmap = map[string]string{
diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
index 9feffe0..ecc4226 100644
--- a/src/cmd/go/internal/vcs/vcs.go
+++ b/src/cmd/go/internal/vcs/vcs.go
@@ -5,7 +5,6 @@
 package vcs
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
 	exec "internal/execabs"
@@ -1189,8 +1188,9 @@
 	{
 		pathPrefix: "bitbucket.org",
 		regexp:     lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
+		vcs:        "git",
 		repo:       "https://{root}",
-		check:      bitbucketVCS,
+		check:      noVCSSuffix,
 	},
 
 	// IBM DevOps Services (JazzHub)
@@ -1262,56 +1262,6 @@
 	return nil
 }
 
-// bitbucketVCS determines the version control system for a
-// Bitbucket repository, by using the Bitbucket API.
-func bitbucketVCS(match map[string]string) error {
-	if err := noVCSSuffix(match); err != nil {
-		return err
-	}
-
-	var resp struct {
-		SCM string `json:"scm"`
-	}
-	url := &urlpkg.URL{
-		Scheme:   "https",
-		Host:     "api.bitbucket.org",
-		Path:     expand(match, "/2.0/repositories/{bitname}"),
-		RawQuery: "fields=scm",
-	}
-	data, err := web.GetBytes(url)
-	if err != nil {
-		if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 {
-			// this may be a private repository. If so, attempt to determine which
-			// VCS it uses. See issue 5375.
-			root := match["root"]
-			for _, vcs := range []string{"git", "hg"} {
-				if vcsByCmd(vcs).Ping("https", root) == nil {
-					resp.SCM = vcs
-					break
-				}
-			}
-		}
-
-		if resp.SCM == "" {
-			return err
-		}
-	} else {
-		if err := json.Unmarshal(data, &resp); err != nil {
-			return fmt.Errorf("decoding %s: %v", url, err)
-		}
-	}
-
-	if vcsByCmd(resp.SCM) != nil {
-		match["vcs"] = resp.SCM
-		if resp.SCM == "git" {
-			match["repo"] += ".git"
-		}
-		return nil
-	}
-
-	return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
-}
-
 // launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
 // "foo" could be a series name registered in Launchpad with its own branch,
 // and it could also be the name of a directory within the main project
diff --git a/src/cmd/go/internal/vcs/vcs_test.go b/src/cmd/go/internal/vcs/vcs_test.go
index c5c7a32..a4fec3f 100644
--- a/src/cmd/go/internal/vcs/vcs_test.go
+++ b/src/cmd/go/internal/vcs/vcs_test.go
@@ -183,6 +183,13 @@
 			"chiselapp.com/user/kyle/fossilgg",
 			nil,
 		},
+		{
+			"bitbucket.org/workspace/pkgname",
+			&RepoRoot{
+				VCS:  vcsGit,
+				Repo: "https://bitbucket.org/workspace/pkgname",
+			},
+		},
 	}
 
 	for _, test := range tests {
diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt
index 43b9564..361d993 100644
--- a/src/cmd/go/testdata/script/mod_invalid_version.txt
+++ b/src/cmd/go/testdata/script/mod_invalid_version.txt
@@ -194,10 +194,10 @@
 go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
 cd outside
 ! go list -m github.com/pierrec/lz4
-stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
 cd ..
 ! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
 
 # A +incompatible pseudo-version is valid for a revision of the module
 # that lacks a go.mod file.
@@ -222,7 +222,7 @@
 # not resolve to a pseudo-version with a different major version.
 cp go.mod.orig go.mod
 ! go get -d github.com/pierrec/lz4@v2.0.8
-stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2'
+stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
 
 # An invalid +incompatible suffix for a canonical version should error out,
 # not resolve to a pseudo-version.
@@ -233,10 +233,10 @@
 go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible
 cd outside
 ! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
 cd ..
 ! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
 
 -- go.mod.orig --
 module example.com
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index f7a32ae..81efc8f 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1270,7 +1270,10 @@
 		if ctxt.DynlinkingGo() && objabi.GOOS != "ios" {
 			// -flat_namespace is deprecated on iOS.
 			// It is useful for supporting plugins. We don't support plugins on iOS.
-			argv = append(argv, "-Wl,-flat_namespace")
+			// -flat_namespace may cause the dynamic linker to hang at forkExec when
+			// resolving a lazy binding. See issue 38824.
+			// Force eager resolution to work around.
+			argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
 		}
 		if !combineDwarf {
 			argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index f93dc16..afedf18 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -71,6 +71,11 @@
 }
 
 func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
+	if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
+		y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
+		return false
+	}
+
 	// y² = x³ - 3x + b
 	y2 := new(big.Int).Mul(y, y)
 	y2.Mod(y2, curve.P)
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index e80e773..bb16b0d 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -721,3 +721,84 @@
 		t.Errorf("point did not round-trip correctly: got (%v, %v), want (%v, %v)", X, Y, x, y)
 	}
 }
+
+func testAllCurves(t *testing.T, f func(*testing.T, Curve)) {
+	tests := []struct {
+		name  string
+		curve Curve
+	}{
+		{"P256", P256()},
+		{"P256/Params", P256().Params()},
+		{"P224", P224()},
+		{"P224/Params", P224().Params()},
+		{"P384", P384()},
+		{"P384/Params", P384().Params()},
+		{"P521", P521()},
+		{"P521/Params", P521().Params()},
+	}
+	if testing.Short() {
+		tests = tests[:1]
+	}
+	for _, test := range tests {
+		curve := test.curve
+		t.Run(test.name, func(t *testing.T) {
+			t.Parallel()
+			f(t, curve)
+		})
+	}
+}
+
+// TestInvalidCoordinates tests big.Int values that are not valid field elements
+// (negative or bigger than P). They are expected to return false from
+// IsOnCurve, all other behavior is undefined.
+func TestInvalidCoordinates(t *testing.T) {
+	testAllCurves(t, testInvalidCoordinates)
+}
+
+func testInvalidCoordinates(t *testing.T, curve Curve) {
+	checkIsOnCurveFalse := func(name string, x, y *big.Int) {
+		if curve.IsOnCurve(x, y) {
+			t.Errorf("IsOnCurve(%s) unexpectedly returned true", name)
+		}
+	}
+
+	p := curve.Params().P
+	_, x, y, _ := GenerateKey(curve, rand.Reader)
+	xx, yy := new(big.Int), new(big.Int)
+
+	// Check if the sign is getting dropped.
+	xx.Neg(x)
+	checkIsOnCurveFalse("-x, y", xx, y)
+	yy.Neg(y)
+	checkIsOnCurveFalse("x, -y", x, yy)
+
+	// Check if negative values are reduced modulo P.
+	xx.Sub(x, p)
+	checkIsOnCurveFalse("x-P, y", xx, y)
+	yy.Sub(y, p)
+	checkIsOnCurveFalse("x, y-P", x, yy)
+
+	// Check if positive values are reduced modulo P.
+	xx.Add(x, p)
+	checkIsOnCurveFalse("x+P, y", xx, y)
+	yy.Add(y, p)
+	checkIsOnCurveFalse("x, y+P", x, yy)
+
+	// Check if the overflow is dropped.
+	xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535))
+	checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y)
+	yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535))
+	checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy)
+
+	// Check if P is treated like zero (if possible).
+	// y^2 = x^3 - 3x + B
+	// y = mod_sqrt(x^3 - 3x + B)
+	// y = mod_sqrt(B) if x = 0
+	// If there is no modsqrt, there is no point with x = 0, can't test x = P.
+	if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil {
+		if !curve.IsOnCurve(big.NewInt(0), yy) {
+			t.Fatal("(0, mod_sqrt(B)) is not on the curve?")
+		}
+		checkIsOnCurveFalse("P, y", p, yy)
+	}
+}
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
index 8c76021..ff5c834 100644
--- a/src/crypto/elliptic/p224.go
+++ b/src/crypto/elliptic/p224.go
@@ -48,6 +48,11 @@
 }
 
 func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool {
+	if bigX.Sign() < 0 || bigX.Cmp(curve.P) >= 0 ||
+		bigY.Sign() < 0 || bigY.Cmp(curve.P) >= 0 {
+		return false
+	}
+
 	var x, y p224FieldElement
 	p224FromBig(&x, bigX)
 	p224FromBig(&y, bigY)
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index 73cfce3..cdc500e 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -650,10 +650,14 @@
 		return nil, err
 	}
 
-	// Look for DWARF4 .debug_types sections.
+	// Look for DWARF4 .debug_types sections and DWARF5 sections.
 	for i, s := range f.Sections {
 		suffix := dwarfSuffix(s)
-		if suffix != "types" {
+		if suffix == "" {
+			continue
+		}
+		if _, ok := dat[suffix]; ok {
+			// Already handled.
 			continue
 		}
 
@@ -662,7 +666,11 @@
 			return nil, err
 		}
 
-		err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+		if suffix == "types" {
+			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+		} else {
+			err = d.AddSection(".debug_"+suffix, b)
+		}
 		if err != nil {
 			return nil, err
 		}
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 7d763ff..7987730 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -267,10 +267,14 @@
 		return nil, err
 	}
 
-	// Look for DWARF4 .debug_types sections.
+	// Look for DWARF4 .debug_types sections and DWARF5 sections.
 	for i, s := range f.Sections {
 		suffix := dwarfSuffix(s)
-		if suffix != "types" {
+		if suffix == "" {
+			continue
+		}
+		if _, ok := dat[suffix]; ok {
+			// Already handled.
 			continue
 		}
 
@@ -279,7 +283,11 @@
 			return nil, err
 		}
 
-		err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+		if suffix == "types" {
+			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+		} else {
+			err = d.AddSection(".debug_"+suffix, b)
+		}
 		if err != nil {
 			return nil, err
 		}
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
index ac3c8bd..90053a9 100644
--- a/src/math/big/ratconv.go
+++ b/src/math/big/ratconv.go
@@ -169,6 +169,11 @@
 		n := exp5
 		if n < 0 {
 			n = -n
+			if n < 0 {
+				// This can occur if -n overflows. -(-1 << 63) would become
+				// -1 << 63, which is still negative.
+				return nil, false
+			}
 		}
 		if n > 1e6 {
 			return nil, false // avoid excessively large exponents
diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
index 15d206c..e55e655 100644
--- a/src/math/big/ratconv_test.go
+++ b/src/math/big/ratconv_test.go
@@ -104,6 +104,7 @@
 	{in: "4/3/"},
 	{in: "4/3."},
 	{in: "4/"},
+	{in: "13e-9223372036854775808"}, // CVE-2022-23772
 
 	// valid
 	{"0", "0", true},
diff --git a/src/net/http/internal/testcert.go b/src/net/http/internal/testcert.go
index 2284a83..e1bdbe1 100644
--- a/src/net/http/internal/testcert.go
+++ b/src/net/http/internal/testcert.go
@@ -9,37 +9,56 @@
 // LocalhostCert is a PEM-encoded TLS cert with SAN IPs
 // "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
 // generated from src/crypto/tls:
-// go run generate_cert.go  --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+// go run generate_cert.go  --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
 var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
+MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
 MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
-iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
-rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
-BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
-AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
-AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
-tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
-h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
-fblo6RBxUQ==
+MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
+bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
+aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
+YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
+POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
+h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
+AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
+bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
+5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
+cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
++tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
+grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
+5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
+WkBKOclmOV2xlTVuPw==
 -----END CERTIFICATE-----`)
 
 // LocalhostKey is the private key for localhostCert.
 var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
-MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
-SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
-l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
-AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
-3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
-uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
-qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
-jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
-fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
-fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
-y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
-qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
-f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
+4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
+gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
+URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
+AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
+VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
+x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
+lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
+dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
+EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
+XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
+6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
+3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
+uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
+Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
+w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
++bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
+OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
+brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
+m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
+LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
+/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
+s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
+Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
+xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
+ZboOWVe3icTy64BT3OQhmg==
 -----END RSA TESTING KEY-----`))
 
 func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 0e0cccb..7bd28fc 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -1458,3 +1458,38 @@
 		})
 	}
 }
+
+func TestTimeVDSO(t *testing.T) {
+	// Test that time functions have the right stack trace. In particular,
+	// it shouldn't be recursive.
+
+	if runtime.GOOS == "android" {
+		// Flaky on Android, issue 48655. VDSO may not be enabled.
+		testenv.SkipFlaky(t, 48655)
+	}
+
+	p := testCPUProfile(t, stackContains, []string{"time.now"}, avoidFunctions(), func(dur time.Duration) {
+		t0 := time.Now()
+		for {
+			t := time.Now()
+			if t.Sub(t0) >= dur {
+				return
+			}
+		}
+	})
+
+	// Check for recursive time.now sample.
+	for _, sample := range p.Sample {
+		var seenNow bool
+		for _, loc := range sample.Location {
+			for _, line := range loc.Line {
+				if line.Function.Name == "time.now" {
+					if seenNow {
+						t.Fatalf("unexpected recursive time.now")
+					}
+					seenNow = true
+				}
+			}
+		}
+	}
+}
diff --git a/src/runtime/race/testdata/mutex_test.go b/src/runtime/race/testdata/mutex_test.go
index cbed2d3..9dbed9a 100644
--- a/src/runtime/race/testdata/mutex_test.go
+++ b/src/runtime/race/testdata/mutex_test.go
@@ -78,16 +78,23 @@
 	var mu sync.Mutex
 	var x int16 = 0
 	_ = x
+	written := false
 	ch := make(chan bool, 2)
 	go func() {
 		x = 1
 		mu.Lock()
+		written = true
 		mu.Unlock()
 		ch <- true
 	}()
 	go func() {
-		<-time.After(1e5)
+		time.Sleep(100 * time.Microsecond)
 		mu.Lock()
+		for !written {
+			mu.Unlock()
+			time.Sleep(100 * time.Microsecond)
+			mu.Lock()
+		}
 		mu.Unlock()
 		x = 1
 		ch <- true
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 475f523..5ebff90 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -259,8 +259,9 @@
 	MOVW	R1, 4(R13)
 	MOVW	R2, 8(R13)
 
+	MOVW	$ret-4(FP), R2 // caller's SP
 	MOVW	LR, m_vdsoPC(R5)
-	MOVW	R13, m_vdsoSP(R5)
+	MOVW	R2, m_vdsoSP(R5)
 
 	MOVW	m_curg(R5), R0
 
@@ -351,8 +352,9 @@
 	MOVW	R1, 4(R13)
 	MOVW	R2, 8(R13)
 
+	MOVW	$ret-4(FP), R2 // caller's SP
 	MOVW	LR, m_vdsoPC(R5)
-	MOVW	R13, m_vdsoSP(R5)
+	MOVW	R2, m_vdsoSP(R5)
 
 	MOVW	m_curg(R5), R0
 
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 198a5ba..27a2850 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -221,8 +221,9 @@
 	MOVD	R2, 8(RSP)
 	MOVD	R3, 16(RSP)
 
+	MOVD	$ret-8(FP), R2 // caller's SP
 	MOVD	LR, m_vdsoPC(R21)
-	MOVD	R20, m_vdsoSP(R21)
+	MOVD	R2, m_vdsoSP(R21)
 
 	MOVD	m_curg(R21), R0
 	CMP	g, R0
@@ -304,8 +305,9 @@
 	MOVD	R2, 8(RSP)
 	MOVD	R3, 16(RSP)
 
+	MOVD	$ret-8(FP), R2 // caller's SP
 	MOVD	LR, m_vdsoPC(R21)
-	MOVD	R20, m_vdsoSP(R21)
+	MOVD	R2, m_vdsoSP(R21)
 
 	MOVD	m_curg(R21), R0
 	CMP	g, R0
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index c3e9f37..6450b28 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -228,8 +228,9 @@
 	MOVV	R2, 8(R29)
 	MOVV	R3, 16(R29)
 
+	MOVV	$ret-8(FP), R2 // caller's SP
 	MOVV	R31, m_vdsoPC(R17)
-	MOVV	R29, m_vdsoSP(R17)
+	MOVV	R2, m_vdsoSP(R17)
 
 	MOVV	m_curg(R17), R4
 	MOVV	g, R5
@@ -297,8 +298,9 @@
 	MOVV	R2, 8(R29)
 	MOVV	R3, 16(R29)
 
+	MOVV	$ret-8(FP), R2 // caller's SP
 	MOVV	R31, m_vdsoPC(R17)
-	MOVV	R29, m_vdsoSP(R17)
+	MOVV	R2, m_vdsoSP(R17)
 
 	MOVV	m_curg(R17), R4
 	MOVV	g, R5
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 7be8c4c..601ce20 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -204,8 +204,9 @@
 	MOVD	R5, 40(R1)
 
 	MOVD	LR, R14
+	MOVD	$ret-FIXED_FRAME(FP), R5 // caller's SP
 	MOVD	R14, m_vdsoPC(R21)
-	MOVD	R15, m_vdsoSP(R21)
+	MOVD	R5, m_vdsoSP(R21)
 
 	MOVD	m_curg(R21), R6
 	CMP	g, R6
@@ -296,9 +297,10 @@
 	MOVD	R4, 32(R1)
 	MOVD	R5, 40(R1)
 
-	MOVD	LR, R14		// R14 is unchanged by C code
+	MOVD	LR, R14				// R14 is unchanged by C code
+	MOVD	$ret-FIXED_FRAME(FP), R5	// caller's SP
 	MOVD	R14, m_vdsoPC(R21)
-	MOVD	R15, m_vdsoSP(R21)
+	MOVD	R5, m_vdsoSP(R21)
 
 	MOVD	m_curg(R21), R6
 	CMP	g, R6
diff --git a/src/testing/testing.go b/src/testing/testing.go
index dec39d2..a53d574 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -251,6 +251,8 @@
 	"sync"
 	"sync/atomic"
 	"time"
+	"unicode"
+	"unicode/utf8"
 )
 
 var initRan bool
@@ -906,11 +908,6 @@
 	c.cleanups = append(c.cleanups, fn)
 }
 
-var tempDirReplacer struct {
-	sync.Once
-	r *strings.Replacer
-}
-
 // TempDir returns a temporary directory for the test to use.
 // The directory is automatically removed by Cleanup when the test and
 // all its subtests complete.
@@ -934,13 +931,26 @@
 	if nonExistent {
 		c.Helper()
 
-		// os.MkdirTemp doesn't like path separators in its pattern,
-		// so mangle the name to accommodate subtests.
-		tempDirReplacer.Do(func() {
-			tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_")
-		})
-		pattern := tempDirReplacer.r.Replace(c.Name())
-
+		// Drop unusual characters (such as path separators or
+		// characters interacting with globs) from the directory name to
+		// avoid surprising os.MkdirTemp behavior.
+		mapper := func(r rune) rune {
+			if r < utf8.RuneSelf {
+				const allowed = "!#$%&()+,-.=@^_{}~ "
+				if '0' <= r && r <= '9' ||
+					'a' <= r && r <= 'z' ||
+					'A' <= r && r <= 'Z' {
+					return r
+				}
+				if strings.ContainsRune(allowed, r) {
+					return r
+				}
+			} else if unicode.IsLetter(r) || unicode.IsNumber(r) {
+				return r
+			}
+			return -1
+		}
+		pattern := strings.Map(mapper, c.Name())
 		c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
 		if c.tempDirErr == nil {
 			c.Cleanup(func() {
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 0f09698..42058ae 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -58,6 +58,9 @@
 	t.Run("test:subtest", testTempDir)
 	t.Run("test/..", testTempDir)
 	t.Run("../test", testTempDir)
+	t.Run("test[]", testTempDir)
+	t.Run("test*", testTempDir)
+	t.Run("äöüéè", testTempDir)
 }
 
 func testTempDir(t *testing.T) {
@@ -74,7 +77,7 @@
 			if err != nil {
 				t.Fatal(err)
 			}
-			t.Errorf("directory %q stil exists: %v, isDir=%v", dir, fi, fi.IsDir())
+			t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
 		default:
 			if !t.Failed() {
 				t.Fatal("never received dir channel")
@@ -108,4 +111,9 @@
 	if len(files) > 0 {
 		t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
 	}
+
+	glob := filepath.Join(dir, "*.txt")
+	if _, err := filepath.Glob(glob); err != nil {
+		t.Error(err)
+	}
 }
diff --git a/test/fixedbugs/issue50671.go b/test/fixedbugs/issue50671.go
new file mode 100644
index 0000000..9f4742b
--- /dev/null
+++ b/test/fixedbugs/issue50671.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2022 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.
+
+// Issue 50671: sign extension eliminated incorrectly on MIPS64.
+
+package main
+
+//go:noinline
+func F(x int32) (float64, int64) {
+	a := float64(x)
+	b := int64(x)
+	return a, b
+}
+
+var a, b, c float64
+
+// Poison some floating point registers with non-zero high bits.
+//
+//go:noinline
+func poison(x float64) {
+	a = x - 123.45
+	b = a * 1.2
+	c = b + 3.4
+}
+
+func main() {
+	poison(333.3)
+	_, b := F(123)
+	if b != 123 {
+		panic("FAIL")
+	}
+}
diff --git a/test/fixedbugs/issue50854.go b/test/fixedbugs/issue50854.go
new file mode 100644
index 0000000..a5be919
--- /dev/null
+++ b/test/fixedbugs/issue50854.go
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2022 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
+
+// This checks for incorrect application of CMP(-x,y) -> CMN(x,y) in arm and arm64
+
+//go:noinline
+func f(p int64, x, y int64) bool { return -x <= p && p <= y }
+
+//go:noinline
+func g(p int32, x, y int32) bool { return -x <= p && p <= y }
+
+// There are some more complicated patterns involving compares and shifts, try to trigger those.
+
+//go:noinline
+func h(p int64, x, y int64) bool { return -(x<<1) <= p && p <= y }
+
+//go:noinline
+func k(p int32, x, y int32) bool { return -(1<<x) <= p && p <= y }
+
+//go:noinline
+func check(b bool) {
+	if b {
+		return
+	}
+	panic("FAILURE")
+}
+
+func main() {
+	check(f(1, -1<<63, 1<<63-1))
+	check(g(1, -1<<31, 1<<31-1))
+	check(h(1, -1<<62, 1<<63-1))
+	check(k(1, 31, 1<<31-1))
+}