cmd/compile: special case nowritebarrierrec for allocm

allocm is a very unusual function: it is specifically designed to
allocate in contexts where m.p is nil by temporarily taking over a P.
Since allocm is used in many contexts where it would make sense to use
nowritebarrierrec, this commit teaches the nowritebarrierrec analysis
to stop at allocm.

Updates #10600.

Change-Id: I8499629461d4fe25712d861720dfe438df7ada9b
Reviewed-on: https://go-review.googlesource.com/17005
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index c0326c5..9b865bb 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -1575,6 +1575,9 @@
 	if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
 		return
 	}
+	if (compiling_runtime != 0 || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
+		return
+	}
 	defn := fn.Name.Defn
 
 	fnbest, ok := c.best[defn]
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index f47c4be..f89669f 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1182,6 +1182,9 @@
 // Allocate a new m unassociated with any thread.
 // Can use p for allocation context if needed.
 // fn is recorded as the new m's m.mstartfn.
+//
+// This function it known to the compiler to inhibit the
+// go:nowritebarrierrec annotation because it uses P for allocation.
 func allocm(_p_ *p, fn func()) *m {
 	_g_ := getg()
 	_g_.m.locks++ // disable GC because it can be called from sysmon