-
Notifications
You must be signed in to change notification settings - Fork 221
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
Remove use of atomic_load_unordered
and undefined behaviour from arm_linux.rs
#790
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't comment on the inline asm attributes, but the rest LGTM.
__kuser_cmpxchg
is a bit questionable since oldval
and newval
seem like they must be able to hold provenance, but u32
is the wrong type for that. It would be more correct to use MaybeUninit<u32>
.
src/arm_linux.rs
Outdated
/// # Safety | ||
/// | ||
/// `ptr` must be aligned and point to memory within a page that allows read access. | ||
/// If `T` has a size of 4, then `ptr` must be valid for an atomic read. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// If `T` has a size of 4, then `ptr` must be valid for an atomic read. | |
/// If `T` has a size of 4, then `ptr` must be valid for a relaxed atomic read. |
However, I am a bit confused about what extra requirements you have in mind here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When T
has a size of 4
, the method loads the value using AtomicU32::from_ptr(ptr).load(Ordering::Relaxed)
instead of inline ASM. AtomicU32::from_ptr(ptr).load(Ordering::Relaxed)
, has greater safety requirements than "ptr
must be aligned and point to memory within a page that allows read access" (i.e. the read must be valid under the Rust memory model, as opposed to just not segfaulting), so I was trying to state that the caller must uphold those stricter requirements when size_of::<T>() == 4
. I've added more documentation to try and clarify this; let me know if you think it could be clarified further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like an implementation detail of the function.
I'd expect the safety contract to be something like
ptr
must be 4-aligned (currently it just says "aligned" but it is ambiguous how aligned -- is 4 even correct?)- this implies that a 4-byte range cannot cross a page boundary, so that part need not be mentioned in the docs, it becomes part of the SAFETY comment for the asm block
T
must have a size of at most 4ptr
must be valid for a relaxed atomic read of sizesize_of::<T>()
Whether and when it uses atomics vs inline asm does not have to be exposed in the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the safety section and comment.
9da124b
to
0031ae4
Compare
The 4 byte functions like |
Also I think it would be OK to use |
Ah, I had not thought of that part yet, I was more concerned of the data that is outside the value we conceptually operate on -- there might be pointers there we have to preserve. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes here LGTM with some of the minor docs updates Ralf mentioned at #790 (comment), and possibly a mention somewhere that the read is atomic without ordering. I double checked that ldr
is all LLVM emits anyway in this case https://rust.godbolt.org/z/cerYKhKd8.
"Without ordering" sounds like a non-atomic read. Is that enough?
|
At least on this target, probably, but isn't this an AM vs. hardware difference? E.g. as I understand it LLVM could decide to turn a non-atomic |
This has to be an atomic load since otherwise there could be UB due to a data race. After all, this is allowed to race with concurrent (atomic) stores. So the comment should say that this acts like a relaxed atomic load. (There is no such thing as an "atomic load without ordering".) |
Rebased to fix merge conflict. |
Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: rust-lang/compiler-builtins#789 [2]: rust-lang/compiler-builtins#790
Update `compiler-builtins` to 0.1.152 Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: rust-lang/compiler-builtins#789 [2]: rust-lang/compiler-builtins#790
Unfortunately it looks like this is hitting the monomorphization error for Android rust-lang/rust#138771 (comment). I guess this file may not be covered in CI at all, given it is only used for very old arm compiler-builtins/compiler-builtins/build.rs Lines 75 to 84 in e49ff02
|
I thought calling generic functions is fine since they get inlined anyway? What does "cannot call functions through upstream monomorphizations" mean? |
I don't really understand what the exact restrictions are, @saethlin would know better. But in this case Manually inlining the |
Ah ofc the atomic types are all monomorphic. So I understand now why it errors, but still can't make sense of the error message. |
Currently this cannot be inlined, which among other things means it can't be used in `compiler-builtins` [1]. These are trivial functions that should be inlineable, so add `#[inline]`. [1]: rust-lang/compiler-builtins#790 (comment)
It comes from an internal detail https://github.com/rust-lang/rust/blob/a4a11aca5ecf24dfff3c00715641026809951305/compiler/rustc_codegen_ssa/src/base.rs#L851. But yeah, I'm not sure what the significance of "upstream monomorphization" is instead of "non-inlinable call" or whatever. |
Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: rust-lang/compiler-builtins#789 [2]: rust-lang/compiler-builtins#790
Currently this cannot be inlined, which among other things means it can't be used in `compiler-builtins` [1]. These are trivial functions that should be inlineable, so add `#[inline]`. [1]: rust-lang/compiler-builtins#790 (comment) (cherry picked from commit eb2a2f8)
Update `compiler-builtins` to 0.1.152 Includes the following changes related to unordered atomics: * Remove element_unordered_atomic intrinsics [1] * Remove use of `atomic_load_unordered` and undefined behaviour [2] There are a handful of other small changes, but nothing else user-visible. [1]: rust-lang/compiler-builtins#789 [2]: rust-lang/compiler-builtins#790 try-job: arm-android
…=RalfJung Allow inlining for `Atomic*::from_ptr` Currently this cannot be inlined, which among other things means it can't be used in `compiler-builtins` [1]. These are trivial functions that should be inlineable, so add `#[inline]`. [1]: rust-lang/compiler-builtins#790 (comment)
Because whether a call is non-inlinable (note that "non-inlinable call" isn't even a concept we have in the compiler) is not strictly the same as whether it is to an upstream monomorphization. Calls to upstream monomorphizations can still be inlined or otherwise optimized away by the codegen backend, and the point of this diagnostic is that we don't take that into consideration. So we could change the error to say "compiler-builtins can only make calls to functions defined in compiler-builtins or functions which are defined in other crates but lowered from MIR as part of compiling compiler-builtins" but that's just including the definition of "upstream monomorphization" in the diagnostic 🤷 |
That would still be useful, given that hardly anyone knows what an "upstream monomorphization" is.^^ I did non-trivial work on the monomorphization logic, and I never encountered that term, and did not understand it when encountering it here. |
atomic_load_unordered
is in the process of being removed (#788), so replace it with a relaxed atomic load. Additionally, avoid doing an out-of-bounds Rust read (#559) on 1 and 2 byte atomics by using inline ASM.The only changes to the resulting optimised assembly on the latest Rust nightly (
rustc 1.87.0-nightly (665025243 2025-03-11)
) are a few minor changes to instruction scheduling in the 1 and 2 byte atomic RMW functions.cc @RalfJung - I've tried to summarise the approach of using inline ASM in the
SAFETY
comments, but would definitely appreciate someone checking they make sense.