Repository: go
Issue: cmd/compile: rewrite sequences of mutex calls
Labels: NeedsInvestigation,compiler/runtime

Just a random idea that may be worth considering. It should be safe (at least on amd64) for the compiler to rewrite sequences of

```golang
// var m sync.Mutex
m.Lock()
// no code between the two
m.Unlock()
```

to 

```golang
if atomic.LoadUint32(&m.state) != mutexUnlocked {
	m.Lock()
	m.Unlock()
}
```

and, similarly,

```golang
// var m sync.Mutex
m.Unlock()
// no code between the two
m.Lock()
```

to

```golang
if atomic.LoadUint32(&m.state) != mutexLocked {
	m.Unlock()
	m.Lock()
}
```

Especially the latter is used in low-priority long-running operations holding a mutex to yield to higher-priority operations, like:

```golang
m.Lock()
for ... {
	// ...
	m.Unlock() // yield
	m.Lock()
}
m.Unlock()
```

(that ideally should instead be written as follows, but that would require a much smarter compiler)

```golang
for ... {
	m.Lock()
	// ...
	m.Unlock()
}
```

The benefit being that, in the no-contention case, we would avoid two RMW atomic ops and replace it with a single atomic load from a location that is almost certainly already in cache, plus a predictable jump (in the contention case the extra load+jump would be overshadowed by the rest of the mutex machinery, so it shouldn't matter anyway). I haven't benchmarked this yet: I can do it if we're interested in adding this.

A (imperfect) search on the the GH dataset on BQ shows the following number of occurrences:

- Lock/Unlock: 365
- Unlock/Lock: 80
- RLock/RUnlock: 133
- RUnlock/RLock: 16

<details>
<summary>query</summary>

```sql
DECLARE first, second STRING;
SET (first, second) = ("Lock", "Unlock");

WITH matching_files AS (
  SELECT ANY_VALUE(files.repo_name) AS repo_name, ANY_VALUE(files.path) AS path, files.id
  FROM `bigquery-public-data.github_repos.files` AS files
  WHERE ENDS_WITH(files.path, ".go")
  AND NOT ENDS_WITH(files.path, "_test.go")
  AND NOT REGEXP_CONTAINS(files.path, r"(^|/)(vendor|Godeps|deps|_third_party)/")
  GROUP BY files.id
),
matching_contents AS (
  SELECT matching_files.repo_name, matching_files.path, contents.content
  FROM matching_files
  LEFT JOIN `bigquery-public-data.github_repos.contents` AS contents ON matching_files.id = contents.id
  WHERE REGEXP_CONTAINS( contents.content, CONCAT(r"[\r\n]\s*\S+[.]", first, r"[(][)](\s*[\r\n]{1,2})+\s*\S+[.]", second, r"[(][)]\s*[\r\n]") )
),
matches AS (
  SELECT repo_name, path, content, REGEXP_EXTRACT_ALL( content, CONCAT(r"[\r\n]\s*(\S+[.]", first, r"[(][)](?:\s*[\r\n]{1,2})+\s*\S+[.]", second, r"[(][)])\s*[\r\n]") ) AS match
  FROM matching_contents
),
flatmatches AS (
  SELECT repo_name, path, content, flatmatches AS match FROM matches, matches.match AS flatmatches
),
cleanmatches AS (
  SELECT repo_name, path, content, SPLIT(REGEXP_REPLACE(match, r"\s+", "|"), "|") AS match FROM flatmatches
),
rootmatches AS (
  SELECT repo_name, path, content, match[OFFSET(0)] AS match0, match[OFFSET(1)] AS match1 , REGEXP_REPLACE(match[OFFSET(0)], CONCAT(r"[.]", first, r"[(][)]"), "") AS root0, REGEXP_REPLACE(match[OFFSET(1)], CONCAT(r"[.]", second, r"[(][)]"), "") AS root1 FROM cleanmatches
)

SELECT repo_name, path, match0, match1, content FROM rootmatches WHERE root0 = root1
```

</details>