-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Implement SSA-based reference propagation #106285
Conversation
(rustbot has picked a reviewer for you, use r? to override) |
r? rust-lang/compiler |
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
⌛ Trying commit 46516095d7a9cb208c8f17a01574a9a8bc180833 with merge fea7409a5e37c7f115c6b24d93e12e52fe364c27... |
This comment has been minimized.
This comment has been minimized.
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (fea7409a5e37c7f115c6b24d93e12e52fe364c27): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
|
This comment has been minimized.
This comment has been minimized.
| PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | ||
| PlaceContext::MutatingUse(MutatingUseContext::AddressOf) => { | ||
debug!(?local, "BORROW"); | ||
self.assignments[local] = Set1::Many; |
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.
For immutable borrows and AddressOf
, we probably don't need to mark the local as non-SSA: that borrow cannot be used, even indirectly to modify the local. Recording a direct use should be enough.
00ae1c3
to
a70ab55
Compare
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
⌛ Testing commit d30bbe1857fbdac2f4c03a974b22419b02b3c514 with merge bdd6f2fd486b691ba79fff426393a0a45417becb... |
This comment has been minimized.
This comment has been minimized.
💔 Test failed - checks-actions |
@bors r=JakobDegen |
☀️ Test successful - checks-actions |
Finished benchmarking commit (50dff95): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDNext Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 657.982s -> 659.227s (0.19%) |
Allow MIR debuginfo to point to a variable's address MIR optimizations currently do not to operate on borrowed locals. When enabling rust-lang#106285, many borrows will be left as-is because they are used in debuginfo. This pass allows to replace this pattern directly in MIR debuginfo: ```rust a => _1 _1 = &raw? mut? _2 ``` becomes ```rust a => &_2 // No statement to borrow _2. ``` This pass is implemented as a drive-by in ReferencePropagation MIR pass. This transformation allows following following MIR opts to treat _2 as an unborrowed local, and optimize it as such, even in builds with debuginfo. In codegen, when encountering `a => &..&_2`, we create a list of allocas: ```llvm store ptr %_2.dbg.spill, ptr %a.ref0.dbg.spill store ptr %a.ref0.dbg.spill, ptr %a.ref1.dbg.spill ... call void `@llvm.dbg.declare(metadata` ptr %a.ref{n}.dbg.spill, /* ... */) ``` Caveat: this transformation looses the exact type, we do not differentiate `a` as a immutable, mutable reference or a raw pointer. Everything is declared to `*mut` to codegen. I'm not convinced this is a blocker.
Regressions appear to mostly be bimodality. |
Rust has a tendency to create a lot of short-lived borrows, in particular for method calls. This PR aims to remove those short-lived borrows with a const-propagation dedicated to pointers to local places.
This pass aims to transform the following pattern:
Into
where
PLACE
is a direct or an indirect place expression.By removing indirection, this pass should help both dest-prop and const-prop to handle more cases.
This optimization is distinct from const-prop and dataflow const-prop since the borrow-reborrow patterns needs to preserve borrowck invariants, especially the uniqueness property of mutable references.
The pointed-to places are computed using a SSA analysis. We suppose that removable borrows are typically temporaries from autoref, so they are by construction assigned only once, and a SSA analysis is enough to catch them. For each local, we store both where and how it is used, in order to efficiently compute the all-or-nothing property. Thanks to
Derefer
, we only have to track locals, not places in general.There are 3 properties that need to be upheld for this transformation to be legal:
PLACE
must refer to the same memory wherever it appears;&mut
borrow uniqueness.Constness
If
PLACE
is an indirect projection, if its of the form(*LOCAL).PROJECTIONS
where:LOCAL
is SSA;PROJECTIONS
are constant (no dereference and no indexing).If
PLACE
is a direct projection of a local, we consider it as constant if:StorageLive
that dominates all uses;Liveness
When performing a substitution, we must take care not to introduce uses of dangling locals.
Using a dangling borrow is UB. Therefore, we assume that for any use of
*x
, wherex
is a borrow, the pointed-to memory is live.Limitations:
*x
in an&raw mut? *x
are accepted;In those 2 case, we do not substitute anything, to be on the safe side.
Open question: we do not differentiate borrows of ZST and non-ZST. The UB rules may be
different depending on the layout. Having a different treatment would effectively prevent this
pass from running on polymorphic MIR, which defeats the purpose of MIR opts.
Uniqueness
For
&mut
borrows, we also need to preserve the uniqueness property:we must avoid creating a state where we interleave uses of
*_1
and_2
.To do it, we only perform full substitution of mutable borrows:
we replace either all or none of the occurrences of
*_1
.Some care has to be taken when
_1
is copied in other locals.In such cases, fully substituting
_1
means fully substituting all of the copies.For immutable borrows, we do not need to preserve such uniqueness property,
so we perform all the possible substitutions without removing the
_1 = &_2
statement.