cmd/compile: handle new panicindex/slice names in optimizations

These new calls should not prevent NOSPLIT promotion, like the old ones.
These new calls should not prevent racefuncenter/exit removal.

(The latter was already true, as the new calls are not yet lowered
to StaticCalls at the point where racefuncenter/exit removal is done.)

Add tests to make sure we don't regress (again).

Fixes #31219

Change-Id: I3fb6b17cdd32c425829f1e2498defa813a5a9ace
Reviewed-on: https://go-review.googlesource.com/c/go/+/170639
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ilya Tocar <ilya.tocar@intel.com>
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 8165852..6fc504e 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -1129,17 +1129,20 @@
 		for _, v := range b.Values {
 			switch v.Op {
 			case OpStaticCall:
-				switch v.Aux.(fmt.Stringer).String() {
-				case "runtime.racefuncenter", "runtime.racefuncexit", "runtime.panicindex",
-					"runtime.panicslice", "runtime.panicdivide", "runtime.panicwrap",
-					"runtime.panicshift":
 				// Check for racefuncenter will encounter racefuncexit and vice versa.
 				// Allow calls to panic*
-				default:
-					// If we encountered any call, we need to keep racefunc*,
-					// for accurate stacktraces.
-					return false
+				s := v.Aux.(fmt.Stringer).String()
+				switch s {
+				case "runtime.racefuncenter", "runtime.racefuncexit",
+					"runtime.panicdivide", "runtime.panicwrap",
+					"runtime.panicshift":
+					continue
 				}
+				// If we encountered any call, we need to keep racefunc*,
+				// for accurate stacktraces.
+				return false
+			case OpPanicBounds, OpPanicExtend:
+				// Note: these are panic generators that are ok (like the static calls above).
 			case OpClosureCall, OpInterCall:
 				// We must keep the race functions if there are any other call types.
 				return false
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index eb0e88b..2fba397 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -975,7 +975,13 @@
 		return false
 	}
 	switch s.Name {
-	case "runtime.panicindex", "runtime.panicslice", "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
+	case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
+		return true
+	}
+	if strings.HasPrefix(s.Name, "runtime.panicIndex") || strings.HasPrefix(s.Name, "runtime.panicSlice") {
+		// These functions do take arguments (in registers),
+		// but use no stack before they do a stack check. We
+		// should include them. See issue 31219.
 		return true
 	}
 	return false
diff --git a/test/codegen/race.go b/test/codegen/race.go
new file mode 100644
index 0000000..ed6706f
--- /dev/null
+++ b/test/codegen/race.go
@@ -0,0 +1,20 @@
+// asmcheck -race
+
+// Copyright 2019 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 codegen
+
+// Check that we elide racefuncenter/racefuncexit for
+// functions with no calls (but which might panic
+// in various ways). See issue 31219.
+// amd64:-"CALL.*racefuncenter.*"
+func RaceMightPanic(a []int, i, j, k, s int) {
+	var b [4]int
+	_ = b[i]     // panicIndex
+	_ = a[i:j]   // panicSlice
+	_ = a[i:j:k] // also panicSlice
+	_ = i << s   // panicShift
+	_ = i / j    // panicDivide
+}
diff --git a/test/codegen/stack.go b/test/codegen/stack.go
index ed2c1ed..ca37622 100644
--- a/test/codegen/stack.go
+++ b/test/codegen/stack.go
@@ -98,3 +98,14 @@
 	// arm:`.*b\+4\(FP\)`
 	return b
 }
+
+// Check that simple functions get promoted to nosplit, even when
+// they might panic in various ways. See issue 31219.
+// amd64:"TEXT\t.*NOSPLIT.*"
+func MightPanic(a []int, i, j, k, s int) {
+	_ = a[i]     // panicIndex
+	_ = a[i:j]   // panicSlice
+	_ = a[i:j:k] // also panicSlice
+	_ = i << s   // panicShift
+	_ = i / j    // panicDivide
+}
diff --git a/test/run.go b/test/run.go
index 292903f..460d4f2 100644
--- a/test/run.go
+++ b/test/run.go
@@ -660,6 +660,9 @@
 			cmdline = append(cmdline, long)
 			cmd := exec.Command(goTool(), cmdline...)
 			cmd.Env = append(os.Environ(), env.Environ()...)
+			if len(flags) > 0 && flags[0] == "-race" {
+				cmd.Env = append(cmd.Env, "CGO_ENABLED=1")
+			}
 
 			var buf bytes.Buffer
 			cmd.Stdout, cmd.Stderr = &buf, &buf