diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index db65737ed390e7..a53e3771bc3378 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -1389,6 +1389,11 @@ (GreaterThanF (InvertFlags x)) => (LessThanF x) (GreaterEqualF (InvertFlags x)) => (LessEqualF x) +(GreaterEqual (CMPconst x [0])) => (XORconst [1] (SRLconst [63] x)) +(LessThan (CMPconst x [0])) => (SRLconst [63] x) +(GreaterEqual (CMPWconst x [0])) => (XORconst [1] (UBFX [armBFAuxInt(31,1)] x)) +(LessThan (CMPWconst x [0])) => (UBFX [armBFAuxInt(31,1)] x) + // Don't bother extending if we're not using the higher bits. (MOV(B|BU)reg x) && v.Type.Size() <= 1 => x (MOV(H|HU)reg x) && v.Type.Size() <= 2 => x diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 149de06c0aba9b..aa603286a6ce8c 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -7736,6 +7736,36 @@ func rewriteValueARM64_OpARM64GreaterEqual(v *Value) bool { v.AddArg(x) return true } + // match: (GreaterEqual (CMPconst x [0])) + // result: (XORconst [1] (SRLconst [63] x)) + for { + if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpARM64XORconst) + v.AuxInt = int64ToAuxInt(1) + v0 := b.NewValue0(v.Pos, OpARM64SRLconst, v.Type) + v0.AuxInt = int64ToAuxInt(63) + v0.AddArg(x) + v.AddArg(v0) + return true + } + // match: (GreaterEqual (CMPWconst x [0])) + // result: (XORconst [1] (UBFX [armBFAuxInt(31,1)] x)) + for { + if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpARM64XORconst) + v.AuxInt = int64ToAuxInt(1) + v0 := b.NewValue0(v.Pos, OpARM64UBFX, v.Type) + v0.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(31, 1)) + v0.AddArg(x) + v.AddArg(v0) + return true + } return false } func rewriteValueARM64_OpARM64GreaterEqualF(v *Value) bool { @@ -8415,6 +8445,30 @@ func rewriteValueARM64_OpARM64LessThan(v *Value) bool { v.AddArg(x) return true } + // match: (LessThan (CMPconst x [0])) + // result: (SRLconst [63] x) + for { + if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpARM64SRLconst) + v.AuxInt = int64ToAuxInt(63) + v.AddArg(x) + return true + } + // match: (LessThan (CMPWconst x [0])) + // result: (UBFX [armBFAuxInt(31,1)] x) + for { + if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpARM64UBFX) + v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(31, 1)) + v.AddArg(x) + return true + } return false } func rewriteValueARM64_OpARM64LessThanF(v *Value) bool { diff --git a/src/cmd/go/internal/telemetrystats/telemetrystats.go b/src/cmd/go/internal/telemetrystats/telemetrystats.go index c6e58935bb0ee2..763aed8bf46bda 100644 --- a/src/cmd/go/internal/telemetrystats/telemetrystats.go +++ b/src/cmd/go/internal/telemetrystats/telemetrystats.go @@ -39,8 +39,6 @@ func incrementConfig() { counter.Inc("go/cgo:disabled") } - counter.Inc("go/platform/target/goos:" + cfg.Goos) - counter.Inc("go/platform/target/goarch:" + cfg.Goarch) counter.Inc("go/platform/target/port:" + cfg.Goos + "-" + cfg.Goarch) switch cfg.Goarch { case "386": diff --git a/src/cmd/internal/script/cmds.go b/src/cmd/internal/script/cmds.go index 7e2e507a02157e..baf7cc6069a277 100644 --- a/src/cmd/internal/script/cmds.go +++ b/src/cmd/internal/script/cmds.go @@ -36,7 +36,7 @@ func DefaultCmds() map[string]Cmd { "cp": Cp(), "echo": Echo(), "env": Env(), - "exec": Exec(func(cmd *exec.Cmd) error { return cmd.Process.Signal(os.Interrupt) }, 100*time.Millisecond), // arbitrary grace period + "exec": Exec(func(cmd *exec.Cmd) error { return InterruptCmd(cmd) }, 100*time.Millisecond), // arbitrary grace period "exists": Exists(), "grep": Grep(), "help": Help(), @@ -53,6 +53,19 @@ func DefaultCmds() map[string]Cmd { } } +// InterruptCmd interrupts cmd process. +// InterruptCmd kills the process on Windows, because +// cmd.Process.Signal(os.Interrupt) is not supported on Windows. +func InterruptCmd(cmd *exec.Cmd) error { + if runtime.GOOS == "windows" { + // windows does not implement cmd.Process.Signal + return cmd.Process.Kill() + } + // TODO(thepudds): currently cmd/go/script_test.go uses a platform-specific cancel + // that we could consider emulating here. + return cmd.Process.Signal(os.Interrupt) +} + // Command returns a new Cmd with a Usage method that returns a copy of the // given CmdUsage and a Run method calls the given function. func Command(usage CmdUsage, run func(*State, ...string) (WaitFunc, error)) Cmd { diff --git a/src/cmd/internal/script/engine_test.go b/src/cmd/internal/script/engine_test.go index 45d0a0faf9d2e2..19d18364eee884 100644 --- a/src/cmd/internal/script/engine_test.go +++ b/src/cmd/internal/script/engine_test.go @@ -6,10 +6,76 @@ package script import ( "context" + "fmt" + "internal/testenv" + "io" + "os" + "os/exec" + "runtime" "slices" "testing" + "time" ) +func TestInterruptCmd(t *testing.T) { + if runtime.GOOS == "js" || runtime.GOOS == "wasip1" { + t.Skip(runtime.GOOS + " does not support executables") + } + + const msg = "Hello world\n" + + if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { + fmt.Printf(msg) + time.Sleep(24 * time.Hour) // sleep forever + os.Exit(3) + } + + exe := testenv.Executable(t) + cmd := testenv.CommandContext(t, t.Context(), exe, "-test.run=^TestInterruptCmd$") + cmd = testenv.CleanCmdEnv(cmd) + cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") + + stdout, err := cmd.StdoutPipe() + if err != nil { + t.Fatal(err) + } + + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + + buf := make([]byte, len(msg)) + n, err := io.ReadFull(stdout, buf) + if n != len(buf) || err != nil || string(buf) != msg { + t.Fatalf("ReadFull = %d, %v, %q", n, err, buf[:n]) + } + + interruptCmdErr := make(chan error) + go func() { + interruptCmdErr <- InterruptCmd(cmd) + }() + + err = cmd.Wait() + if err == nil { + t.Fatal("expected Wait failure") + } else if err, ok := err.(*exec.ExitError); ok { + expectedError := "signal: interrupt" + if runtime.GOOS == "windows" { + expectedError = "exit status 1" + } + if err.Error() != expectedError { + t.Fatalf("unexpected error while exiting executable: got=%q, want=%q", err.Error(), expectedError) + } + } else { + t.Fatalf("unexpected error while running executable: %s\n%s", err, string(buf)) + } + + err = <-interruptCmdErr + if err != nil { + t.Errorf("InterruptCmd failed: %v", err) + } +} + func FuzzQuoteArgs(f *testing.F) { state, err := NewState(context.Background(), f.TempDir(), nil /* env */) if err != nil { diff --git a/src/cmd/internal/script/scripttest/run.go b/src/cmd/internal/script/scripttest/run.go index ecd91b84be2ad7..dab3834065658e 100644 --- a/src/cmd/internal/script/scripttest/run.go +++ b/src/cmd/internal/script/scripttest/run.go @@ -103,17 +103,11 @@ func NewEngine(t *testing.T, repls []ToolReplacement) (*script.Engine, []string) return env } - interrupt := func(cmd *exec.Cmd) error { - // TODO(thepudds): currently cmd/go/script_test.go uses a platform-specific cancel - // that we could consider emulating here. - return cmd.Process.Signal(os.Interrupt) - } - // Customize the subprocess termination grace period to reduce flakes on busy builders (#76685). // The grace period is the max of 100ms or 5% of the time remaining until any t.Deadline. gracePeriod := subprocessGracePeriod(t.Deadline()) - cmdExec := script.Exec(interrupt, gracePeriod) + cmdExec := script.Exec(script.InterruptCmd, gracePeriod) cmds["exec"] = cmdExec // Set up an alternate go root for running script tests, since it @@ -130,7 +124,7 @@ func NewEngine(t *testing.T, repls []ToolReplacement) (*script.Engine, []string) // Add in commands for "go" and "cc". testgo := filepath.Join(tgr, "bin", "go") - gocmd := script.Program(testgo, interrupt, gracePeriod) + gocmd := script.Program(testgo, script.InterruptCmd, gracePeriod) addcmd("go", gocmd) addcmd("cc", scriptCC(cmdExec, goEnv("CC"))) diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index 0c25946094ce5a..778fe8490a0852 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -590,6 +590,23 @@ func CmpToOneU_ex2(a uint8, b uint16, c uint32, d uint64) int { return 0 } +func int64LtZero(x int64) bool { + // arm64: `LSR [$]63` + return x < 0 +} +func int64GeZero(x int64) bool { + // arm64: `LSR [$]63` `EOR [$]1` + return x >= 0 +} +func int32LtZero(x int32) bool { + // arm64: `UBFX [$]31, R[0-9]+, [$]1,` + return x < 0 +} +func int32GeZero(x int32) bool { + // arm64: `UBFX [$]31, R[0-9]+, [$]1,` `EOR [$]1` + return x >= 0 +} + // Check that small memequals are replaced with eq instructions func equalConstString1() bool { @@ -748,7 +765,7 @@ func cmpToCmnLessThan(a, b, c, d int) int { if a*b+c < 0 { c3 = 1 } - // arm64:`MSUB` `CSET LT` -`CMN` + // arm64:`MSUB` `LSR` if a-b*c < 0 { c4 = 1 } @@ -817,7 +834,7 @@ func cmpToCmnGreaterThanEqual(a, b, c, d int) int { if a*b+c >= 0 { c3 = 1 } - // arm64:`MSUB` `CSET GE` -`CMN` + // arm64:`MSUB` `LSR` `EOR [$]1` if a-b*c >= 0 { c4 = 1 }