Skip to content

Save liveness results for DestinationPropagation#115291

Merged
bors merged 4 commits intorust-lang:masterfrom
cjgillot:dest-prop-save
Jan 18, 2024
Merged

Save liveness results for DestinationPropagation#115291
bors merged 4 commits intorust-lang:masterfrom
cjgillot:dest-prop-save

Conversation

@cjgillot
Copy link
Contributor

DestinationPropagation needs to verify that merge candidates do not conflict with each other. This is done by verifying that a local is not live when its counterpart is written to.

To get the liveness information, the pass runs MaybeLiveLocals dataflow analysis repeatedly, once for each propagation round. This is quite costly, and the main driver for the perf impact on ucd and diesel. (See #115105 (comment))

In order to mitigate this cost, this PR proposes to save the result of the analysis into a SparseIntervalMatrix, and mirror merges of locals into that matrix: liveness(destination) := liveness(destination) union liveness(source).

Proof

We denote by ' all the quantities of the transformed program. Let $\varphi$ be a mapping of locals, which maps source to destination, and is identity otherwise. The exact liveness set after a statement is $out'(statement)$, and the proposed liveness set is $\varphi(out(statement))$.

Consider a statement. Suppose that the output state verifies $out' \subset phi(out)$. We want to prove that $in' \subset \varphi(in)$ where $in = (out - kill) \cup gen$, and conclude by induction.

We have 2 cases: either that statement is kept with locals renumbered by $\varphi$, or it is a tautological assignment and it removed.

  1. If the statement is kept: the gen-set and the kill-set of $statement' = \varphi(statement)$ are $gen' = \varphi(gen)$ and $kill' = \varphi(kill)$ exactly.
    From soundness requirement 3, $\varphi(in)$ is disjoint from $\varphi(kill)$.
    This implies that $\varphi(out - kill)$ is disjoint from $\varphi(kill)$, and so $\varphi(out - kill) = \varphi(out) - \varphi(kill)$. Then $\varphi(in) = (\varphi(out) - \varphi(kill)) \cup \varphi(gen) = (\varphi(out) - kill') \cup gen'$.
    We can conclude that $out' \subset \varphi(out) \implies in' \subset \varphi(in)$.

  2. If the statement is removed. As $\varphi(statement)$ is a tautological assignment, we know that $\varphi(gen) = \varphi(kill) = \{ destination \}$, while $gen' = kill' = \emptyset$. So $\varphi(in) = \varphi(out) \cup \{ destination \}$. Then $in' = out' \subset out \subset \varphi(in)$.

By recursion, we can conclude by that $in' \subset \varphi(in)$ everywhere.

This approximate liveness results is only suboptimal if there are locals that fully disappear from the CFG due to an assignment cycle. These cases are quite unlikely, so we do not bother with them.

This change allows to reduce the perf impact of DestinationPropagation by half on diesel and ucd (#115105 (comment)).

cc @JakobDegen

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-mir-opt Area: MIR optimizations S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants