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
gccgo: MemmoveAtomicity fails on ppc64x since it uses C's memmove #41428
Comments
That's unfortunate. It is somewhat surprising that C memmove breaks word boundary, even the thing we move is a multiple of word size and well aligned... |
I'm not really involved with what goes into glibc for each ISA and distro. Sometimes for a distro they want to chose a version that will work on multiple ISAs, and different ISAs might have different alignment requirements so that all affects its implementation. However the main point is that libc's memmove has no guarantee of atomicity of pointer copies so when it is implemented that is not taken into consideration. Having said that, I looked at the Go language definition and I don't see where it mentions that pointers are always aligned either. So couldn't there be a pointer within a struct that is unaligned because of the size of the previous structure members? I'm looking at the Go Programming Language document, at the very end where it says "size and alignment guarantees". |
We don't provide any alignment guarantees on pointers to the user. |
It is deeply baked in the runtime that pointers are aligned. If it is not, everything will go wrong. The compiler ensures pointers are aligned. |
@ianlancetaylor Would it be possible to add (power) asm implementations of memove and memclr to gccgo that are similar to those implementations in golang? |
Sure, it's possible. We have one piece of assembler code already in runtime/go-context.S. Of course it will be necessary to change the frontend to call those functions where appropriate, which may mean losing some compiler optimizations. That said, I haven't looked into this issue, and I'm somewhat flabbergasted that the C library memmove function doesn't do the right thing. As far as I can see the natural way to write memmove on PPC64 would copy a pointer at a time. Any idea why that doesn't happen? |
This is my impression as well. Kind of surprising.
Maybe it is possible to play some symbol shadowing trick? In the frontend we still lower to __builtin_memmove and when the backend decides to generate an actual memmove call, our symbol shadows the libc symbol? Not sure if it would work. Also not sure about all build modes... (Kind of ugly anyway.) |
There is no requirement that the memmove in libc ensure pointer atomicity, so they wouldn't have tested for it. On previous ISAs the alignment requirements varied, so that moving 8-bytes required certain alignment either for performance or correctness. In the memmove for the distro they wanted an implementation that would work for several instruction sets. In some cases doing 2 4-byte moves was as good as an 8-byte move if they didn't have to check for alignment. |
OK, thanks. It's fine with me to add assembler code for the PPC memmove, as long as on other platforms we continue to call |
We are also seeing this failure in issue13160.go intermittently, which I believe is the same issue:
|
@ianlancetaylor What is your recommendation where the ppc64 asm implementation for memmove belongs? |
I think libgo/runtime is probably the right place. |
Sir, I have a issue like this... I wonder how long does it take to be implemented? |
I'm not going to commit to a date on this at this point. What gcc release are you using and do you need it for big or little endian? |
I am using gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 and little endian. |
@ianlancetaylor I don't want to break older BE ISAs (< power7) but if I port over the Golang memmove to ppc64asm I don't know if it will work there and I have no way to test those. I assume it would be OK to use libc memmove for < power7 and the new asm for >= power7 so the old ones continue to work the same? Also I suspect the memmove atomicity isn't broken for < power7 but again can't test that. |
It's OK with me to only use the new assembler code on newer processors. We could also just write the code in C. Or switch between C and assembler based on the processor. |
If this was written in C then that should work on all processors and no need to switch back and forth. |
I would be fine with a C implementation but it might not be the fastest possible. |
@ianlancetaylor Sir, are you going to fix this bug(memmove in glibc)? |
@Helflym Is this an issue on AIX for gccgo? |
@ianlancetaylor I haven't had to update Makefiles or configure files in gcc for a while, so maybe I'm doing something wrong. If I regenerate the configure file in libgo from configure.ac using autoconf it doesn't match what's in master.
If I add a new file go-memmove.c and only use it for PPC64 then it looks like I have to update configure.ac, regenerate configure, and update Makefile.in. |
@laboger Honestly no idea. I don't think so. As long as you stay with C code, it should work. I'll have to check if the test is failing in first instance too. I haven't run gccgo testsuite for a while. |
@Helflym I was mainly wondering if the fix should be done for AIX too. I think the answer is yes. |
@laboger I think too. If it doesn't work, I'll revert for AIX. But I see no disadvantage to have a internal memmove instead of calling a libc version. Especially on AIX where libcalls are expensives. |
@laboger You have to use an unpatched version of autoconf 2.69. Unfortunately distros often patch autoconf, so you can't use a distro autoconf, you have to build it yourself. That said, I can fix this up for you. |
@ianlancetaylor I'm working on a fix for memmove which I believe works but now the test fails because of memclrNoHeapPointers which uses memset. Based on the function name I had assumed that it didn't require 8-byte atomicity, but the test expects it. Where are these requirements documented? |
Unfortunately I doubt that they are documented anywhere. |
memclrNoHeapPointers does need pointer atomicity, because it is the underlying implementation of memclrHasPointers (which is write barrier + memclrNoHeapPointers). We probably want to document it somewhere. |
Change https://golang.org/cl/287692 mentions this issue: |
memclrNoHeapPointers is the underlying implementation of typedmemclr and memclrHasPointers, so it still needs to write pointer-aligned words atomically. Document this requirement. Updates #41428. Change-Id: Ice00dee5de7a96a50e51ff019fcef069e8a8406a Reviewed-on: https://go-review.googlesource.com/c/go/+/287692 Trust: Cherry Zhang <cherryyz@google.com> Reviewed-by: Keith Randall <khr@golang.org>
I think the solution for this is to have Power asm versions of both memmove and memclr. We can't have a C memclr because the libc memset doesn't ensure 8 byte atomicity and the compiler will in some cases determine that C code could be done by the memset builtin and use that. If memset must be asm then might as well do memmove also. Changed my mind again -- better to use C. |
Change https://golang.org/cl/294931 mentions this issue: |
Go requires that pointer moves are done 8 bytes at a time, but gccgo uses libc's memmove and memset which does not require that, and there are some cases where an 8 byte move might be done as 4+4. To enforce 8 byte moves for memmove and memset, this adds a C implementation in libgo/runtime for memmove and memset to be used on ppc64le and ppc64. Asm implementations were considered but discarded to avoid different implementations for different target ISAs. Fixes golang/go#41428 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/294931
In the testing of gccgo runtime package on ppc64le and ppc64 we are seeing this error:
This has been happening since the addition of the MemmoveAtomicity test, but has been hidden because of a segv in other runtime tests which prevented all the runtime tests from running. For some reason this now shows up intermittently in the libgo.log.
According to this CL https://go-review.googlesource.com/c/go/+/213418/ it is understood that while Go's memmove copies pointers atomically, but C's memmove does not have that guarantee, and gccgo is using libc's memmove at least on ppc64le/ppc64.
The text was updated successfully, but these errors were encountered: