Commit 9e9ff565 authored by Lynn Boger's avatar Lynn Boger Committed by Brad Fitzpatrick

runtime/race: implement race detector for ppc64le

This adds the support to enable the race detector for ppc64le.

Added runtime/race_ppc64le.s to manage the calls from Go to the
LLVM tsan functions, mostly converting from the Go ABI to the
PPC64 ABI expected by Clang generated code.

Changed racewalk.go to call racefuncenterfp instead of racefuncenter
on ppc64le to allow the caller pc to be obtained in the asm code
before calling the tsan version.

Changed the set up code for racecallbackthunk so it doesn't use
the autogenerated save and restore of the link register since that
sequence uses registers inconsistent with the normal ppc64 ABI.

Made various changes to recognize that race is supported for
ppc64le.

Ensured that tls_g is updated and accessible from race_linux_ppc64le.s
so that the race ctx can be obtained and passed to tsan functions.

This enables the race tests for ppc64le in cmd/dist/test.go and
increases the timeout when running the benchmarks with the -race
option to avoid timing out.

Updates #24354, #23731

Change-Id: Ib97dc7ac313e6313c836dc7d2fb698f9d8fba3ef
Reviewed-on: https://go-review.googlesource.com/107935
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 1de0dcfc
...@@ -141,6 +141,7 @@ var runtimeDecls = [...]struct { ...@@ -141,6 +141,7 @@ var runtimeDecls = [...]struct {
{"uint32tofloat64", funcTag, 109}, {"uint32tofloat64", funcTag, 109},
{"complex128div", funcTag, 110}, {"complex128div", funcTag, 110},
{"racefuncenter", funcTag, 111}, {"racefuncenter", funcTag, 111},
{"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5}, {"racefuncexit", funcTag, 5},
{"raceread", funcTag, 111}, {"raceread", funcTag, 111},
{"racewrite", funcTag, 111}, {"racewrite", funcTag, 111},
......
...@@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128) ...@@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128)
// race detection // race detection
func racefuncenter(uintptr) func racefuncenter(uintptr)
func racefuncenterfp()
func racefuncexit() func racefuncexit()
func raceread(uintptr) func raceread(uintptr)
func racewrite(uintptr) func racewrite(uintptr)
......
...@@ -7,6 +7,7 @@ package gc ...@@ -7,6 +7,7 @@ package gc
import ( import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src" "cmd/internal/src"
"cmd/internal/sys"
) )
// The racewalk pass is currently handled in two parts. // The racewalk pass is currently handled in two parts.
...@@ -58,17 +59,23 @@ func instrument(fn *Node) { ...@@ -58,17 +59,23 @@ func instrument(fn *Node) {
lno := lineno lno := lineno
lineno = src.NoXPos lineno = src.NoXPos
// nodpc is the PC of the caller as extracted by if thearch.LinkArch.Arch == sys.ArchPPC64LE {
// getcallerpc. We use -widthptr(FP) for x86. fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil))
// BUG: this will not work on arm. fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
nodpc := nodfp.copy() } else {
nodpc.Type = types.Types[TUINTPTR]
nodpc.Xoffset = int64(-Widthptr)
fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
// nodpc is the PC of the caller as extracted by
// getcallerpc. We use -widthptr(FP) for x86.
// BUG: This only works for amd64. This will not
// work on arm or others that might support
// race in the future.
nodpc := nodfp.copy()
nodpc.Type = types.Types[TUINTPTR]
nodpc.Xoffset = int64(-Widthptr)
fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
}
lineno = lno lineno = lno
} }
} }
...@@ -312,7 +312,6 @@ func (t *tester) registerStdTest(pkg string) { ...@@ -312,7 +312,6 @@ func (t *tester) registerStdTest(pkg string) {
break break
} }
} }
args := []string{ args := []string{
"test", "test",
short(), short(),
...@@ -355,7 +354,8 @@ func (t *tester) registerRaceBenchTest(pkg string) { ...@@ -355,7 +354,8 @@ func (t *tester) registerRaceBenchTest(pkg string) {
"test", "test",
short(), short(),
"-race", "-race",
"-run=^$", // nothing. only benchmarks. t.timeout(1200), // longer timeout for race with benchmarks
"-run=^$", // nothing. only benchmarks.
"-benchtime=.1s", "-benchtime=.1s",
"-cpu=4", "-cpu=4",
} }
...@@ -1318,7 +1318,7 @@ func (t *tester) raceDetectorSupported() bool { ...@@ -1318,7 +1318,7 @@ func (t *tester) raceDetectorSupported() bool {
case "linux", "darwin", "freebsd", "windows": case "linux", "darwin", "freebsd", "windows":
// The race detector doesn't work on Alpine Linux: // The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481 // golang.org/issue/14481
return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux() return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux()
} }
return false return false
} }
......
...@@ -43,11 +43,16 @@ func instrumentInit() { ...@@ -43,11 +43,16 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2) os.Exit(2)
} }
if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") { if cfg.BuildRace {
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) platform := cfg.Goos + "/" + cfg.Goarch
os.Exit(2) switch platform {
default:
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
os.Exit(2)
case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "darwin/amd64", "windows/amd64":
// race supported on these platforms
}
} }
mode := "race" mode := "race"
if cfg.BuildMSan { if cfg.BuildMSan {
mode = "msan" mode = "msan"
......
...@@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q = c.stacksplit(q, autosize) // emit split check q = c.stacksplit(q, autosize) // emit split check
} }
if autosize != 0 { // Special handling of the racecall thunk. Assume that its asm code will
// save the link register and update the stack, since that code is
// called directly from C/C++ and can't clobber REGTMP (R31).
if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
// Save the link register and update the SP. MOVDU is used unless // Save the link register and update the SP. MOVDU is used unless
// the frame size is too large. The link register must be saved // the frame size is too large. The link register must be saved
// even for non-empty leaf functions so that traceback works. // even for non-empty leaf functions so that traceback works.
...@@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retTarget := p.To.Sym retTarget := p.To.Sym
if c.cursym.Func.Text.Mark&LEAF != 0 { if c.cursym.Func.Text.Mark&LEAF != 0 {
if autosize == 0 { if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
p.As = ABR p.As = ABR
p.From = obj.Addr{} p.From = obj.Addr{}
if retTarget == nil { if retTarget == nil {
...@@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.Link = q p.Link = q
p = q p = q
} }
prev := p
if autosize != 0 { if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
q = c.newprog() q = c.newprog()
q.As = AADD q.As = AADD
q.Pos = p.Pos q.Pos = p.Pos
...@@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = -autosize q.Spadj = -autosize
q.Link = p.Link q.Link = p.Link
p.Link = q prev.Link = q
prev = q
} }
q1 = c.newprog() q1 = c.newprog()
...@@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.Spadj = +autosize q1.Spadj = +autosize
q1.Link = q.Link q1.Link = q.Link
q.Link = q1 prev.Link = q1
case AADD: case AADD:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset) p.Spadj = int32(-p.From.Offset)
......
...@@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { ...@@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
return true, objabi.GOARCH + " does not support internal cgo" return true, objabi.GOARCH + " does not support internal cgo"
} }
// When the race flag is set, the LLVM tsan relocatable file is linked
// into the final binary, which means external linking is required because
// internal linking does not support it.
if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
return true, "race on ppc64le"
}
// Some build modes require work the internal linker cannot do (yet). // Some build modes require work the internal linker cannot do (yet).
switch ctxt.BuildMode { switch ctxt.BuildMode {
case BuildModeCArchive: case BuildModeCArchive:
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
set -e set -e
function usage { function usage {
echo 'race detector is only supported on linux/amd64, freebsd/amd64 and darwin/amd64' 1>&2 echo 'race detector is only supported on linux/amd64, linux/ppc64le, freebsd/amd64 and darwin/amd64' 1>&2
exit 1 exit 1
} }
...@@ -21,7 +21,7 @@ case $(uname) in ...@@ -21,7 +21,7 @@ case $(uname) in
fi fi
;; ;;
"Linux") "Linux")
if [ $(uname -m) != "x86_64" ]; then if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ]; then
usage usage
fi fi
;; ;;
......
...@@ -24,6 +24,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 ...@@ -24,6 +24,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
// create istack out of the given (operating system) stack. // create istack out of the given (operating system) stack.
// _cgo_init may update stackguard. // _cgo_init may update stackguard.
MOVD $runtime·g0(SB), g MOVD $runtime·g0(SB), g
BL runtime·save_g(SB)
MOVD $(-64*1024), R31 MOVD $(-64*1024), R31
ADD R31, R1, R3 ADD R31, R1, R3
MOVD R3, g_stackguard0(g) MOVD R3, g_stackguard0(g)
......
...@@ -292,6 +292,7 @@ var racearenastart uintptr ...@@ -292,6 +292,7 @@ var racearenastart uintptr
var racearenaend uintptr var racearenaend uintptr
func racefuncenter(uintptr) func racefuncenter(uintptr)
func racefuncenterfp()
func racefuncexit() func racefuncexit()
func racereadrangepc1(uintptr, uintptr, uintptr) func racereadrangepc1(uintptr, uintptr, uintptr)
func racewriterangepc1(uintptr, uintptr, uintptr) func racewriterangepc1(uintptr, uintptr, uintptr)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64 // +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le
package race package race
......
This diff is collapsed.
...@@ -46,4 +46,4 @@ TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0 ...@@ -46,4 +46,4 @@ TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0
MOVD 0(R13)(R31*1), g MOVD 0(R13)(R31*1), g
RET RET
GLOBL runtime·tls_g+0(SB), TLSBSS, $8 GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment