cmd/gc: implement more cases in racewalk.

Add missing CLOSUREVAR in switch.
Mark MAKE, string conversion nodes as impossible.
Control statements do not need instrumentation.
Instrument COM and LROT nodes.
Instrument map length.

Update #4228

R=dvyukov, golang-dev
CC=golang-dev
https://golang.org/cl/7504047
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index 269c0b2..3e5e592 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -196,6 +196,7 @@
 	case OPLUS:
 	case OREAL:
 	case OIMAG:
+	case OCOM:
 		racewalknode(&n->left, init, wr, 0);
 		goto ret;
 
@@ -222,23 +223,17 @@
 	case OCAP:
 		racewalknode(&n->left, init, 0, 0);
 		if(istype(n->left->type, TMAP)) {
-			// crashes on len(m[0]) or len(f())
-			SET(n1);
-			USED(n1);
-			/*
-			n1 = nod(OADDR, n->left, N);
-			n1 = conv(n1, types[TUNSAFEPTR]);
-			n1 = conv(n1, ptrto(ptrto(types[TINT8])));
-			n1 = nod(OIND, n1, N);
+			n1 = nod(OCONVNOP, n->left, N);
+			n1->type = ptrto(types[TUINT8]);
 			n1 = nod(OIND, n1, N);
 			typecheck(&n1, Erv);
 			callinstr(&n1, init, 0, skip);
-			*/
 		}
 		goto ret;
 
 	case OLSH:
 	case ORSH:
+	case OLROT:
 	case OAND:
 	case OANDNOT:
 	case OOR:
@@ -279,7 +274,6 @@
 
 	case ODIV:
 	case OMOD:
-		// TODO(dvyukov): add a test for this
 		racewalknode(&n->left, init, wr, 0);
 		racewalknode(&n->right, init, wr, 0);
 		goto ret;
@@ -324,9 +318,30 @@
 	case OPANIC:
 	case ORECOVER:
 	case OCONVIFACE:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case OCALL:
+	case OCOPY:
+	case ORUNESTR:
+	case OARRAYBYTESTR:
+	case OARRAYRUNESTR:
+	case OSTRARRAYBYTE:
+	case OSTRARRAYRUNE:
+	case OINDEXMAP:  // lowered to call
+	case OCMPSTR:
+	case OADDSTR:
+	case ODOTTYPE:
+	case ODOTTYPE2:
 		yyerror("racewalk: %O must be lowered by now", n->op);
 		goto ret;
 
+	// impossible nodes: only appear in backend.
+	case ORROTC:
+	case OEXTEND:
+		yyerror("racewalk: %O cannot exist now", n->op);
+		goto ret;
+
 	// just do generic traversal
 	case OFOR:
 	case OIF:
@@ -334,43 +349,28 @@
 	case ORETURN:
 	case OSELECT:
 	case OEMPTY:
+	case OBREAK:
+	case OCONTINUE:
+	case OFALL:
+	case OGOTO:
+	case OLABEL:
 		goto ret;
 
 	// does not require instrumentation
-	case OINDEXMAP:  // implemented in runtime
 	case OPRINT:     // don't bother instrumenting it
 	case OPRINTN:    // don't bother instrumenting it
 	case OPARAM:     // it appears only in fn->exit to copy heap params back
 		goto ret;
 
 	// unimplemented
-	case OCMPSTR:
-	case OADDSTR:
 	case OSLICESTR:
 	case OAPPEND:
-	case OCOPY:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case ORUNESTR:
-	case OARRAYBYTESTR:
-	case OARRAYRUNESTR:
-	case OSTRARRAYBYTE:
-	case OSTRARRAYRUNE:
 	case OCMPIFACE:
 	case OARRAYLIT:
 	case OMAPLIT:
 	case OSTRUCTLIT:
 	case OCLOSURE:
-	case ODOTTYPE:
-	case ODOTTYPE2:
-	case OCALL:
-	case OBREAK:
 	case ODCL:
-	case OCONTINUE:
-	case OFALL:
-	case OGOTO:
-	case OLABEL:
 	case ODCLCONST:
 	case ODCLTYPE:
 	case OLITERAL:
@@ -378,14 +378,11 @@
 	case OTYPE:
 	case ONONAME:
 	case OINDREG:
-	case OCOM:
 	case ODOTMETH:
 	case OITAB:
-	case OEXTEND:
 	case OHMUL:
-	case OLROT:
-	case ORROTC:
 	case OCHECKNOTNIL:
+	case OCLOSUREVAR:
 		goto ret;
 	}
 
diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go
index 6f86a50..35db8db 100644
--- a/src/pkg/runtime/race/testdata/map_test.go
+++ b/src/pkg/runtime/race/testdata/map_test.go
@@ -94,8 +94,7 @@
 	<-ch
 }
 
-// Map len is not instrumented.
-func TestRaceFailingMapLen(t *testing.T) {
+func TestRaceMapLen(t *testing.T) {
 	m := make(map[string]bool)
 	ch := make(chan bool, 1)
 	go func() {
@@ -117,8 +116,7 @@
 	<-ch
 }
 
-// Map len is not instrumented.
-func TestRaceFailingMapLenDelete(t *testing.T) {
+func TestRaceMapLenDelete(t *testing.T) {
 	m := make(map[string]bool)
 	ch := make(chan bool, 1)
 	go func() {
diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go
index f2daa37..26cd3a4 100644
--- a/src/pkg/runtime/race/testdata/mop_test.go
+++ b/src/pkg/runtime/race/testdata/mop_test.go
@@ -306,6 +306,102 @@
 	<-ch
 }
 
+func TestRaceComplement(t *testing.T) {
+	var x, y, z int
+	ch := make(chan int, 2)
+
+	go func() {
+		x = ^y
+		ch <- 1
+	}()
+	go func() {
+		y = ^z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
+func TestRaceDiv(t *testing.T) {
+	var x, y, z int
+	ch := make(chan int, 2)
+
+	go func() {
+		x = y / (z + 1)
+		ch <- 1
+	}()
+	go func() {
+		y = z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
+func TestRaceDivConst(t *testing.T) {
+	var x, y, z int
+	ch := make(chan int, 2)
+
+	go func() {
+		x = y / 3
+		ch <- 1
+	}()
+	go func() {
+		y = z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
+func TestRaceMod(t *testing.T) {
+	var x, y, z int
+	ch := make(chan int, 2)
+
+	go func() {
+		x = y % (z + 1)
+		ch <- 1
+	}()
+	go func() {
+		y = z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
+func TestRaceModConst(t *testing.T) {
+	var x, y, z int
+	ch := make(chan int, 2)
+
+	go func() {
+		x = y % 3
+		ch <- 1
+	}()
+	go func() {
+		y = z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
+func TestRaceRotate(t *testing.T) {
+	var x, y, z uint32
+	ch := make(chan int, 2)
+
+	go func() {
+		x = y<<12 | y>>20
+		ch <- 1
+	}()
+	go func() {
+		y = z
+		ch <- 1
+	}()
+	<-ch
+	<-ch
+}
+
 // May crash if the instrumentation is reckless.
 func TestNoRaceEnoughRegisters(t *testing.T) {
 	// from erf.go
diff --git a/src/pkg/runtime/race/testdata/regression_test.go b/src/pkg/runtime/race/testdata/regression_test.go
index afe8cc5..f08ee3e 100644
--- a/src/pkg/runtime/race/testdata/regression_test.go
+++ b/src/pkg/runtime/race/testdata/regression_test.go
@@ -45,6 +45,18 @@
 	_ = len(*m[0])
 }
 
+func TestRaceUnaddressableMapLen(t *testing.T) {
+	m := make(map[int]map[int]int)
+	ch := make(chan int, 1)
+	m[0] = make(map[int]int)
+	go func() {
+		_ = len(m[0])
+		ch <- 0
+	}()
+	m[0][0] = 1
+	<-ch
+}
+
 type Rect struct {
 	x, y int
 }
diff --git a/src/pkg/runtime/race/testdata/slice_test.go b/src/pkg/runtime/race/testdata/slice_test.go
index 7734636..1fe051b 100644
--- a/src/pkg/runtime/race/testdata/slice_test.go
+++ b/src/pkg/runtime/race/testdata/slice_test.go
@@ -463,3 +463,24 @@
 	s[9] = 42
 	<-c
 }
+
+func TestRaceConcatString(t *testing.T) {
+	s := "hello"
+	c := make(chan string, 1)
+	go func() {
+		c <- s + " world"
+	}()
+	s = "world"
+	<-c
+}
+
+func TestRaceCompareString(t *testing.T) {
+	s1 := "hello"
+	s2 := "world"
+	c := make(chan bool, 1)
+	go func() {
+		c <- s1 == s2
+	}()
+	s1 = s2
+	<-c
+}