Skip to content

Commit

Permalink
runtime/race: implement race detector for ppc64le
Browse files Browse the repository at this point in the history
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 golang#24354, golang#23731

Change-Id: Ib97dc7ac313e6313c836dc7d2fb698f9d8fba3ef
Reviewed-on: https://go-review.googlesource.com/107935
Run-TryBot: Lynn Boger <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Bryan C. Mills <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
  • Loading branch information
laboger authored and bradfitz committed Jun 11, 2018
1 parent 1de0dcf commit 9e9ff56
Show file tree
Hide file tree
Showing 13 changed files with 622 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/cmd/compile/internal/gc/builtin.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/cmd/compile/internal/gc/builtin/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128)

// race detection
func racefuncenter(uintptr)
func racefuncenterfp()
func racefuncexit()
func raceread(uintptr)
func racewrite(uintptr)
Expand Down
27 changes: 17 additions & 10 deletions src/cmd/compile/internal/gc/racewalk.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/types"
"cmd/internal/src"
"cmd/internal/sys"
)

// The racewalk pass is currently handled in two parts.
Expand Down Expand Up @@ -58,17 +59,23 @@ func instrument(fn *Node) {
lno := lineno
lineno = src.NoXPos

// nodpc is the PC of the caller as extracted by
// getcallerpc. We use -widthptr(FP) for x86.
// BUG: this will not work on arm.
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))
if thearch.LinkArch.Arch == sys.ArchPPC64LE {
fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil))
fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
} else {

// 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
}
}
6 changes: 3 additions & 3 deletions src/cmd/dist/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ func (t *tester) registerStdTest(pkg string) {
break
}
}

args := []string{
"test",
short(),
Expand Down Expand Up @@ -355,7 +354,8 @@ func (t *tester) registerRaceBenchTest(pkg string) {
"test",
short(),
"-race",
"-run=^$", // nothing. only benchmarks.
t.timeout(1200), // longer timeout for race with benchmarks
"-run=^$", // nothing. only benchmarks.
"-benchtime=.1s",
"-cpu=4",
}
Expand Down Expand Up @@ -1318,7 +1318,7 @@ func (t *tester) raceDetectorSupported() bool {
case "linux", "darwin", "freebsd", "windows":
// The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481
return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux()
return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux()
}
return false
}
Expand Down
13 changes: 9 additions & 4 deletions src/cmd/go/internal/work/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,16 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2)
}
if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") {
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
os.Exit(2)
if cfg.BuildRace {
platform := cfg.Goos + "/" + cfg.Goarch
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"
if cfg.BuildMSan {
mode = "msan"
Expand Down
16 changes: 10 additions & 6 deletions src/cmd/internal/obj/ppc64/obj9.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
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
// the frame size is too large. The link register must be saved
// even for non-empty leaf functions so that traceback works.
Expand Down Expand Up @@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retTarget := p.To.Sym

if c.cursym.Func.Text.Mark&LEAF != 0 {
if autosize == 0 {
if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
p.As = ABR
p.From = obj.Addr{}
if retTarget == nil {
Expand Down Expand Up @@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.Link = q
p = q
}

if autosize != 0 {
prev := p
if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
q = c.newprog()
q.As = AADD
q.Pos = p.Pos
Expand All @@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = -autosize

q.Link = p.Link
p.Link = q
prev.Link = q
prev = q
}

q1 = c.newprog()
Expand All @@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.Spadj = +autosize

q1.Link = q.Link
q.Link = q1
prev.Link = q1
case AADD:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
Expand Down
7 changes: 7 additions & 0 deletions src/cmd/link/internal/ld/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
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).
switch ctxt.BuildMode {
case BuildModeCArchive:
Expand Down
4 changes: 2 additions & 2 deletions src/race.bash
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
set -e

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
}

Expand All @@ -21,7 +21,7 @@ case $(uname) in
fi
;;
"Linux")
if [ $(uname -m) != "x86_64" ]; then
if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ]; then
usage
fi
;;
Expand Down
1 change: 1 addition & 0 deletions src/runtime/asm_ppc64x.s
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
// create istack out of the given (operating system) stack.
// _cgo_init may update stackguard.
MOVD $runtime·g0(SB), g
BL runtime·save_g(SB)
MOVD $(-64*1024), R31
ADD R31, R1, R3
MOVD R3, g_stackguard0(g)
Expand Down
1 change: 1 addition & 0 deletions src/runtime/race.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ var racearenastart uintptr
var racearenaend uintptr

func racefuncenter(uintptr)
func racefuncenterfp()
func racefuncexit()
func racereadrangepc1(uintptr, uintptr, uintptr)
func racewriterangepc1(uintptr, uintptr, uintptr)
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/race/race.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// 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

Expand Down
Loading

0 comments on commit 9e9ff56

Please sign in to comment.