-
Notifications
You must be signed in to change notification settings - Fork 212
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
"Cannot select" LLVM failure due to unimplemented atomics on msp430 #441
Comments
I think the easiest way to resolve this is to make a minor change to |
@Amanieu I'll prepare a patch for this/try it out and open a PR. Eventually, the need for this for msp430 will be removed; I've asked someone familiar w/ LLVM to help me implement fences for msp430 (because I am empathetically, err, not familiar with LLVM :)). But it's prob good to gate it for others. |
I believe I see the same issue in the nightly channel with the ESP32-C3 and the = note: rust-lld: error: undefined symbol: __atomic_load_4
>>> referenced by impls.rs:98 (/cargo/registry/src/gh.neting.cc-1ecc6299db9ec823/compiler_builtins-0.1.52/src/mem/impls.rs:98)
>>> compiler_builtins-f61960a02225fda8.compiler_builtins.f451d05e-cgu.3.rcgu.o:(memcpy) in archive /usr/share/rust/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv32imc-unknown-none-elf/lib/libcompiler_builtins-f61960a02225fda8.rlib So I guess that the alternative (non-atomic) load would have to be made conditional not only for the msp430, but at least also for the RISCV ISA without atomic support. And for those, the changes will have to stick around. I tried replacing the atomic operation with |
Doesn't riscv require loads and stores to be atomic even when the atomic extension isn't implemented? From section 2.6 of the riscv spec:
(emphasis mine) The loads should be aligned and thus it should be fine to depend on the atomicity of aligned loads. In addition the fence instruction is also part of the base spec. Not that it is needed for this specific case as the unordered memory ordering is used. |
IIRC there were concerns about the compatibility between a direct instruction for load/store and libcalls for RMW operations. So LLVM just makes everything use libcalls on RISCV without A. In any case, the workaround I described ( |
I'll make sure to add a comment describing the RISCV case as well. But just to clarify for my own understanding:
If RISCV without A is preferring a libcall, shouldn't the atomic load be converted into a libcall without bombing as above? Meaning either version of the load (
I don't fully understand the issue in msp430's case, but AIUI: msp430 the ISA doesn't support hardware fences, so attempts to lower atomic ops will choke when doing so. However, msp430 LLVM also doesn't support compiler fences (I guess on the C side, there wasn't use for a fence? Idk...). So But why is an atomic load w/ unordered memory ordering requiring the backend to supply code for a fence at all, software or otherwise? I have my own ideas:
|
It doesn't try to generate a fence. It tries to generate an atomic load. Fences are only necessary to ensure a consistent view of the memory. Unordered atomic operations don't generate fences. They only need an instruction that atomically performs the operation, without needing any memory ordering restrictions. As the msp430 is single core only AFAICT, it should be possible to lower atomic loads and stores to regular loads and stores inside LLVM. It is probably that simply nobody implemented this. |
Upstream seems to want Anyways, I'm fine with the |
MSP430 does not support anything "atomic" and it's up to the IR producer to ensure that the IR is compatible with the target hardware. While it might look reasonable to expect that backend would lower unsupported stuff to anything else (e.g. libcalls or just drop atomic from the load), in practice it is not: we cannot expect that e.g. PowerPC or RISC-V backend would emulate x86 vector intrinsics :) |
@asl Rust seems to think it is the backend's responsibility to accept certain IR regardless of arch- and atomic support is one of them. I'm not making a value judgment either way- I just want my msp430 code to work :D. Would you accept compiler fence support in the msp430 LLVM backend1? If not, I'll continue to submit issues and PRs to gate msp430 behavior like this one (and get clarification from Rust upstream re: "no, msp430 is not going to implement compiler fences").
|
Well let me sincerely disagree with this. And let me amplify the issue we're talking here about. Consider the frontend will generate, say, ppc vector intrinsic. Or i256 division, or something else, because why not. Should it be a backend responsibility to take care of this? The common (unwritten contract) is no. It's up to frontend to generate the IR that is compatible with the given target (similar to ABI bits, btw). Certainly the key point here is where to draw the borderline. If this is only simple thing that just drops some bits and lowers atomic stuff to normal loads / stores, then probably it could be fine. I just do not want some generalizations and precedents :) |
No, it shouldn't handle ppc vector intrinsics as those are powerpc specific, but it should handle the platform independent vector intrinsics implemented by every other backend. In fact we recently got |
Almost certainly msp430 doesn't support these either, but you shouldn't be doing simd on an msp430 ;). I still think it's on topic for this issue to discuss what to do re: msp430 here because there's a few conflicting things going on now:
Adding |
Well, let me be clear: I'm not opposing adding few emulations here and there. But I do not see point to support every and each IR feature on msp430 :) |
Regarding the situation in This is what I understand the situation to be (please correct me if I got something wrong):
So, if |
People are not just using I hope to offer alternate lowerings as a fallback, to make it easier for backends and reduce the maintenance burden, but as the generic vector ops functionally just express operations over an array-like construct (with some qualifications so that it can be easily optimized if the backend knows how), I don't see why, in principle, such IR cannot be lowered to small devices. |
@workingjubilee I don't maintain the LLVM backend (nor am I terribly familiar w/ it, tbh), and while that's something I need to/been meaning to fix, I'm the only person right now making sure Rust on msp430 works. I simply do not have the bandwidth to learn how to add all the unimplemented IR constructs, only for my contributions to potentially get rejected by upstream.
Although, based on above, if the only missing IR constructs are compiler fences and SIMD, then I can probably get away w/ saying "this is required for stabilizing Rust support, and this is the only reason I'm implementing it." msp430 is extremely size sensitive and my own experience is loop unrolling is too expensive. I think msp430 should lower SIMD constructs to a basic loop. |
Bump compiler_builtins to 0.1.55 to bring in fixes for targets lackin… …g atomic support. This fixes a "Cannot select" LLVM error when compiling `compiler_builtins` for targets lacking atomics, like MSP430. Se rust-lang/compiler-builtins#441 for more info. This PR is a more general version of rust-lang#91248.
Bump compiler_builtins to 0.1.55 to bring in fixes for targets lackin… …g atomic support. This fixes a "Cannot select" LLVM error when compiling `compiler_builtins` for targets lacking atomics, like MSP430. Se rust-lang/compiler-builtins#441 for more info. This PR is a more general version of rust-lang#91248.
Hmm. If getting it upstreamed is a concern, then we can probably figure something out, either adjusting how we generate the IR in the first place, or even having LLVM run a "desugaring" pass for vector LLVMIR using the pass manager. |
Would you be open to supporting AtomicFence on MSP430 in the same way as the AVR backend supports it? This should allow us to use singlethread: true for MSP430 in Rust. If that sounds acceptable, I'd be happy to help with implementing it. |
cc: @asl What are your thoughts re: SIMD and AtomicFence? Are you open to those emulations? I think these are the only emulations required so that I can get |
Context
A few nights ago, CI started failing for some msp430 firmware I use to make sure that msp430 Rust code builds:
MSP430 doesn't have meaningful atomic support, so I'm not sure why code using atomics is being generated.
Bisecting
rustc
Using
cargo-bisect-rustc
, I found the range of commits where compilation started failing.searched nightlies: from nightly-2021-11-18 to nightly-2021-11-19
regressed nightly: nightly-2021-11-19
searched commits: from rust-lang/rust@c9c4b5d to rust-lang/rust@cc946fc
regressed commit: rust-lang/rust@b6f580a
bisected with cargo-bisect-rustc v0.6.0
Host triple: x86_64-unknown-linux-gnu
Reproduce with:
I further bisected manually, the actual last good commit in rust is rust-lang/rust@a3b9405 and the regression is rust-lang/rust@88f1bf7. Commit b6591c2 bumps
compiler_builtins
to0.1.52
.Bisecting
compiler_builtins
Using a nightly from before the failure started (see "Other Notes"), the first compile failure I get is with commit ce86d41. The error is quite similar to the one in the CI failures:
I believe fixing the failure in
compiler_builtins
will fix the error I'm seeing when compilingrustc
, and I would need to test locally. That said, I'm not sure what is causingcompiler_builtins
to be built anyway when I specify-Zbuild-std=core
. Doesn'tcore
have no dependencies?Solution
I'm not sure what should be done here. Can there be a gate for targets whose maximum atomic width is
0
? Although it eventually needs to be done, implementing atomic support for msp430 is unlikely right now, as I don't have the bandwidth to do it. Additionally, AIUI, Rust does not actually mandate that targets implement atomics, and that they should become noops/not available on targets without them (not just msp430).Other Notes
Environment
rustc
cargo
Circular Dependency Problems
I have to compile on msp430 using
-Zbuild-std=core
, since it's not built as part of a Rust release right now. Even if I have an older version ofcompiler_builtins
checked out, using a too-recent nightly/commit causes-Zbuild-std=core
to compilecompiler_builtins
v0.1.52
anyway as a dependency of the oldercompiler_builtins
in a fun circular dependency!The text was updated successfully, but these errors were encountered: