-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Miscompilation on ARM-M with nightly-2021-04-23 #85351
Comments
We are having problems with Rust 1.52 on We are usually compiling with [profile.release]
codegen-units = 1
lto = true
debug = false
opt-level = "s" But we tried without specifying the opt-level and it didn't make any difference. Unfortunately I can't share the code to reproduce. |
The last toolchain bump exposed some issue with outlining, turn it off for now See rust-lang/rust#85351
The last toolchain bump exposed some issue with outlining, turn it off for now See rust-lang/rust#85351
Thanks for the heads-up and analysis. I confirm that the issue was introduced with LLVM-12 due to the last developments made on the Machine Outliner. Notice that it is only enabled under -Oz optimization level for 32-bit ARM M-profile and AArch64 targets, unless the To give you a bit more context here, Machine Outlining is a code size optimization which, in a nutshell, is the reverse of inlining (it replaces repeated sequences of instructions by function calls). In our case here, since the extracted peace of code contains a call, the link register needs to be saved on the entry of the block and restored to be able jump back to the call site, the offsets of the instruction which are using the stack are changed accordingly to reflect thios change, but it doesn't take into account that a stack pointer was saved into a register ( I'll fix the issue in LLVM and let you know the status. |
@yroux, I'm not sure this is correct. The stack pointer relative address saved in You know this algorithm better than I do, of course, so let me know if I've missed something. |
@cbiffle no sorry, you are right, I read it too quickly and I shouldn't work that late ;-) |
Assigning priority as discussed in the Zulip thread of the Prioritization Working Group. @rustbot label -I-prioritize +P-critical +T-compiler |
@TriageBot ping llvm |
Hey LLVM ICE-breakers! This bug has been identified as a good cc @camelid @comex @cuviper @DutchGhost @hdhoang @henryboisdequin @heyrutvik @higuoxing @JOE1994 @jryans @mmilenko @nagisa @nikic @Noah-Kennedy @SiavoshZarrasvand @spastorino @vertexclique |
@rustbot ping llvm |
Hey LLVM ICE-breakers! This bug has been identified as a good cc @camelid @comex @cuviper @DutchGhost @hdhoang @henryboisdequin @heyrutvik @higuoxing @JOE1994 @jryans @mmilenko @nagisa @nikic @Noah-Kennedy @SiavoshZarrasvand @spastorino @vertexclique |
A couple points: IIRC outliner is a pretty recent addition to LLVM. Also, to work on this it is going to be important to have some code that reproduces this (I'm not seeing any, please tell me if I missed anything) |
Machine Outliner initial support for ARM was added into LLVM-11, but it was improved to handled more cases (such as ld/st stack instructions involved in this issue) and enabled into -Oz for M-profile targets in LLVM-12 release. I managed to reproduce the issue on a reduce LLVM MIR test, and I'm working on a fix. |
Issue reported into llvm bugzilla: https://bugs.llvm.org/show_bug.cgi?id=50481 I hope to have it part of llvm 12.0.1 which is currently in RC1 state |
Fix commited into mainline as: https://reviews.llvm.org/rG6c78dbd4ca1f |
Disable the machine outliner by default This addresses a codegen-issue that needs to be fixed upstream in LLVM. While we wait for the fix, we can disable it. Verified manually that the outliner is no longer run when `-Copt-level=z` is specified, and also that you can override this with `-Cllvm-args=-enable-machine-outliner` if you need it anyway. A regression test is not really feasible in this instance, given that we do not have any minimal reproducers. Fixes rust-lang#85351 cc `@pnkfelix`
This addresses a codegen-issue that needs to be fixed upstream in LLVM. While we wait for the fix, we can disable it. Verified manually that the outliner is no longer run when `-Copt-level=z` is specified, and also that you can override this with `-Cllvm-args=-enable-machine-outliner` if you need it anyway. A regression test is not really feasible in this instance, given that we do not have any minimal reproducers. Fixes rust-lang#85351
Revert "Disable the machine outliner by default" The fix commit is already in the fork: rust-lang/llvm-project@6c78dbd4ca1f Linked: - rust-lang#85351 - rust-lang#86020
We are seeing a subtle occasional miscompilation on ARM-M using
nightly-2021-04-23
inrust-toolchain
. It is difficult to elicit and reproduce, since subtle changes to the layout of the code will cause the compiler to make decisions that either do or do not trigger the bug. It appears to have something to do with stack frame maintenance in outlined functions. We are definitely observing it onthumbv8m.main-none-eabihf
, but it's subtle enough that we may also be getting it onthumbv7em-none-eabihf
and just haven't noticed it yet.As of somewhat recently (late April?) output at
opt-level = "z"
has started including outlined functions that look like this (actual example):Now, note that the instructions at 0x211e6 and 0x211fe are setting up and tearing down a temporary stack frame, respectively. This will become important in a bit.
It appears that the stack frame offsets used in instructions while this temporary stack frame exists are not being updated to reflect its existence. Stack variables updated within the outlined function above are being deposited 8 bytes off where they should be.
I do not currently have a compact repro case, and the code in question has not yet been published (though I could arrange to publish it if it would help, we intend to open source it). Here are two execution traces of programs showing correct behavior vs corrupt behavior. Both traces set up arguments to a syscall, which uses struct return and deposits a struct onto the stack; the routines then shuffle the results around before calling a library function. It is during the shuffling that things go awry.
In this working trace I have called the struct return buffer in the stack frame R and another related-but-separate buffer B. I've omitted instructions that don't contribute by control flow or value-dominating the registers at the end. S refers to the value of the stack pointer on entry to the trace.
Now, here is the non-working trace with the same sort of annotations. Note that while the function at the end is still called with one argument
R
(stack frame plus 28), the actual struct being passed is deposited starting 8 bytes lower at stack frame plus 20:Additional notes:
rust-toolchain
fromnightly-2020-12-29
tonightly-2021-04-23
, so the behavior was introduced somewhere between those points. (@luqmana points out that this likely includes the LLVM 11-12 transition.)opt-level = "z"
but this may or may not be specific to that opt level.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: