diff options
| author | Joshua Liebow-Feeser <hello@joshlf.com> | 2025-04-10 13:45:39 -0700 |
|---|---|---|
| committer | Joshua Liebow-Feeser <hello@joshlf.com> | 2025-04-23 11:45:00 -0700 |
| commit | 4326a44e6f0859077b7789d42416b9291b0ff4d1 (patch) | |
| tree | 713ed8f802314f672e8d51725b158eb1a6c1dc9e /compiler/rustc_transmute/src/maybe_transmutable/tests.rs | |
| parent | be181dd75c83d72fcc95538e235768bc367b76b9 (diff) | |
| download | rust-4326a44e6f0859077b7789d42416b9291b0ff4d1.tar.gz rust-4326a44e6f0859077b7789d42416b9291b0ff4d1.zip | |
transmutability: Mark edges by ranges, not values
In the `Tree` and `Dfa` representations of a type's layout, store byte ranges rather than needing to separately store each byte value. This permits us to, for example, represent a `u8` using a single 0..=255 edge in the DFA rather than using 256 separate edges. This leads to drastic performance improvements. For example, on the author's 2024 MacBook Pro, the time to convert the `Tree` representation of a `u64` to its equivalent DFA representation drops from ~8.5ms to ~1us, a reduction of ~8,500x. See `bench_dfa_from_tree`. Similarly, the time to execute a transmutability query from `u64` to `u64` drops from ~35us to ~1.7us, a reduction of ~20x. See `bench_transmute`.
Diffstat (limited to 'compiler/rustc_transmute/src/maybe_transmutable/tests.rs')
| -rw-r--r-- | compiler/rustc_transmute/src/maybe_transmutable/tests.rs | 183 |
1 files changed, 179 insertions, 4 deletions
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index cc6a4dce17b..24e2a1acadd 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -1,3 +1,5 @@ +extern crate test; + use itertools::Itertools; use super::query_context::test::{Def, UltraMinimal}; @@ -12,15 +14,25 @@ trait Representation { impl Representation for Tree { fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> { - crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) - .answer() + crate::maybe_transmutable::MaybeTransmutableQuery::new( + src, + dst, + assume, + UltraMinimal::default(), + ) + .answer() } } impl Representation for Dfa { fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> { - crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal) - .answer() + crate::maybe_transmutable::MaybeTransmutableQuery::new( + src, + dst, + assume, + UltraMinimal::default(), + ) + .answer() } } @@ -89,6 +101,36 @@ mod safety { } } +mod size { + use super::*; + + #[test] + fn size() { + let small = Tree::number(1); + let large = Tree::number(2); + + for alignment in [false, true] { + for lifetimes in [false, true] { + for safety in [false, true] { + for validity in [false, true] { + let assume = Assume { alignment, lifetimes, safety, validity }; + assert_eq!( + is_transmutable(&small, &large, assume), + Answer::No(Reason::DstIsTooBig), + "assume: {assume:?}" + ); + assert_eq!( + is_transmutable(&large, &small, assume), + Answer::Yes, + "assume: {assume:?}" + ); + } + } + } + } + } +} + mod bool { use super::*; @@ -113,6 +155,27 @@ mod bool { } #[test] + fn transmute_u8() { + let bool = &Tree::bool(); + let u8 = &Tree::u8(); + for (src, dst, assume_validity, answer) in [ + (bool, u8, false, Answer::Yes), + (bool, u8, true, Answer::Yes), + (u8, bool, false, Answer::No(Reason::DstIsBitIncompatible)), + (u8, bool, true, Answer::Yes), + ] { + assert_eq!( + is_transmutable( + src, + dst, + Assume { validity: assume_validity, ..Assume::default() } + ), + answer + ); + } + } + + #[test] fn should_permit_validity_expansion_and_reject_contraction() { let b0 = layout::Tree::<Def, !>::from_bits(0); let b1 = layout::Tree::<Def, !>::from_bits(1); @@ -175,6 +238,62 @@ mod bool { } } +mod uninit { + use super::*; + + #[test] + fn size() { + let mu = Tree::uninit(); + let u8 = Tree::u8(); + + for alignment in [false, true] { + for lifetimes in [false, true] { + for safety in [false, true] { + for validity in [false, true] { + let assume = Assume { alignment, lifetimes, safety, validity }; + + let want = if validity { + Answer::Yes + } else { + Answer::No(Reason::DstIsBitIncompatible) + }; + + assert_eq!(is_transmutable(&mu, &u8, assume), want, "assume: {assume:?}"); + assert_eq!( + is_transmutable(&u8, &mu, assume), + Answer::Yes, + "assume: {assume:?}" + ); + } + } + } + } + } +} + +mod alt { + use super::*; + use crate::Answer; + + #[test] + fn should_permit_identity_transmutation() { + type Tree = layout::Tree<Def, !>; + + let x = Tree::Seq(vec![Tree::from_bits(0), Tree::from_bits(0)]); + let y = Tree::Seq(vec![Tree::bool(), Tree::from_bits(1)]); + let layout = Tree::Alt(vec![x, y]); + + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout.clone(), + layout.clone(), + crate::Assume::default(), + UltraMinimal::default(), + ) + .answer(); + assert_eq!(answer, Answer::Yes, "layout:{:#?}", layout); + } +} + mod union { use super::*; @@ -203,3 +322,59 @@ mod union { assert_eq!(is_transmutable(&t, &u, Assume::default()), Answer::Yes); } } + +mod r#ref { + use super::*; + + #[test] + fn should_permit_identity_transmutation() { + type Tree = crate::layout::Tree<Def, [(); 1]>; + + let layout = Tree::Seq(vec![Tree::from_bits(0), Tree::Ref([()])]); + + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout.clone(), + layout, + Assume::default(), + UltraMinimal::default(), + ) + .answer(); + assert_eq!(answer, Answer::If(crate::Condition::IfTransmutable { src: [()], dst: [()] })); + } +} + +mod benches { + use std::hint::black_box; + + use test::Bencher; + + use super::*; + + #[bench] + fn bench_dfa_from_tree(b: &mut Bencher) { + let num = Tree::number(8).prune(&|_| false); + let num = black_box(num); + + b.iter(|| { + let _ = black_box(Dfa::from_tree(num.clone())); + }) + } + + #[bench] + fn bench_transmute(b: &mut Bencher) { + let num = Tree::number(8).prune(&|_| false); + let dfa = black_box(Dfa::from_tree(num).unwrap()); + + b.iter(|| { + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + dfa.clone(), + dfa.clone(), + Assume::default(), + UltraMinimal::default(), + ) + .answer(); + let answer = std::hint::black_box(answer); + assert_eq!(answer, Answer::Yes); + }) + } +} |
