Skip to content

Commit aa47150

Browse files
Mark-Simulacrumsteveklabnik
authored andcommitted
Add side effect post (#534)
1 parent 65c3037 commit aa47150

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
layout: post
3+
title: "Resolving Rust's forward progress guarantees"
4+
author: Mark Rousskov
5+
description: "Should side-effect be the fix?"
6+
team: the compiler team <https://www.rust-lang.org/governance/teams/compiler>
7+
---
8+
9+
There has been a longstanding miscompilation in Rust: programs that do not make
10+
[forward progress]. Note that the previous link is to the C++ definition; Rust
11+
is not C++, but currently LLVM optimizes all LLVM IR with the assumption that a
12+
lack of forward progress is undefined behavior.
13+
14+
Note also that Rust does not define a lack of forward progress as [undefined
15+
behavior], while C++ does. It is particularly common to encounter the
16+
miscompilation "intentionally" when writing panic handlers and other such code
17+
with a body of `loop {}`. Some users also report that they've unintentionally
18+
hit this bug in recursive code which accidentally lacks a base case.
19+
20+
Somewhat recently, LLVM added an intrinsic which tells the optimizer that
21+
forward progress has been made. On nightly Rust, you can enable this with
22+
`-Zinsert-sideeffect`, which will use some heuristics to insert it where it's
23+
possibly needed (currently, massively overshooting the minimal set).
24+
25+
However, recent attempts to enable this intrinsic by default hit a snag: it's
26+
very expensive on compile times to do so ([3-30% regressions][compile-time
27+
regressions]). There is some runtime effect as well; check builds (which do not
28+
generate LLVM IR or run LLVM passes) regressed by up to 3-7%.
29+
30+
The current implementation in rustc emits calls to the side effect intrinsic
31+
very aggressively; certainly in way more cases than is strictly necessary.
32+
However, there's not really any good ideas on how to improve the analysis rustc
33+
does without missing edge cases: we'd have to be "as good" as LLVM to emit only
34+
when necessary.
35+
36+
Upstream, in LLVM, discussion has been ongoing for some time around whether, and
37+
how to, adjust LLVM's model to permit frontends for languages like Rust to
38+
opt-out of the forward progress guarantees. It seems unlikely that a solution
39+
will materialize in upstream LLVM that allows us to opt-out in the short term.
40+
41+
However, having said that, side effect itself is likely improvable to at least
42+
avoid the excessive consecutive calls, as demonstrated by this [IR][IR-test]
43+
that occurs after LLVM optimizations. It seems plausible that those
44+
improvements may also reduce the compile time hit that we see when enabling
45+
side effect on the rustc side. Having said that, how simple these improvements
46+
are is unclear.
47+
48+
We would love to hear feedback and suggestions on how to resolve this problem!
49+
Please leave feedback on this internals thread (link to be filled in right
50+
before merging).
51+
52+
[IR-test]: https://gist.github.com/nikic/7e521def71d106c345a255e464b18d3f
53+
[compile-time regressions]: https://perf.rust-lang.org/compare.html?start=66b0c97070f422cb82baaaafc79ee94cab4396c5&end=548b5e75afd6bad696920dfdb69c9812ce0488f1
54+
[forward progress]: https://en.cppreference.com/w/cpp/language/memory_model#Forward_progress
55+
[undefined behavior]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#undefined-behavior

0 commit comments

Comments
 (0)