Auto merge of #121421 - saethlin:smarter-mono, r= · rust-lang/rust@b183b7a (original) (raw)
`@@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
`
10
10
`use crate::ty::print::{FmtPrinter, Printer};
`
11
11
`use crate::ty::visit::TypeVisitableExt;
`
12
12
`use crate::ty::{self, List, Ty, TyCtxt};
`
13
``
`-
use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
`
``
13
`+
use crate::ty::{AdtDef, Instance, InstanceDef, UserTypeAnnotationIndex};
`
14
14
`use crate::ty::{GenericArg, GenericArgsRef};
`
15
15
``
16
16
`use rustc_data_structures::captures::Captures;
`
`@@ -29,6 +29,7 @@ pub use rustc_ast::Mutability;
`
29
29
`use rustc_data_structures::fx::FxHashMap;
`
30
30
`use rustc_data_structures::fx::FxHashSet;
`
31
31
`use rustc_data_structures::graph::dominators::Dominators;
`
``
32
`+
use rustc_index::bit_set::BitSet;
`
32
33
`use rustc_index::{Idx, IndexSlice, IndexVec};
`
33
34
`use rustc_serialize::{Decodable, Encodable};
`
34
35
`use rustc_span::symbol::Symbol;
`
`@@ -642,6 +643,73 @@ impl<'tcx> Body<'tcx> {
`
642
643
`self.injection_phase.is_some()
`
643
644
`}
`
644
645
``
``
646
`+
/// Finds which basic blocks are actually reachable for a specific
`
``
647
`+
/// monomorphization of this body.
`
``
648
`+
///
`
``
649
`+
/// This is allowed to have false positives; just because this says a block
`
``
650
`+
/// is reachable doesn't mean that's necessarily true. It's thus always
`
``
651
`+
/// legal for this to return a filled set.
`
``
652
`+
///
`
``
653
`` +
/// Regardless, the [BitSet::domain_size
] of the returned set will always
``
``
654
`` +
/// exactly match the number of blocks in the body so that contains
``
``
655
`+
/// checks can be done without worrying about panicking.
`
``
656
`+
///
`
``
657
`` +
/// The main case this supports is filtering out if <T as Trait>::CONST
``
``
658
`+
/// bodies that can't be removed in generic MIR, but can be removed once
`
``
659
`` +
/// the specific T
is known.
``
``
660
`+
///
`
``
661
`+
/// This is used in the monomorphization collector as well as in codegen.
`
``
662
`+
pub fn reachable_blocks_in_mono(
`
``
663
`+
&self,
`
``
664
`+
tcx: TyCtxt<'tcx>,
`
``
665
`+
instance: Instance<'tcx>,
`
``
666
`+
) -> BitSet {
`
``
667
`+
if instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_none() {
`
``
668
`+
// If it's non-generic, then mir-opt const prop has already run, meaning it's
`
``
669
`+
// probably not worth doing any further filtering. So call everything reachable.
`
``
670
`+
return BitSet::new_filled(self.basic_blocks.len());
`
``
671
`+
}
`
``
672
+
``
673
`+
let mut set = BitSet::new_empty(self.basic_blocks.len());
`
``
674
`+
self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK);
`
``
675
`+
set
`
``
676
`+
}
`
``
677
+
``
678
`+
fn reachable_blocks_in_mono_from(
`
``
679
`+
&self,
`
``
680
`+
tcx: TyCtxt<'tcx>,
`
``
681
`+
instance: Instance<'tcx>,
`
``
682
`+
set: &mut BitSet,
`
``
683
`+
bb: BasicBlock,
`
``
684
`+
) {
`
``
685
`+
if !set.insert(bb) {
`
``
686
`+
return;
`
``
687
`+
}
`
``
688
+
``
689
`+
let data = &self.basic_blocks[bb];
`
``
690
+
``
691
`+
if let TerminatorKind::SwitchInt { discr: Operand::Constant(constant), targets } =
`
``
692
`+
&data.terminator().kind
`
``
693
`+
{
`
``
694
`+
let env = ty::ParamEnv::reveal_all();
`
``
695
`+
let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions(
`
``
696
`+
tcx,
`
``
697
`+
env,
`
``
698
`+
crate::ty::EarlyBinder::bind(constant.const_),
`
``
699
`+
);
`
``
700
`+
if let Some(bits) = mono_literal.try_eval_bits(tcx, env) {
`
``
701
`+
let target = targets.target_for_value(bits);
`
``
702
`+
return self.reachable_blocks_in_mono_from(tcx, instance, set, target);
`
``
703
`+
} else {
`
``
704
`+
bug!("Couldn't evaluate constant {:?} in mono {:?}", constant, instance);
`
``
705
`+
}
`
``
706
`+
}
`
``
707
+
``
708
`+
for target in data.terminator().successors() {
`
``
709
`+
self.reachable_blocks_in_mono_from(tcx, instance, set, target);
`
``
710
`+
}
`
``
711
`+
}
`
``
712
+
645
713
`` /// For a Location
in this scope, determine what the "caller location" at that point is. This
``
646
714
`` /// is interesting because of inlining: the #[track_caller]
attribute of inlined functions
``
647
715
`` /// must be honored. Falls back to the tracked_caller
value for #[track_caller]
functions,
``