1 //! This pass eliminates casting of arrays into slices when their length
2 //! is taken using `.len()` method. Handy to preserve information in MIR for const prop
4 use crate::ssa::SsaLocals;
6 use rustc_index::vec::IndexVec;
7 use rustc_middle::mir::visit::*;
8 use rustc_middle::mir::*;
9 use rustc_middle::ty::{self, TyCtxt};
10 use rustc_mir_dataflow::impls::borrowed_locals;
12 pub struct NormalizeArrayLen;
14 impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
15 fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
16 sess.mir_opt_level() >= 3
19 #[instrument(level = "trace", skip(self, tcx, body))]
20 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
21 debug!(def_id = ?body.source.def_id());
22 normalize_array_len_calls(tcx, body)
26 fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
27 let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
28 let borrowed_locals = borrowed_locals(body);
29 let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
31 let slice_lengths = compute_slice_length(tcx, &ssa, body);
32 debug!(?slice_lengths);
34 Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body);
37 fn compute_slice_length<'tcx>(
41 ) -> IndexVec<Local, Option<ty::Const<'tcx>>> {
42 let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls);
44 for (local, rvalue) in ssa.assignments(body) {
47 CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
51 let operand_ty = operand.ty(body, tcx);
53 if let Some(operand_ty) = operand_ty.builtin_deref(true)
54 && let ty::Array(_, len) = operand_ty.ty.kind()
55 && let Some(cast_ty) = cast_ty.builtin_deref(true)
56 && let ty::Slice(..) = cast_ty.ty.kind()
58 slice_lengths[local] = Some(*len);
61 // The length information is stored in the fat pointer, so we treat `operand` as a value.
62 Rvalue::Use(operand) => {
63 if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() {
64 slice_lengths[local] = slice_lengths[rhs];
67 // The length information is stored in the fat pointer.
68 // Reborrowing copies length information from one pointer to the other.
69 Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => {
70 if let [PlaceElem::Deref] = rhs.projection[..] {
71 slice_lengths[local] = slice_lengths[rhs.local];
81 struct Replacer<'tcx> {
83 slice_lengths: IndexVec<Local, Option<ty::Const<'tcx>>>,
86 impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
87 fn tcx(&self) -> TyCtxt<'tcx> {
91 fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) {
92 if let Rvalue::Len(place) = rvalue
93 && let [PlaceElem::Deref] = &place.projection[..]
94 && let Some(len) = self.slice_lengths[place.local]
96 *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
97 span: rustc_span::DUMMY_SP,
99 literal: ConstantKind::from_const(len, self.tcx),
102 self.super_rvalue(rvalue, loc);