1 //! This pass lowers calls to core::slice::len to just Len op.
2 //! It should run before inlining!
4 use crate::transform
::MirPass
;
5 use rustc_hir
::def_id
::DefId
;
6 use rustc_index
::vec
::IndexVec
;
7 use rustc_middle
::mir
::*;
8 use rustc_middle
::ty
::{self, TyCtxt}
;
10 pub struct LowerSliceLenCalls
;
12 impl<'tcx
> MirPass
<'tcx
> for LowerSliceLenCalls
{
13 fn run_pass(&self, tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
14 lower_slice_len_calls(tcx
, body
)
18 pub fn lower_slice_len_calls
<'tcx
>(tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
19 let language_items
= tcx
.lang_items();
20 let slice_len_fn_item_def_id
= if let Some(slice_len_fn_item
) = language_items
.slice_len_fn() {
23 // there is no language item to compare to :)
27 let (basic_blocks
, local_decls
) = body
.basic_blocks_and_local_decls_mut();
29 for block
in basic_blocks
{
30 // lower `<[_]>::len` calls
31 lower_slice_len_call(tcx
, block
, &*local_decls
, slice_len_fn_item_def_id
);
35 struct SliceLenPatchInformation
<'tcx
> {
36 add_statement
: Statement
<'tcx
>,
37 new_terminator_kind
: TerminatorKind
<'tcx
>,
40 fn lower_slice_len_call
<'tcx
>(
42 block
: &mut BasicBlockData
<'tcx
>,
43 local_decls
: &IndexVec
<Local
, LocalDecl
<'tcx
>>,
44 slice_len_fn_item_def_id
: DefId
,
46 let mut patch_found
: Option
<SliceLenPatchInformation
<'_
>> = None
;
48 let terminator
= block
.terminator();
49 match &terminator
.kind
{
50 TerminatorKind
::Call
{
53 destination
: Some((dest
, bb
)),
58 // some heuristics for fast rejection
62 let arg
= match args
[0].place() {
66 let func_ty
= func
.ty(local_decls
, tcx
);
67 match func_ty
.kind() {
68 ty
::FnDef(fn_def_id
, _
) if fn_def_id
== &slice_len_fn_item_def_id
=> {
69 // perform modifications
70 // from something like `_5 = core::slice::<impl [u8]>::len(move _6) -> bb1`
71 // into `_5 = Len(*_6)
74 // make new RValue for Len
75 let deref_arg
= tcx
.mk_place_deref(arg
);
76 let r_value
= Rvalue
::Len(deref_arg
);
77 let len_statement_kind
= StatementKind
::Assign(Box
::new((*dest
, r_value
)));
78 let add_statement
= Statement
{
79 kind
: len_statement_kind
,
80 source_info
: terminator
.source_info
.clone(),
83 // modify terminator into simple Goto
84 let new_terminator_kind
= TerminatorKind
::Goto { target: bb.clone() }
;
86 let patch
= SliceLenPatchInformation { add_statement, new_terminator_kind }
;
88 patch_found
= Some(patch
);
96 if let Some(SliceLenPatchInformation { add_statement, new_terminator_kind }
) = patch_found
{
97 block
.statements
.push(add_statement
);
98 block
.terminator_mut().kind
= new_terminator_kind
;