about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs42
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs11
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs30
3 files changed, 51 insertions, 32 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index ef4031c5c03..94088156756 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
+use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 use tracing::{debug, debug_span, instrument};
@@ -13,13 +14,13 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
 /// The coverage counter or counter expression associated with a particular
 /// BCB node or BCB edge.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum BcbCounter {
+enum BcbCounter {
     Counter { id: CounterId },
     Expression { id: ExpressionId },
 }
 
 impl BcbCounter {
-    pub(super) fn as_term(&self) -> CovTerm {
+    fn as_term(&self) -> CovTerm {
         match *self {
             BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
             BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
@@ -78,21 +79,22 @@ impl CoverageCounters {
     /// counters or counter expressions for nodes and edges as required.
     pub(super) fn make_bcb_counters(
         basic_coverage_blocks: &CoverageGraph,
-        bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool,
+        bcb_needs_counter: &BitSet<BasicCoverageBlock>,
     ) -> Self {
-        let num_bcbs = basic_coverage_blocks.num_nodes();
+        let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter);
+        counters.make_bcb_counters();
 
-        let mut this = Self {
+        counters.coverage_counters
+    }
+
+    fn with_num_bcbs(num_bcbs: usize) -> Self {
+        Self {
             counter_increment_sites: IndexVec::new(),
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
             bcb_edge_counters: FxHashMap::default(),
             expressions: IndexVec::new(),
             expressions_memo: FxHashMap::default(),
-        };
-
-        MakeBcbCounters::new(&mut this, basic_coverage_blocks).make_bcb_counters(bcb_needs_counter);
-
-        this
+        }
     }
 
     /// Shared helper used by [`Self::make_phys_node_counter`] and
@@ -218,8 +220,8 @@ impl CoverageCounters {
         }
     }
 
-    pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
-        self.bcb_counters[bcb]
+    pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
+        self.bcb_counters[bcb].map(|counter| counter.as_term())
     }
 
     /// Returns an iterator over all the nodes/edges in the coverage graph that
@@ -265,19 +267,25 @@ impl CoverageCounters {
 
 /// Helper struct that allows counter creation to inspect the BCB graph.
 struct MakeBcbCounters<'a> {
-    coverage_counters: &'a mut CoverageCounters,
+    coverage_counters: CoverageCounters,
     basic_coverage_blocks: &'a CoverageGraph,
+    bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
 }
 
 impl<'a> MakeBcbCounters<'a> {
     fn new(
-        coverage_counters: &'a mut CoverageCounters,
         basic_coverage_blocks: &'a CoverageGraph,
+        bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
     ) -> Self {
-        Self { coverage_counters, basic_coverage_blocks }
+        assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size());
+        Self {
+            coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()),
+            basic_coverage_blocks,
+            bcb_needs_counter,
+        }
     }
 
-    fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) {
+    fn make_bcb_counters(&mut self) {
         debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
 
         // Traverse the coverage graph, ensuring that every node that needs a
@@ -290,7 +298,7 @@ impl<'a> MakeBcbCounters<'a> {
         let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks);
         while let Some(bcb) = traversal.next() {
             let _span = debug_span!("traversal", ?bcb).entered();
-            if bcb_needs_counter(bcb) {
+            if self.bcb_needs_counter.contains(bcb) {
                 self.make_node_counter_and_out_edge_counters(&traversal, bcb);
             }
         }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 104f340c8d6..79482ba3919 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -94,9 +94,8 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
         return;
     }
 
-    let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
     let coverage_counters =
-        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
+        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings);
 
     let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
     if mappings.is_empty() {
@@ -153,12 +152,8 @@ fn create_mappings<'tcx>(
         &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
     );
 
-    let term_for_bcb = |bcb| {
-        coverage_counters
-            .bcb_counter(bcb)
-            .expect("all BCBs with spans were given counters")
-            .as_term()
-    };
+    let term_for_bcb =
+        |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
     let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 0bb46675e9a..daf868559bc 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -103,7 +103,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
-use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx};
+use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
 use smallvec::SmallVec;
 use tracing::{debug, instrument, trace};
 
@@ -568,13 +568,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 CastKind::Transmute => {
                     let value = self.evaluated[value].as_ref()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    // `offset` for immediates only supports scalar/scalar-pair ABIs,
-                    // so bail out if the target is not one.
+                    // `offset` for immediates generally only supports projections that match the
+                    // type of the immediate. However, as a HACK, we exploit that it can also do
+                    // limited transmutes: it only works between types with the same layout, and
+                    // cannot transmute pointers to integers.
                     if value.as_mplace_or_imm().is_right() {
-                        match (value.layout.abi, to.abi) {
-                            (Abi::Scalar(..), Abi::Scalar(..)) => {}
-                            (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {}
-                            _ => return None,
+                        let can_transmute = match (value.layout.abi, to.abi) {
+                            (Abi::Scalar(s1), Abi::Scalar(s2)) => {
+                                s1.size(&self.ecx) == s2.size(&self.ecx)
+                                    && !matches!(s1.primitive(), Primitive::Pointer(..))
+                            }
+                            (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => {
+                                a1.size(&self.ecx) == a2.size(&self.ecx) &&
+                                b1.size(&self.ecx) == b2.size(&self.ecx) &&
+                                // The alignment of the second component determines its offset, so that also needs to match.
+                                b1.align(&self.ecx) == b2.align(&self.ecx) &&
+                                // None of the inputs may be a pointer.
+                                !matches!(a1.primitive(), Primitive::Pointer(..))
+                                    && !matches!(b1.primitive(), Primitive::Pointer(..))
+                            }
+                            _ => false,
+                        };
+                        if !can_transmute {
+                            return None;
                         }
                     }
                     value.offset(Size::ZERO, to, &self.ecx).discard_err()?