Skip to content

Commit d9c439e

Browse files
committed
Implement JumpThreading pass.
1 parent 86506d1 commit d9c439e

27 files changed

+2375
-18
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4242,6 +4242,7 @@ dependencies = [
42424242
"coverage_test_macros",
42434243
"either",
42444244
"itertools",
4245+
"rustc_arena",
42454246
"rustc_ast",
42464247
"rustc_attr",
42474248
"rustc_const_eval",

compiler/rustc_middle/src/mir/terminator.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ impl SwitchTargets {
2828
Self { values: smallvec![value], targets: smallvec![then, else_] }
2929
}
3030

31+
/// Inverse of `SwitchTargets::static_if`.
32+
pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> {
33+
if let &[value] = &self.values[..] && let &[then, else_] = &self.targets[..] {
34+
Some((value, then, else_))
35+
} else {
36+
None
37+
}
38+
}
39+
3140
/// Returns the fallback target that is jumped to when none of the values match the operand.
3241
pub fn otherwise(&self) -> BasicBlock {
3342
*self.targets.last().unwrap()

compiler/rustc_mir_dataflow/src/value_analysis.rs

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,19 @@ impl<V: Clone> Clone for State<V> {
463463
}
464464
}
465465

466-
impl<V: Clone + HasTop + HasBottom> State<V> {
466+
impl<V: Clone> State<V> {
467+
pub fn new(init: V, map: &Map) -> State<V> {
468+
let values = IndexVec::from_elem_n(init, map.value_count);
469+
State(StateData::Reachable(values))
470+
}
471+
472+
pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
473+
match self.0 {
474+
StateData::Unreachable => true,
475+
StateData::Reachable(ref values) => values.iter().all(f),
476+
}
477+
}
478+
467479
pub fn is_reachable(&self) -> bool {
468480
matches!(&self.0, StateData::Reachable(_))
469481
}
@@ -472,7 +484,10 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
472484
self.0 = StateData::Unreachable;
473485
}
474486

475-
pub fn flood_all(&mut self) {
487+
pub fn flood_all(&mut self)
488+
where
489+
V: HasTop,
490+
{
476491
self.flood_all_with(V::TOP)
477492
}
478493

@@ -482,27 +497,40 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
482497
}
483498

484499
pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
485-
let StateData::Reachable(values) = &mut self.0 else { return };
486-
map.for_each_aliasing_place(place, None, &mut |vi| {
487-
values[vi] = value.clone();
488-
});
500+
self.flood_with_extra(place, None, map, value)
489501
}
490502

491-
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
503+
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map)
504+
where
505+
V: HasTop,
506+
{
492507
self.flood_with(place, map, V::TOP)
493508
}
494509

495510
pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
496-
let StateData::Reachable(values) = &mut self.0 else { return };
497-
map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |vi| {
498-
values[vi] = value.clone();
499-
});
511+
self.flood_with_extra(place, Some(TrackElem::Discriminant), map, value)
500512
}
501513

502-
pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) {
514+
pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map)
515+
where
516+
V: HasTop,
517+
{
503518
self.flood_discr_with(place, map, V::TOP)
504519
}
505520

521+
pub fn flood_with_extra(
522+
&mut self,
523+
place: PlaceRef<'_>,
524+
tail_elem: Option<TrackElem>,
525+
map: &Map,
526+
value: V,
527+
) {
528+
let StateData::Reachable(values) = &mut self.0 else { return };
529+
map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
530+
values[vi] = value.clone();
531+
});
532+
}
533+
506534
/// Low-level method that assigns to a place.
507535
/// This does nothing if the place is not tracked.
508536
///
@@ -553,44 +581,87 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
553581
}
554582

555583
/// Helper method to interpret `target = result`.
556-
pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
584+
pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
585+
where
586+
V: HasTop,
587+
{
557588
self.flood(target, map);
558589
if let Some(target) = map.find(target) {
559590
self.insert_idx(target, result, map);
560591
}
561592
}
562593

563594
/// Helper method for assignments to a discriminant.
564-
pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map) {
595+
pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
596+
where
597+
V: HasTop,
598+
{
565599
self.flood_discr(target, map);
566600
if let Some(target) = map.find_discr(target) {
567601
self.insert_idx(target, result, map);
568602
}
569603
}
570604

571605
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
572-
pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V {
606+
pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
607+
let place = map.find(place)?;
608+
self.try_get_idx(place, map)
609+
}
610+
611+
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
612+
pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
613+
let place = map.find_discr(place)?;
614+
self.try_get_idx(place, map)
615+
}
616+
617+
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
618+
pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
619+
match &self.0 {
620+
StateData::Reachable(values) => {
621+
map.places[place].value_index.map(|v| values[v].clone())
622+
}
623+
StateData::Unreachable => {
624+
// Because this is unreachable, we can return any value we want.
625+
None
626+
}
627+
}
628+
}
629+
630+
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
631+
pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V
632+
where
633+
V: HasBottom + HasTop,
634+
{
573635
map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP)
574636
}
575637

576638
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
577-
pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V {
639+
pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V
640+
where
641+
V: HasBottom + HasTop,
642+
{
578643
match map.find_discr(place) {
579644
Some(place) => self.get_idx(place, map),
580645
None => V::TOP,
581646
}
582647
}
583648

584649
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
585-
pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V {
650+
pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V
651+
where
652+
V: HasBottom + HasTop,
653+
{
586654
match map.find_len(place) {
587655
Some(place) => self.get_idx(place, map),
588656
None => V::TOP,
589657
}
590658
}
591659

592660
/// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
593-
pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
661+
pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
662+
where
663+
V: HasBottom + HasTop,
664+
{
594665
match &self.0 {
595666
StateData::Reachable(values) => {
596667
map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)

compiler/rustc_mir_transform/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
1111
tracing = "0.1"
1212
either = "1"
1313
rustc_ast = { path = "../rustc_ast" }
14+
rustc_arena = { path = "../rustc_arena" }
1415
rustc_attr = { path = "../rustc_attr" }
1516
rustc_data_structures = { path = "../rustc_data_structures" }
1617
rustc_errors = { path = "../rustc_errors" }

0 commit comments

Comments
 (0)