1 //! Finds locals which are assigned once to a const and unused except for debuginfo and converts
2 //! their debuginfo to use the const directly, allowing the local to be removed.
6 visit
::{PlaceContext, Visitor}
,
7 Body
, Constant
, Local
, Location
, Operand
, Rvalue
, StatementKind
, VarDebugInfoContents
,
13 use rustc_index
::{bit_set::BitSet, vec::IndexVec}
;
15 pub struct ConstDebugInfo
;
17 impl<'tcx
> MirPass
<'tcx
> for ConstDebugInfo
{
18 fn is_enabled(&self, sess
: &rustc_session
::Session
) -> bool
{
19 sess
.opts
.debugging_opts
.unsound_mir_opts
&& sess
.mir_opt_level() > 0
22 fn run_pass(&self, _tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
23 trace
!("running ConstDebugInfo on {:?}", body
.source
);
25 for (local
, constant
) in find_optimization_oportunities(body
) {
26 for debuginfo
in &mut body
.var_debug_info
{
27 if let VarDebugInfoContents
::Place(p
) = debuginfo
.value
{
28 if p
.local
== local
&& p
.projection
.is_empty() {
30 "changing debug info for {:?} from place {:?} to constant {:?}",
35 debuginfo
.value
= VarDebugInfoContents
::Const(constant
);
43 struct LocalUseVisitor
{
44 local_mutating_uses
: IndexVec
<Local
, u8>,
45 local_assignment_locations
: IndexVec
<Local
, Option
<Location
>>,
48 fn find_optimization_oportunities
<'tcx
>(body
: &Body
<'tcx
>) -> Vec
<(Local
, Constant
<'tcx
>)> {
49 let mut visitor
= LocalUseVisitor
{
50 local_mutating_uses
: IndexVec
::from_elem(0, &body
.local_decls
),
51 local_assignment_locations
: IndexVec
::from_elem(None
, &body
.local_decls
),
54 visitor
.visit_body(body
);
56 let mut locals_to_debuginfo
= BitSet
::new_empty(body
.local_decls
.len());
57 for debuginfo
in &body
.var_debug_info
{
58 if let VarDebugInfoContents
::Place(p
) = debuginfo
.value
&& let Some(l
) = p
.as_local() {
59 locals_to_debuginfo
.insert(l
);
63 let mut eligible_locals
= Vec
::new();
64 for (local
, mutating_uses
) in visitor
.local_mutating_uses
.drain_enumerated(..) {
65 if mutating_uses
!= 1 || !locals_to_debuginfo
.contains(local
) {
69 if let Some(location
) = visitor
.local_assignment_locations
[local
] {
70 let bb
= &body
[location
.block
];
72 // The value is assigned as the result of a call, not a constant
73 if bb
.statements
.len() == location
.statement_index
{
77 if let StatementKind
::Assign(box (p
, Rvalue
::Use(Operand
::Constant(box c
)))) =
78 &bb
.statements
[location
.statement_index
].kind
80 if let Some(local
) = p
.as_local() {
81 eligible_locals
.push((local
, *c
));
90 impl Visitor
<'_
> for LocalUseVisitor
{
91 fn visit_local(&mut self, local
: &Local
, context
: PlaceContext
, location
: Location
) {
92 if context
.is_mutating_use() {
93 self.local_mutating_uses
[*local
] = self.local_mutating_uses
[*local
].saturating_add(1);
95 if context
.is_place_assignment() {
96 self.local_assignment_locations
[*local
] = Some(location
);