Skip to content

transmutability: remove NFA intermediate representation #139990

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

jswrenn
Copy link
Member

@jswrenn jswrenn commented Apr 17, 2025

Prior to this commit, the transmutability analysis used an intermediate NFA representation of type layout. We then determinized this representation into a DFA, upon which we ran the core transmutability analysis. Unfortunately, determinizing NFAs is expensive. In this commit, we avoid NFAs entirely by observing that Rust unions are the only source of nondeterminism and that it is comparatively cheap to compute the DFA union of DFAs.

We also implement Graphviz DOT debug formatting of DFAs.

Fixes rust-lang/project-safe-transmute#23
Fixes rust-lang/project-safe-transmute#24

r? @compiler-errors

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 17, 2025
@jswrenn jswrenn force-pushed the no-nfas branch 2 times, most recently from 0548619 to 0fec408 Compare April 17, 2025 23:15
Prior to this commit, the transmutability analysis used an intermediate
NFA representation of type layout. We then determinized this
representation into a DFA, upon which we ran the core transmutability
analysis. Unfortunately, determinizing NFAs is expensive. In this
commit, we avoid NFAs entirely by observing that Rust `union`s are the
only source of nondeterminism and that it is comparatively cheap to
compute the DFA union of DFAs.

We also implement Graphviz DOT debug formatting of DFAs.

Fixes rust-lang/project-safe-transmute#23
Fixes rust-lang/project-safe-transmute#24
@@ -22,12 +22,12 @@ fn validity() {
}

fn padding() {
#[repr(align(8))]
struct Align8;
#[repr(align(4))]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This temporary downsizing is tracked here: rust-lang/project-safe-transmute#25

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you double check that those test changes are necessary after resolving other comments?

Comment on lines +7 to 8
#[derive(PartialEq, Clone)]
pub(crate) struct Dfa<R>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems suspect to have a derived implementation of Clone, since it doesn't preserve the invariant that the states of distinct automatons are disjoint. This is orthogonal to the changes here, so feel free to ignore.

Comment on lines 35 to +37
/// The states in a `Nfa` represent byte offsets.
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
pub(crate) struct State(u32);
pub(crate) struct State(pub(crate) u32);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outdated reference to Nfa.


transitions.entry(src).or_default().byte_transitions.insert(*byte_transition, dst);

queue.push((a_dst, b_dst))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that each state is enqueued and processed only once. While it is irrelevant for correctness, it duplicates the work performed otherwise. For example, consider a union between two chain automatons with complete byte edges, the first state pair is enqueued once, the second state pair is enqueued 256 times, the third state pair 256^2 times, and so on.

Tree::Alt(alts) => {
// Convert and filter the inhabited alternatives.
let mut alts = alts.into_iter().map(Self::from_tree).filter_map(Result::ok);
// If there is not at least one alternative, return `Uninhabited`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps: "If there are no alternatives, ..."

Self { transitions, start, accepting }
}

/// Compute the union of two `Nfa`s.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outdated reference to Nfa.

@@ -109,7 +109,7 @@ where
// representation. If the conversion fails because `src` is uninhabited,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line above: outdated reference to NFA.

@@ -120,7 +120,7 @@ where
// the `dst` type do not exist, either because it's genuinely
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three lines above: outdated reference to NFA.

@@ -22,12 +22,12 @@ fn validity() {
}

fn padding() {
#[repr(align(8))]
struct Align8;
#[repr(align(4))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you double check that those test changes are necessary after resolving other comments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. 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.

Optimization: Remove NFAs, implement DFA union Visualize layouts with Graphviz
5 participants