Replace NormalizeArrayLen
with GVN
GVN is actually on in release, and covers all the same things (or more), with `LowerSliceLen` changed to produce `PtrMetadata`.
This commit is contained in:
parent
4a7b6c0e6c
commit
b611b6bbb8
30 changed files with 138 additions and 218 deletions
|
@ -88,7 +88,6 @@ mod lower_slice_len;
|
|||
mod match_branches;
|
||||
mod mentioned_items;
|
||||
mod multiple_return_terminators;
|
||||
mod normalize_array_len;
|
||||
mod nrvo;
|
||||
mod prettify;
|
||||
mod promote_consts;
|
||||
|
@ -581,9 +580,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
|
||||
// Inlining may have introduced a lot of redundant code and a large move pattern.
|
||||
// Now, we need to shrink the generated MIR.
|
||||
|
||||
// Has to run after `slice::len` lowering
|
||||
&normalize_array_len::NormalizeArrayLen,
|
||||
&ref_prop::ReferencePropagation,
|
||||
&sroa::ScalarReplacementOfAggregates,
|
||||
&match_branches::MatchBranchSimplification,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
//! This pass lowers calls to core::slice::len to just Len op.
|
||||
//! This pass lowers calls to core::slice::len to just PtrMetadata op.
|
||||
//! It should run before inlining!
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub struct LowerSliceLenCalls;
|
||||
|
||||
|
@ -29,16 +28,11 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
|
||||
for block in basic_blocks {
|
||||
// lower `<[_]>::len` calls
|
||||
lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id);
|
||||
lower_slice_len_call(block, slice_len_fn_item_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_slice_len_call<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
block: &mut BasicBlockData<'tcx>,
|
||||
local_decls: &IndexSlice<Local, LocalDecl<'tcx>>,
|
||||
slice_len_fn_item_def_id: DefId,
|
||||
) {
|
||||
fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
|
||||
let terminator = block.terminator();
|
||||
if let TerminatorKind::Call {
|
||||
func,
|
||||
|
@ -50,19 +44,17 @@ fn lower_slice_len_call<'tcx>(
|
|||
} = &terminator.kind
|
||||
// some heuristics for fast rejection
|
||||
&& let [arg] = &args[..]
|
||||
&& let Some(arg) = arg.node.place()
|
||||
&& let ty::FnDef(fn_def_id, _) = func.ty(local_decls, tcx).kind()
|
||||
&& *fn_def_id == slice_len_fn_item_def_id
|
||||
&& let Some((fn_def_id, _)) = func.const_fn_def()
|
||||
&& fn_def_id == slice_len_fn_item_def_id
|
||||
{
|
||||
// perform modifications from something like:
|
||||
// _5 = core::slice::<impl [u8]>::len(move _6) -> bb1
|
||||
// into:
|
||||
// _5 = Len(*_6)
|
||||
// _5 = PtrMetadata(move _6)
|
||||
// goto bb1
|
||||
|
||||
// make new RValue for Len
|
||||
let deref_arg = tcx.mk_place_deref(arg);
|
||||
let r_value = Rvalue::Len(deref_arg);
|
||||
let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone());
|
||||
let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value)));
|
||||
let add_statement =
|
||||
Statement { kind: len_statement_kind, source_info: terminator.source_info };
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
//! This pass eliminates casting of arrays into slices when their length
|
||||
//! is taken using `.len()` method. Handy to preserve information in MIR for const prop
|
||||
|
||||
use crate::ssa::SsaLocals;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::visit::*;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
pub struct NormalizeArrayLen;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 3
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!(def_id = ?body.source.def_id());
|
||||
normalize_array_len_calls(tcx, body)
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
||||
let ssa = SsaLocals::new(tcx, body, param_env);
|
||||
|
||||
let slice_lengths = compute_slice_length(tcx, &ssa, body);
|
||||
debug!(?slice_lengths);
|
||||
|
||||
Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body);
|
||||
}
|
||||
|
||||
fn compute_slice_length<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ssa: &SsaLocals,
|
||||
body: &Body<'tcx>,
|
||||
) -> IndexVec<Local, Option<ty::Const<'tcx>>> {
|
||||
let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls);
|
||||
|
||||
for (local, rvalue, _) in ssa.assignments(body) {
|
||||
match rvalue {
|
||||
Rvalue::Cast(
|
||||
CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize),
|
||||
operand,
|
||||
cast_ty,
|
||||
) => {
|
||||
let operand_ty = operand.ty(body, tcx);
|
||||
debug!(?operand_ty);
|
||||
if let Some(operand_ty) = operand_ty.builtin_deref(true)
|
||||
&& let ty::Array(_, len) = operand_ty.kind()
|
||||
&& let Some(cast_ty) = cast_ty.builtin_deref(true)
|
||||
&& let ty::Slice(..) = cast_ty.kind()
|
||||
{
|
||||
slice_lengths[local] = Some(*len);
|
||||
}
|
||||
}
|
||||
// The length information is stored in the fat pointer, so we treat `operand` as a value.
|
||||
Rvalue::Use(operand) => {
|
||||
if let Some(rhs) = operand.place()
|
||||
&& let Some(rhs) = rhs.as_local()
|
||||
{
|
||||
slice_lengths[local] = slice_lengths[rhs];
|
||||
}
|
||||
}
|
||||
// The length information is stored in the fat pointer.
|
||||
// Reborrowing copies length information from one pointer to the other.
|
||||
Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => {
|
||||
if let [PlaceElem::Deref] = rhs.projection[..] {
|
||||
slice_lengths[local] = slice_lengths[rhs.local];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
slice_lengths
|
||||
}
|
||||
|
||||
struct Replacer<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
slice_lengths: IndexVec<Local, Option<ty::Const<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) {
|
||||
if let Rvalue::Len(place) = rvalue
|
||||
&& let [PlaceElem::Deref] = &place.projection[..]
|
||||
&& let Some(len) = self.slice_lengths[place.local]
|
||||
{
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||
span: rustc_span::DUMMY_SP,
|
||||
user_ty: None,
|
||||
const_: Const::from_ty_const(len, self.tcx.types.usize, self.tcx),
|
||||
})));
|
||||
}
|
||||
self.super_rvalue(rvalue, loc);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue