13
13
//!
14
14
15
15
use rustc_index:: bit_set:: BitSet ;
16
+ use rustc_middle:: mir:: visit:: Visitor ;
16
17
use rustc_middle:: mir:: * ;
17
18
use 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
+ } ;
19
22
use rustc_mir_dataflow:: Analysis ;
20
23
21
24
/// Performs the optimization on the body
@@ -28,8 +31,33 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
28
31
. iterate_to_fixpoint ( )
29
32
. into_results_cursor ( body) ;
30
33
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 ( ) ;
31
37
let mut patch = Vec :: new ( ) ;
38
+
32
39
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
+
33
61
for ( statement_index, statement) in bb_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
34
62
let loc = Location { block : bb, statement_index } ;
35
63
if let StatementKind :: Assign ( assign) = & statement. kind {
@@ -64,14 +92,22 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
64
92
}
65
93
}
66
94
67
- if patch. is_empty ( ) {
95
+ if patch. is_empty ( ) && call_operands_to_move . is_empty ( ) {
68
96
return ;
69
97
}
70
98
71
99
let bbs = body. basic_blocks . as_mut_preserves_cfg ( ) ;
72
100
for Location { block, statement_index } in patch {
73
101
bbs[ block] . statements [ statement_index] . make_nop ( ) ;
74
102
}
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
+ }
75
111
76
112
crate :: simplify:: simplify_locals ( body, tcx)
77
113
}
0 commit comments