New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime/cgo: crosscall2 must save all callee-saved registers (xmm, VFP, etc.) #14876
Comments
Apparently its not just gcc, Wikipedia has this to say:
|
memmove is ok as the it's using Go ABI (all registers are caller-save.) The problem is in cgo callback code (crosscall2): it should also save I can see that our arm version also fails to save vfp registers (s16-s31 Only ppc64x is correct in this regard. However, the problem is that on |
CL https://golang.org/cl/21085 mentions this issue. |
CL https://golang.org/cl/21084 mentions this issue. |
For #14876. Change-Id: I33947f74e8058437a784862f1f064974afc99250 Reviewed-on: https://go-review.googlesource.com/21084 Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
For #14876. Change-Id: I0992859264cbaf9c9b691fad53345bbb01b4cf3b Reviewed-on: https://go-review.googlesource.com/21085 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This sucks but it has been broken for many releases. I think it can wait until Go 1.7 to release a fix. |
(Unless someone wants to explain why this is a regression since Go 1.5, which it appears not to be.) |
The only remaining part of this issue is to fix ARM.
But for that, we need to figure out a way how to compile
different code based on the value of $GOARM. Or we.can
penalize GOARM=5 even more by always saving the VFP
registers, but that means cgo callbacks will be even slower
on GOARM=5 programs. Do we care?
|
CL https://golang.org/cl/23140 mentions this issue. |
Glad we fixed the others. Let's leave ARM for another day. |
This was a bastard to diagnose. To summarise:
memmove_amd64.s
clobbers these registers in some cases without restoring their original values (specifically the 65 through 256 byte cases)For pure go code this is perhaps a non-issue. In my case I have a long-lived C thread (spawned by portaudio) repeatedly calling back into go. After two days debugging it has become apparent that gcc is using XMM6 for a certain floating-point calculation, and is expecting the register to remain unmodified after executing the callback (which seems to be within its rights according to the MSDN link).
However my go code calls the builtin
copy
. At some stage it tries to copy 66 bytes, causing memmove to clobber XMM6. Once the callback returns the C code keeps referring to XMM6 in further floating point operations, producing garbage.This particular set of circumstances has left me unable to create a simple reproducer (my workspace is currently full of debugging hacks at every level), but I am entirely satisfied with this explanation. I've observed XMM6 being clobbered after the callback via gcc, and any of the following changes cause the symptom to disappear:
copy
is of the same size (2,304 bytes)copy
invocationJBE move_65through128
andJBE move_129through256
lines inmemmove_amd64.s
printf
to the C function (even if the condition is never met at runtime - presumably gcc decides storing the value in a register is no longer worth it?)gdb's register info before the callback:
ie.
float64(xmm6) = 13663.434856085598
which is inline with previous timings reported by my program:After the callback does its 66-byte memmove, gdb says:
After accounting for endianness this exactly matches the last 32 bytes in the buffer I passed to
copy
. So there is little doubt left as to what is happening - the only remaining question is whether gcc is in error for expecting the register to remain unchanged, or go is in error for not restoring the register's value. As I said earlier it looks like go's fault, but I am not an expert in this area and a single MSDN article is perhaps not entirely authoritative.I'm going to take a break from this problem now and enjoy the rest of my weekend, but happy to provide further information/prepare a minimal-as-possible reproducer as desired.
For completeness, my environment details:
What version of Go are you using (
go version
)?(I've mainly been using 1.3.3 but have confirmed the problem still exists in 1.6)
What operating system and processor architecture are you using (
go env
)?The text was updated successfully, but these errors were encountered: