Ilya Leoshkevich has uploaded this change for review.
cmd,runtime: enable race detector on s390x
LLVM has SystemZ ThreadSanitizer support now [1], this patch integrates
it with golang. The biggest part is the glue code in race_s390x.s,
which is derived from race_arm64.s, and then the support needs to be
enabled in four places.
race_linux_s390x.syso is custom built from LLVM commit 12a89e14b83a.
[1] https://reviews.llvm.org/D105629
Change-Id: I1d4e51beb4042603b681e4aca9af6072879d54d6
---
M src/cmd/go/internal/work/init.go
M src/cmd/internal/sys/supported.go
M src/race.bash
M src/runtime/race/race.go
A src/runtime/race/race_linux_s390x.syso
A src/runtime/race_s390x.s
6 files changed, 397 insertions(+), 6 deletions(-)
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index 37a3e2d..59c8d2a 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -63,7 +63,7 @@
}
if cfg.BuildRace {
if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) {
- fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64\n", flag.Args()[0])
+ fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, linux/s390x, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64\n", flag.Args()[0])
base.SetExitStatus(2)
base.Exit()
}
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index 0d2bad9..e526023 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -12,7 +12,7 @@
func RaceDetectorSupported(goos, goarch string) bool {
switch goos {
case "linux":
- return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
+ return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x"
case "darwin":
return goarch == "amd64" || goarch == "arm64"
case "freebsd", "netbsd", "openbsd", "windows":
diff --git a/src/race.bash b/src/race.bash
index 81fb4be..24cdc0d 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -9,7 +9,7 @@
set -e
function usage {
- echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, openbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2
+ echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, linux/s390x, freebsd/amd64, netbsd/amd64, openbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2
exit 1
}
@@ -20,7 +20,7 @@
fi
;;
"Linux")
- if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ] && [ $(uname -m) != "aarch64" ]; then
+ if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ] && [ $(uname -m) != "aarch64" ] && [ $(uname -m) != "s390x" ]; then
usage
fi
;;
diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go
index 84050e8..bffd617 100644
--- a/src/runtime/race/race.go
+++ b/src/runtime/race/race.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64)
-// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 race,openbsd,amd64
+//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64) || (race && linux && s390x)
+// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 race,openbsd,amd64 race,linux,s390x
package race
diff --git a/src/runtime/race/race_linux_s390x.syso b/src/runtime/race/race_linux_s390x.syso
new file mode 100644
index 0000000..6545289
--- /dev/null
+++ b/src/runtime/race/race_linux_s390x.syso
Binary files differ
diff --git a/src/runtime/race_s390x.s b/src/runtime/race_s390x.s
new file mode 100644
index 0000000..d2257f2
--- /dev/null
+++ b/src/runtime/race_s390x.s
@@ -0,0 +1,391 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build race
+// +build race
+
+#include "go_asm.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// The following thunks allow calling the gcc-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the s390x calling convention.
+// Arguments are passed in R2...R6, the rest is on stack.
+// Callee-saved registers are: R6...R13, R15.
+// Temporary registers are: R0...R5, R14.
+
+// When calling racecalladdr, R1 is the call target address.
+
+// The race ctx, ThreadState *thr below, is passed in R2 and loaded in racecalladdr.
+
+// func runtime·raceread(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·raceread(SB), NOSPLIT, $0-8
+ // void __tsan_read(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_read(SB), R1
+ MOVD addr+0(FP), R3
+ MOVD R14, R4
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceRead(addr uintptr)
+TEXT runtime·RaceRead(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because raceread reads caller pc.
+ JMP runtime·raceread(SB)
+
+// func runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
+ // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_read_pc(SB), R1
+ LMG addr+0(FP), R3, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewrite(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·racewrite(SB), NOSPLIT, $0-8
+ // void __tsan_write(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_write(SB), R1
+ MOVD addr+0(FP), R3
+ MOVD R14, R4
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because racewrite reads caller pc.
+ JMP runtime·racewrite(SB)
+
+// func runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
+ // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_write_pc(SB), R1
+ LMG addr+0(FP), R3, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racereadrange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R1
+ LMG addr+0(FP), R3, R4
+ MOVD R14, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racereadrange reads caller pc.
+ JMP runtime·racereadrange(SB)
+
+// func runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R1
+ LMG addr+0(FP), R3, R5
+ // pc is an interceptor address, but TSan expects it to point to the
+ // middle of an interceptor (see LLVM's SCOPED_INTERCEPTOR_RAW).
+ ADD $2, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewriterange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R1
+ LMG addr+0(FP), R3, R4
+ MOVD R14, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racewriterange reads caller pc.
+ JMP runtime·racewriterange(SB)
+
+// func runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R1
+ LMG addr+0(FP), R3, R5
+ // pc is an interceptor address, but TSan expects it to point to the
+ // middle of an interceptor (see LLVM's SCOPED_INTERCEPTOR_RAW).
+ ADD $2, R5
+ JMP racecalladdr<>(SB)
+
+// If R3 is out of range, do nothing. Otherwise, setup goroutine context and
+// invoke racecall. Other arguments are already set.
+TEXT racecalladdr<>(SB), NOSPLIT, $0-0
+ MOVD runtime·racearenastart(SB), R0
+ CMPUBLT R3, R0, data // Before racearena start?
+ MOVD runtime·racearenaend(SB), R0
+ CMPUBLT R3, R0, call // Before racearena end?
+data:
+ MOVD runtime·racedatastart(SB), R0
+ CMPUBLT R3, R0, ret // Before racedata start?
+ MOVD runtime·racedataend(SB), R0
+ CMPUBGE R3, R0, ret // At or after racedata end?
+call:
+ MOVD g_racectx(g), R2
+ JMP racecall<>(SB)
+ret:
+ RET
+
+// func runtime·racefuncenter(pc uintptr)
+// Called from instrumented code.
+TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVD callpc+0(FP), R3
+ JMP racefuncenter<>(SB)
+
+// Common code for racefuncenter
+// R3 = caller's return address
+TEXT racefuncenter<>(SB), NOSPLIT, $0-0
+ // void __tsan_func_enter(ThreadState *thr, void *pc);
+ MOVD $__tsan_func_enter(SB), R1
+ MOVD g_racectx(g), R2
+ BL racecall<>(SB)
+ RET
+
+// func runtime·racefuncexit()
+// Called from instrumented code.
+TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
+ // void __tsan_func_exit(ThreadState *thr);
+ MOVD $__tsan_func_exit(SB), R1
+ MOVD g_racectx(g), R2
+ JMP racecall<>(SB)
+
+// Atomic operations for sync/atomic package.
+
+// Load
+
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_load(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_load(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ JMP sync∕atomic·LoadInt32(SB)
+
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+// Store
+
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_store(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_store(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ JMP sync∕atomic·StoreInt32(SB)
+
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·StoreInt64(SB)
+
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·StoreInt64(SB)
+
+// Swap
+
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ JMP sync∕atomic·SwapInt32(SB)
+
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·SwapInt64(SB)
+
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·SwapInt64(SB)
+
+// Add
+
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_fetch_add(SB), R1
+ BL racecallatomic<>(SB)
+ // TSan performed fetch_add, but Go needs add_fetch.
+ MOVW add+8(FP), R0
+ MOVW ret+16(FP), R1
+ ADD R0, R1, R0
+ MOVW R0, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_fetch_add(SB), R1
+ BL racecallatomic<>(SB)
+ // TSan performed fetch_add, but Go needs add_fetch.
+ MOVD add+8(FP), R0
+ MOVD ret+16(FP), R1
+ ADD R0, R1, R0
+ MOVD R0, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ JMP sync∕atomic·AddInt32(SB)
+
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·AddInt64(SB)
+
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·AddInt64(SB)
+
+// CompareAndSwap
+
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_compare_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-25
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_compare_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-17
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt32(SB)
+
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-25
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt64(SB)
+
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-25
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt64(SB)
+
+// Common code for atomic operations. Calls R1.
+TEXT racecallatomic<>(SB), NOSPLIT, $0
+ MOVD 24(R15), R5 // Address (arg1, after 2xBL).
+ // If we pass an invalid pointer to the TSan runtime, it will cause a
+ // "fatal error: unknown caller pc". So trigger a SEGV here instead.
+ MOVB (R5), R0
+ MOVD runtime·racearenastart(SB), R0
+ CMPUBLT R5, R0, racecallatomic_data // Before racearena start?
+ MOVD runtime·racearenaend(SB), R0
+ CMPUBLT R5, R0, racecallatomic_ok // Before racearena end?
+racecallatomic_data:
+ MOVD runtime·racedatastart(SB), R0
+ CMPUBLT R5, R0, racecallatomic_ignore // Before racedata start?
+ MOVD runtime·racedataend(SB), R0
+ CMPUBGE R5, R0, racecallatomic_ignore // At or after racearena end?
+racecallatomic_ok:
+ MOVD g_racectx(g), R2 // ThreadState *.
+ MOVD 8(R15), R3 // Caller PC.
+ MOVD R14, R4 // PC.
+ ADD $24, R15, R5 // Arguments.
+ // Tail call fails to restore R15, so use a normal one.
+ BL racecall<>(SB)
+ RET
+racecallatomic_ignore:
+ // Call __tsan_go_ignore_sync_begin to ignore synchronization during
+ // the atomic op. An attempt to synchronize on the address would cause
+ // a crash.
+ MOVD R1, R6 // Save target function.
+ MOVD R14, R7 // Save PC.
+ MOVD $__tsan_go_ignore_sync_begin(SB), R1
+ MOVD g_racectx(g), R2 // ThreadState *.
+ BL racecall<>(SB)
+ MOVD R6, R1 // Restore target function.
+ MOVD g_racectx(g), R2 // ThreadState *.
+ MOVD 8(R15), R3 // Caller PC.
+ MOVD R7, R4 // PC.
+ ADD $24, R15, R5 // Arguments.
+ BL racecall<>(SB)
+ MOVD $__tsan_go_ignore_sync_end(SB), R1
+ MOVD g_racectx(g), R2 // ThreadState *.
+ BL racecall<>(SB)
+ RET
+
+// func runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there
+// are no arguments.
+TEXT runtime·racecall(SB), NOSPLIT, $0-0
+ MOVD fn+0(FP), R1
+ MOVD arg0+8(FP), R2
+ MOVD arg1+16(FP), R3
+ MOVD arg2+24(FP), R4
+ MOVD arg3+32(FP), R5
+ JMP racecall<>(SB)
+
+// Switches SP to g0 stack and calls R1. Arguments are already set.
+TEXT racecall<>(SB), NOSPLIT, $0-0
+ BL runtime·save_g(SB) // Save g for callbacks.
+ MOVD R15, R7 // Save SP.
+ MOVD g_m(g), R8 // R8 = thread.
+ MOVD m_g0(R8), R8 // R8 = g0.
+ CMPBEQ R8, g, call // Already on g0?
+ MOVD (g_sched+gobuf_sp)(R8), R15 // Switch SP to g0.
+call: SUB $160, R15 // Allocate C frame.
+ BL R1 // Call C code.
+ MOVD R7, R15 // Restore SP.
+ RET // Return to Go.
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C
+// code. racecall has only switched SP, finish g->g0 switch by setting correct
+// g. R2 contains command code, R3 contains command-specific context. See
+// racecallback for command codes.
+TEXT runtime·racecallbackthunk(SB), NOSPLIT|NOFRAME, $0
+ STMG R6, R15, 48(R15) // Save non-volatile regs.
+ BL runtime·load_g(SB) // Saved by racecall.
+ CMPBNE R2, $0, rest // raceGetProcCmd?
+ MOVD g_m(g), R2 // R2 = thread.
+ MOVD m_p(R2), R2 // R2 = processor.
+ MVC $8, p_raceprocctx(R2), (R3) // *R3 = ThreadState *.
+ LMG 48(R15), R6, R15 // Restore non-volatile regs.
+ BR R14 // Return to C.
+rest: MOVD g_m(g), R4 // R4 = current thread.
+ MOVD m_g0(R4), g // Switch to g0.
+ SUB $24, R15 // Allocate Go frame.
+ STMG R2, R3, 8(R15) // Fill Go frame.
+ BL runtime·racecallback(SB) // Call Go code.
+ LMG 72(R15), R6, R15 // Restore non-volatile regs.
+ BR R14 // Return to C.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Bryan C. Mills, Michael Knyszek, Austin Clements, Dmitry Vyukov, Michael Pratt, Jay Conrod, Keith Randall, Michael Matloob.
1 comment:
Patchset:
Ping.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
1 comment:
Patchset:
Keith or Dmitry, you're probably the right ones to look at this.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich.
5 comments:
Patchset:
We'll need an update to golang.org/x/build/cmd/racebuild .
Then ideally race_linux_s390x.syso would be generated by racebuild so anyone can update the .syso using the builders.
racebuild should put a new line in src/runtime/race/README which we'll need to keep track of versions.
File src/runtime/race_s390x.s:
(C)
Patch Set #1, Line 367: call: SUB $160, R15 // Allocate C frame.
Why does the caller allocate a frame? Why 160?
Patch Set #1, Line 377: STMG R6, R15, 48(R15) // Save non-volatile regs.
So is the 160 space for saving callee-saved registers? Is that in the C calling convention?
Patch Set #1, Line 387: Go frame
This isn't really a full Go frame, just argument slots.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich.
Ilya Leoshkevich uploaded patch set #2 to this change.
cmd,runtime: enable race detector on s390x
LLVM has SystemZ ThreadSanitizer support now [1], this patch integrates
it with golang. The biggest part is the glue code in race_s390x.s,
which is derived from race_arm64.s, and then the support needs to be
enabled in four places.
race_linux_s390x.syso is custom built from LLVM commit 12a89e14b83a.
[1] https://reviews.llvm.org/D105629
Change-Id: I1d4e51beb4042603b681e4aca9af6072879d54d6
---
M src/runtime/race/race.go
A src/runtime/race/race_linux_s390x.syso
M src/race.bash
M src/cmd/internal/sys/supported.go
A src/runtime/race_s390x.s
5 files changed, 413 insertions(+), 3 deletions(-)
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
5 comments:
Patchset:
We'll need an update to golang.org/x/build/cmd/racebuild . […]
The racebuild change is here: https://go-review.googlesource.com/c/build/+/336511
File src/runtime/race_s390x.s:
Ack
Patch Set #1, Line 367: call: SUB $160, R15 // Allocate C frame.
Why does the caller allocate a frame? Why 160?
The ABI requires the caller to allocate a register save area for the callee.
You can find more details in chapter 1.2 / figure 1.17 of https://github.com/IBM/s390x-abi/releases.
Patch Set #1, Line 377: STMG R6, R15, 48(R15) // Save non-volatile regs.
So is the 160 space for saving callee-saved registers? Is that in the C calling convention?
Exactly, this is the C calling convention.
Patch Set #1, Line 387: Go frame
This isn't really a full Go frame, just argument slots.
Ack
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
2 comments:
File src/runtime/race_s390x.s:
Patch Set #1, Line 367: call: SUB $160, R15 // Allocate C frame.
The ABI requires the caller to allocate a register save area for the callee. […]
Done
Patch Set #1, Line 377: STMG R6, R15, 48(R15) // Save non-volatile regs.
Exactly, this is the C calling convention.
Done
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
1 comment:
Patchset:
Is there anything else that needs to be addressed?
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Patchset:
Ping.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich.
1 comment:
Patchset:
The racebuild change is here: https://go-review.googlesource. […]
When you run racebuild it should put a new line in src/runtime/race/README. That change should be in this CL (as well as the .syso it built).
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
1 comment:
Patchset:
When you run racebuild it should put a new line in src/runtime/race/README. […]
I don't think I have the permissions to actually run racebuild: https://github.com/golang/go/issues/47226
May I ask you to run it for me?
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich, Keith Randall.
Patch set 4:Run-TryBot +1
1 comment:
Patchset:
TRY=s390x
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich.
1 comment:
Patchset:
racebuild fails when I try to run it. I think apt-get doesn't work on the builder - is there some other command you use to install things like git?
$ racebuild -gorev 851ecea4cc99ab276109493477b2c7e30c253ea8 -goroot sandbox/ro -platforms linux/s390x -rev 41cb504b7c4b18ac15830107431a0c1eec73a6b2
2022/04/10 16:50:14 using Go revision: 851ecea4cc99ab276109493477b2c7e30c253ea8
2022/04/10 16:50:14 linux/s390x: gomote [create -status=false linux-s390x-ibm]
user-khr-linux-s390x-ibm-0
2022/04/10 16:50:14 linux/s390x: gomote [create -status=false linux-s390x-ibm] succeeded:
user-khr-linux-s390x-ibm-0
2022/04/10 16:50:14 linux/s390x: using instance user-khr-linux-s390x-ibm-0
2022/04/10 16:50:14 linux/s390x: gomote [put14 user-khr-linux-s390x-ibm-0]
No GoBootstrapURL defined for "user-khr-linux-s390x-ibm-0"; ignoring. (may be baked into image)
2022/04/10 16:50:15 linux/s390x: gomote [put14 user-khr-linux-s390x-ibm-0] succeeded:
No GoBootstrapURL defined for "user-khr-linux-s390x-ibm-0"; ignoring. (may be baked into image)
2022/04/10 16:50:15 linux/s390x: gomote [put -mode=0700 user-khr-linux-s390x-ibm-0 /tmp/racebuild2885521081 script.bash]
2022/04/10 16:50:15 linux/s390x: gomote [put -mode=0700 user-khr-linux-s390x-ibm-0 /tmp/racebuild2885521081 script.bash] succeeded: <no output>
2022/04/10 16:50:15 linux/s390x: gomote [run -e=REV=41cb504b7c4b18ac15830107431a0c1eec73a6b2 -e=GOREV=851ecea4cc99ab276109493477b2c7e30c253ea8 user-khr-linux-s390x-ibm-0 script.bash]
/data/golang/workdir/script.bash: line 3: apt-get: command not found
Error running run: exit status 127
2022/04/10 16:50:15 linux/s390x: gomote [run -e=REV=41cb504b7c4b18ac15830107431a0c1eec73a6b2 -e=GOREV=851ecea4cc99ab276109493477b2c7e30c253ea8 user-khr-linux-s390x-ibm-0 script.bash] failed:
/data/golang/workdir/script.bash: line 3: apt-get: command not found
Error running run: exit status 127
2022/04/10 16:50:15 linux/s390x: gomote [destroy user-khr-linux-s390x-ibm-0]
2022/04/10 16:50:15 linux/s390x: gomote [destroy user-khr-linux-s390x-ibm-0] succeeded: <no output>
2022/04/10 16:50:15 linux/s390x failed: exit status 1
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Keith Randall.
1 comment:
Patchset:
racebuild fails when I try to run it. […]
That's interesting, apparently the linux-s390x-ibm builder is not running Debian/Ubuntu. I cannot find any information about the distro that's installed there, but I assume it must be RHEL/Fedora. I will send another racebuild PR that changes apt-get to yum.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Dmitry Vyukov, Ilya Leoshkevich.
1 comment:
Patchset:
That's interesting, apparently the linux-s390x-ibm builder is not running Debian/Ubuntu. […]
Now racebuild makes it a lot farther. Not all the way, though. I think when it starts to build the race detector I get a bunch of errors:
/data/golang/workdir
Cloning into 'llvm-project'...
Updating files: 100% (114760/114760), done.
Note: switching to '41cb504b7c4b18ac15830107431a0c1eec73a6b2'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 41cb504b7c4b [mlir][linalg][bufferize][NFC] Move interface impl to Linalg Transforms
/data/golang/workdir/tmp/cceGR88V.s: Assembler messages:
/data/golang/workdir/tmp/cceGR88V.s:35718: Error: junk at end of line: `,3'
/data/golang/workdir/tmp/cceGR88V.s:35719: Error: junk at end of line: `,3'
/data/golang/workdir/tmp/cceGR88V.s:40610: Error: junk at end of line: `,3'
...
/data/golang/workdir/tmp/cceGR88V.s:198108: Error: junk at end of line: `,3'
/data/golang/workdir/tmp/cceGR88V.s:198109: Error: junk at end of line: `,3'
Error running run: exit status 1
2022/04/15 13:28:22 linux/s390x: gomote [destroy user-khr-linux-s390x-ibm-0]
2022/04/15 13:28:23 linux/s390x: gomote [destroy user-khr-linux-s390x-ibm-0] succeeded: <no output>
2022/04/15 13:28:23 linux/s390x failed: exit status 1
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Keith Randall.
1 comment:
Patchset:
Now racebuild makes it a lot farther. Not all the way, though. […]
The CL https://go-review.googlesource.com/c/build/+/399996 that included `yum install -y gcc-c++ git golang-bin` is causing https://github.com/golang/go/issues/52408 and https://github.com/golang/go/issues/52407
Those builders are still on RHEL 8.1. On RHEL, when you install newer versions of packages it will grab the latest versions from the latest minor release which is currently 8.5. I have to do more testing but I think what's happening is parts of the gcc toolchain gets updated to the RHEL 8.5 versions and some stay at the RHEL 8.1 versions.
I'm in the process of provisioning new builders to replace the current ones and they will be on the latest RHEL 8.5 but they are not ready yet.
Could https://go-review.googlesource.com/c/build/+/399996 be reverted? I can try to install g++ at the right version on the current builders and help with any other setup needed. I can also look at switching to Ubuntu for the new builders instead of staying with RHEL8.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Keith Randall.
1 comment:
Patchset:
The CL https://go-review.googlesource. […]
Hi Jonathan, sorry about causing the breakage and thanks for looking into it.
We can of course revert the change, but can we simply abstain from running racebuild on s390x until the builders are upgraded? As far as I understand, it is not used by any CI systems and was only run once by Keith as a test.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Keith Randall.
1 comment:
Patchset:
Hi Jonathan, sorry about causing the breakage and thanks for looking into it. […]
Thanks for the info on racebuild, Ilya. If there's no danger of it being run as part of CI then I agree its ok not to revert it. I'm going to see if RHEL can be pinned at a certain minor release so that `yum install -y gcc-c++ git golang-bin` won't cause problems. I wouldn't have thought it would be a problem either. I'll reply back when I know more.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Ilya Leoshkevich.
1 comment:
Patchset:
Thanks for the info on racebuild, Ilya. […]
Ok, I'll avoid running racebuild again until I hear from you.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Keith Randall.
1 comment:
Patchset:
Ok, I'll avoid running racebuild again until I hear from you.
I've installed the `gcc-c++` package at the version that matches the installed `gcc` package on the builders and the builds look fine so I think everything is in a good state now. I've pinned the versions of `gcc`, `gcc-c++`, `git` and `golang-bin` to the currently installed versions so now the `yum install -y gcc-c++ git golang-bin` won't cause any upgrades. It should be safe to run racebuild on any of the s390x builders now. Let me know if I can help in any way.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Ilya Leoshkevich.
1 comment:
Patchset:
I've installed the `gcc-c++` package at the version that matches the installed `gcc` package on the […]
Ok, thanks. I've used racebuild to make the .syso and README changes (it needed some hacking because there's a bootstrapping problem with actually testing the .syso). mailed a CL with just the runtime/race/README and runtime/race/race_linux_s390x.syso changes. You should be able to rebase this CL on top of that one and I can run some trybots to make sure things still work. Then we can submit both.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Ilya Leoshkevich.
Ilya Leoshkevich uploaded patch set #5 to this change.
cmd,runtime: enable race detector on s390x
LLVM has SystemZ ThreadSanitizer support now [1], this patch integrates
it with golang. The biggest part is the glue code in race_s390x.s,
which is derived from race_arm64.s, and then the support needs to be
enabled in four places.
[1] https://reviews.llvm.org/D105629
Change-Id: I1d4e51beb4042603b681e4aca9af6072879d54d6
---
M src/cmd/internal/sys/supported.go
M src/race.bash
M src/runtime/race/race.go
A src/runtime/race_s390x.s
4 files changed, 411 insertions(+), 3 deletions(-)
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Keith Randall.
1 comment:
Patchset:
Ok, thanks. I've used racebuild to make the . […]
Hi Keith, sorry for the delay - I see you've already submitted the .syso change. I've rebased this CL on top of the latest master; ./race.bash worked for me with your .syso. Thanks!
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Jonathan Albrecht, Ilya Leoshkevich.
Patch set 5:Run-TryBot +1Auto-Submit +1Code-Review +2
Attention is currently required from: Jonathan Albrecht, Ilya Leoshkevich.
Patch set 5:Code-Review +1
Attention is currently required from: Jonathan Albrecht.
1 comment:
Patchset:
Ping.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Jonathan Albrecht.
3 comments:
Patchset:
I don't think I have the permissions to actually run racebuild: https://github. […]
Done
Patchset:
Is there anything else that needs to be addressed?
Done
Patchset:
Ping.
Done
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Jonathan Albrecht.
1 comment:
Patchset:
I think this was blocked from being noticed for having unresolved comments. I resolved them, hopefully we'll make progress now.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Ilya Leoshkevich, Jonathan Albrecht.
Patch set 5:Code-Review +1
1 comment:
Patchset:
This is intended to satisfy review enforcement, it all looks good to me.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.
Gopher Robot submitted this change.
cmd,runtime: enable race detector on s390x
LLVM has SystemZ ThreadSanitizer support now [1], this patch integrates
it with golang. The biggest part is the glue code in race_s390x.s,
which is derived from race_arm64.s, and then the support needs to be
enabled in four places.
[1] https://reviews.llvm.org/D105629
Change-Id: I1d4e51beb4042603b681e4aca9af6072879d54d6
Reviewed-on: https://go-review.googlesource.com/c/go/+/336549
Reviewed-by: Keith Randall <k...@golang.org>
Reviewed-by: Keith Randall <k...@google.com>
Auto-Submit: Keith Randall <k...@golang.org>
TryBot-Result: Gopher Robot <go...@golang.org>
Reviewed-by: David Chase <drc...@google.com>
Run-TryBot: Keith Randall <k...@golang.org>
---
M src/cmd/internal/sys/supported.go
M src/race.bash
M src/runtime/race/race.go
A src/runtime/race_s390x.s
4 files changed, 418 insertions(+), 3 deletions(-)
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index 82b6551..d36a4ba 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -12,7 +12,7 @@
func RaceDetectorSupported(goos, goarch string) bool {
switch goos {
case "linux":
- return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
+ return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x"
case "darwin":
return goarch == "amd64" || goarch == "arm64"
case "freebsd", "netbsd", "openbsd", "windows":
diff --git a/src/race.bash b/src/race.bash
index f795ec9..f1a168b 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -9,7 +9,7 @@
set -e
function usage {
- echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, openbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2
+ echo 'race detector is only supported on linux/amd64, linux/ppc64le, linux/arm64, linux/s390x, freebsd/amd64, netbsd/amd64, openbsd/amd64, darwin/amd64, and darwin/arm64' 1>&2
exit 1
}
@@ -19,6 +19,7 @@
"Linux x86_64") ;;
"Linux ppc64le") ;;
"Linux aarch64") ;;
+ "Linux s390x") ;;
"FreeBSD amd64") ;;
"NetBSD amd64") ;;
"OpenBSD amd64") ;;
diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go
index 63fa83f..8692066 100644
--- a/src/runtime/race/race.go
+++ b/src/runtime/race/race.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64)
+//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64) || (race && linux && s390x)
package race
diff --git a/src/runtime/race_s390x.s b/src/runtime/race_s390x.s
new file mode 100644
index 0000000..beb7f83
--- /dev/null
+++ b/src/runtime/race_s390x.s
@@ -0,0 +1,391 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build race
+// +build race
+
+#include "go_asm.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// The following thunks allow calling the gcc-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the s390x C calling convention.
+// Arguments are passed in R2...R6, the rest is on stack.
+// Callee-saved registers are: R6...R13, R15.
+// Temporary registers are: R0...R5, R14.
+
+// When calling racecalladdr, R1 is the call target address.
+
+// The race ctx, ThreadState *thr below, is passed in R2 and loaded in racecalladdr.
+
+// func runtime·raceread(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·raceread(SB), NOSPLIT, $0-8
+ // void __tsan_read(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_read(SB), R1
+ MOVD addr+0(FP), R3
+ MOVD R14, R4
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceRead(addr uintptr)
+TEXT runtime·RaceRead(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because raceread reads caller pc.
+ JMP runtime·raceread(SB)
+
+// func runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
+ // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_read_pc(SB), R1
+ LMG addr+0(FP), R3, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewrite(addr uintptr)
+// Called from instrumented code.
+TEXT runtime·racewrite(SB), NOSPLIT, $0-8
+ // void __tsan_write(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_write(SB), R1
+ MOVD addr+0(FP), R3
+ MOVD R14, R4
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8
+ // This needs to be a tail call, because racewrite reads caller pc.
+ JMP runtime·racewrite(SB)
+
+// func runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
+ // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_write_pc(SB), R1
+ LMG addr+0(FP), R3, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racereadrange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R1
+ LMG addr+0(FP), R3, R4
+ MOVD R14, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racereadrange reads caller pc.
+ JMP runtime·racereadrange(SB)
+
+// func runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R1
+ LMG addr+0(FP), R3, R5
+ // pc is an interceptor address, but TSan expects it to point to the
+ // middle of an interceptor (see LLVM's SCOPED_INTERCEPTOR_RAW).
+ ADD $2, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·racewriterange(addr, size uintptr)
+// Called from instrumented code.
+TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R1
+ LMG addr+0(FP), R3, R4
+ MOVD R14, R5
+ JMP racecalladdr<>(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+ // This needs to be a tail call, because racewriterange reads caller pc.
+ JMP runtime·racewriterange(SB)
+
+// func runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R1
+ LMG addr+0(FP), R3, R5
+ // pc is an interceptor address, but TSan expects it to point to the
+ // middle of an interceptor (see LLVM's SCOPED_INTERCEPTOR_RAW).
+ ADD $2, R5
+ JMP racecalladdr<>(SB)
+
+// If R3 is out of range, do nothing. Otherwise, setup goroutine context and
+// invoke racecall. Other arguments are already set.
+TEXT racecalladdr<>(SB), NOSPLIT, $0-0
+ MOVD runtime·racearenastart(SB), R0
+ CMPUBLT R3, R0, data // Before racearena start?
+ MOVD runtime·racearenaend(SB), R0
+ CMPUBLT R3, R0, call // Before racearena end?
+data:
+ MOVD runtime·racedatastart(SB), R0
+ CMPUBLT R3, R0, ret // Before racedata start?
+ MOVD runtime·racedataend(SB), R0
+ CMPUBGE R3, R0, ret // At or after racedata end?
+call:
+ MOVD g_racectx(g), R2
+ JMP racecall<>(SB)
+ret:
+ RET
+
+// func runtime·racefuncenter(pc uintptr)
+// Called from instrumented code.
+TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVD callpc+0(FP), R3
+ JMP racefuncenter<>(SB)
+
+// Common code for racefuncenter
+// R3 = caller's return address
+TEXT racefuncenter<>(SB), NOSPLIT, $0-0
+ // void __tsan_func_enter(ThreadState *thr, void *pc);
+ MOVD $__tsan_func_enter(SB), R1
+ MOVD g_racectx(g), R2
+ BL racecall<>(SB)
+ RET
+
+// func runtime·racefuncexit()
+// Called from instrumented code.
+TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
+ // void __tsan_func_exit(ThreadState *thr);
+ MOVD $__tsan_func_exit(SB), R1
+ MOVD g_racectx(g), R2
+ JMP racecall<>(SB)
+
+// Atomic operations for sync/atomic package.
+
+// Load
+
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_load(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_load(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ JMP sync∕atomic·LoadInt32(SB)
+
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·LoadInt64(SB)
+
+// Store
+
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_store(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_store(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-12
+ GO_ARGS
+ JMP sync∕atomic·StoreInt32(SB)
+
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·StoreInt64(SB)
+
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-16
+ GO_ARGS
+ JMP sync∕atomic·StoreInt64(SB)
+
+// Swap
+
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ JMP sync∕atomic·SwapInt32(SB)
+
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·SwapInt64(SB)
+
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·SwapInt64(SB)
+
+// Add
+
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_fetch_add(SB), R1
+ BL racecallatomic<>(SB)
+ // TSan performed fetch_add, but Go needs add_fetch.
+ MOVW add+8(FP), R0
+ MOVW ret+16(FP), R1
+ ADD R0, R1, R0
+ MOVW R0, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_fetch_add(SB), R1
+ BL racecallatomic<>(SB)
+ // TSan performed fetch_add, but Go needs add_fetch.
+ MOVD add+8(FP), R0
+ MOVD ret+16(FP), R1
+ ADD R0, R1, R0
+ MOVD R0, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-20
+ GO_ARGS
+ JMP sync∕atomic·AddInt32(SB)
+
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·AddInt64(SB)
+
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
+ GO_ARGS
+ JMP sync∕atomic·AddInt64(SB)
+
+// CompareAndSwap
+
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
+ GO_ARGS
+ MOVD $__tsan_go_atomic32_compare_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-25
+ GO_ARGS
+ MOVD $__tsan_go_atomic64_compare_exchange(SB), R1
+ BL racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-17
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt32(SB)
+
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-25
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt64(SB)
+
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-25
+ GO_ARGS
+ JMP sync∕atomic·CompareAndSwapInt64(SB)
+
+// Common code for atomic operations. Calls R1.
+TEXT racecallatomic<>(SB), NOSPLIT, $0
+ MOVD 24(R15), R5 // Address (arg1, after 2xBL).
+ // If we pass an invalid pointer to the TSan runtime, it will cause a
+ // "fatal error: unknown caller pc". So trigger a SEGV here instead.
+ MOVB (R5), R0
+ MOVD runtime·racearenastart(SB), R0
+ CMPUBLT R5, R0, racecallatomic_data // Before racearena start?
+ MOVD runtime·racearenaend(SB), R0
+ CMPUBLT R5, R0, racecallatomic_ok // Before racearena end?
+racecallatomic_data:
+ MOVD runtime·racedatastart(SB), R0
+ CMPUBLT R5, R0, racecallatomic_ignore // Before racedata start?
+ MOVD runtime·racedataend(SB), R0
+ CMPUBGE R5, R0, racecallatomic_ignore // At or after racearena end?
+racecallatomic_ok:
+ MOVD g_racectx(g), R2 // ThreadState *.
+ MOVD 8(R15), R3 // Caller PC.
+ MOVD R14, R4 // PC.
+ ADD $24, R15, R5 // Arguments.
+ // Tail call fails to restore R15, so use a normal one.
+ BL racecall<>(SB)
+ RET
+racecallatomic_ignore:
+ // Call __tsan_go_ignore_sync_begin to ignore synchronization during
+ // the atomic op. An attempt to synchronize on the address would cause
+ // a crash.
+ MOVD R1, R6 // Save target function.
+ MOVD R14, R7 // Save PC.
+ MOVD $__tsan_go_ignore_sync_begin(SB), R1
+ MOVD g_racectx(g), R2 // ThreadState *.
+ BL racecall<>(SB)
+ MOVD R6, R1 // Restore target function.
+ MOVD g_racectx(g), R2 // ThreadState *.
+ MOVD 8(R15), R3 // Caller PC.
+ MOVD R7, R4 // PC.
+ ADD $24, R15, R5 // Arguments.
+ BL racecall<>(SB)
+ MOVD $__tsan_go_ignore_sync_end(SB), R1
+ MOVD g_racectx(g), R2 // ThreadState *.
+ BL racecall<>(SB)
+ RET
+
+// func runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there
+// are no arguments.
+TEXT runtime·racecall(SB), NOSPLIT, $0-0
+ MOVD fn+0(FP), R1
+ MOVD arg0+8(FP), R2
+ MOVD arg1+16(FP), R3
+ MOVD arg2+24(FP), R4
+ MOVD arg3+32(FP), R5
+ JMP racecall<>(SB)
+
+// Switches SP to g0 stack and calls R1. Arguments are already set.
+TEXT racecall<>(SB), NOSPLIT, $0-0
+ BL runtime·save_g(SB) // Save g for callbacks.
+ MOVD R15, R7 // Save SP.
+ MOVD g_m(g), R8 // R8 = thread.
+ MOVD m_g0(R8), R8 // R8 = g0.
+ CMPBEQ R8, g, call // Already on g0?
+ MOVD (g_sched+gobuf_sp)(R8), R15 // Switch SP to g0.
+call: SUB $160, R15 // Allocate C frame.
+ BL R1 // Call C code.
+ MOVD R7, R15 // Restore SP.
+ RET // Return to Go.
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C
+// code. racecall has only switched SP, finish g->g0 switch by setting correct
+// g. R2 contains command code, R3 contains command-specific context. See
+// racecallback for command codes.
+TEXT runtime·racecallbackthunk(SB), NOSPLIT|NOFRAME, $0
+ STMG R6, R15, 48(R15) // Save non-volatile regs.
+ BL runtime·load_g(SB) // Saved by racecall.
+ CMPBNE R2, $0, rest // raceGetProcCmd?
+ MOVD g_m(g), R2 // R2 = thread.
+ MOVD m_p(R2), R2 // R2 = processor.
+ MVC $8, p_raceprocctx(R2), (R3) // *R3 = ThreadState *.
+ LMG 48(R15), R6, R15 // Restore non-volatile regs.
+ BR R14 // Return to C.
+rest: MOVD g_m(g), R4 // R4 = current thread.
+ MOVD m_g0(R4), g // Switch to g0.
+ SUB $24, R15 // Allocate Go argument slots.
+ STMG R2, R3, 8(R15) // Fill Go frame.
+ BL runtime·racecallback(SB) // Call Go code.
+ LMG 72(R15), R6, R15 // Restore non-volatile regs.
+ BR R14 // Return to C.
To view, visit change 336549. To unsubscribe, or for help writing mail filters, visit settings.