1313//!
1414
1515use rustc_index:: bit_set:: BitSet ;
16+ use rustc_middle:: mir:: visit:: Visitor ;
1617use rustc_middle:: mir:: * ;
1718use rustc_middle:: ty:: TyCtxt ;
18- use rustc_mir_dataflow:: impls:: { borrowed_locals, MaybeTransitiveLiveLocals } ;
19+ use rustc_mir_dataflow:: impls:: {
20+ borrowed_locals, LivenessTransferFunction , MaybeTransitiveLiveLocals ,
21+ } ;
1922use rustc_mir_dataflow:: Analysis ;
2023
2124/// Performs the optimization on the body
@@ -28,8 +31,33 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
2831 . iterate_to_fixpoint ( )
2932 . into_results_cursor ( body) ;
3033
34+ // For blocks with a call terminator, if an argument copy can be turned into a move,
35+ // record it as (block, argument index).
36+ let mut call_operands_to_move = Vec :: new ( ) ;
3137 let mut patch = Vec :: new ( ) ;
38+
3239 for ( bb, bb_data) in traversal:: preorder ( body) {
40+ if let TerminatorKind :: Call { ref args, .. } = bb_data. terminator ( ) . kind {
41+ let loc = Location { block : bb, statement_index : bb_data. statements . len ( ) } ;
42+
43+ // Position ourselves between the evaluation of `args` and the write to `destination`.
44+ live. seek_to_block_end ( bb) ;
45+ let mut state = live. get ( ) . clone ( ) ;
46+
47+ for ( index, arg) in args. iter ( ) . enumerate ( ) . rev ( ) {
48+ if let Operand :: Copy ( place) = * arg
49+ && !place. is_indirect ( )
50+ && !borrowed. contains ( place. local )
51+ && !state. contains ( place. local )
52+ {
53+ call_operands_to_move. push ( ( bb, index) ) ;
54+ }
55+
56+ // Account that `arg` is read from, so we don't promote another argument to a move.
57+ LivenessTransferFunction ( & mut state) . visit_operand ( arg, loc) ;
58+ }
59+ }
60+
3361 for ( statement_index, statement) in bb_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
3462 let loc = Location { block : bb, statement_index } ;
3563 if let StatementKind :: Assign ( assign) = & statement. kind {
@@ -64,14 +92,22 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
6492 }
6593 }
6694
67- if patch. is_empty ( ) {
95+ if patch. is_empty ( ) && call_operands_to_move . is_empty ( ) {
6896 return ;
6997 }
7098
7199 let bbs = body. basic_blocks . as_mut_preserves_cfg ( ) ;
72100 for Location { block, statement_index } in patch {
73101 bbs[ block] . statements [ statement_index] . make_nop ( ) ;
74102 }
103+ for ( block, argument_index) in call_operands_to_move {
104+ let TerminatorKind :: Call { ref mut args, .. } = bbs[ block] . terminator_mut ( ) . kind else {
105+ bug ! ( )
106+ } ;
107+ let arg = & mut args[ argument_index] ;
108+ let Operand :: Copy ( place) = * arg else { bug ! ( ) } ;
109+ * arg = Operand :: Move ( place) ;
110+ }
75111
76112 crate :: simplify:: simplify_locals ( body, tcx)
77113}
0 commit comments