-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove unused discriminant reads from MIR bodies #70595
Remove unused discriminant reads from MIR bodies #70595
Conversation
@@ -382,6 +382,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { | |||
} | |||
} | |||
} | |||
} else if let StatementKind::Assign(box (p, Rvalue::Discriminant(d))) = &stmt.kind { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any Rvalue
s (except those that reference a ConstKind::Unevaluated
, which I'm working on) that have side effects? I think we could use a visitor here looking for ConstKind::Unevaluated
and remove the assignment if there is no Unevaluated
in that Rvalue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I don't think we have side effects in the sense that there might be a user-defined function call or something hiding in an Rvalue
(excluding ConstKind::Unevaluated
). However there are somethings that might be termed side effects like:
-
de-referencing a pointer
- Removing a deref means we could potentially be removing UB if the pointer isn't actually valid. That seems ok to me.
-
Boxing values
- I believe this lowers to a call to the global allocator which means you could observe this not happening via a custom allocator.
-
{Checked,}Binary ops could over/under flow.
In general, Rvalues
except for these seem side-effect free to me (excluding ConstKind::Unevaluated
and things that contain Place
values with projections):
BinaryOp
CheckedBinaryOp
Cast
NullaryOp
UnaryOp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CheckedBinaryOp
doesn't have a side-effect as over/under flow will just return that it had over/under flowed. UnaryOp
is used to implement both negation and bitwise not. The later is always side-effect free. Cast(CatKind::Pointer(_), _, _)
is side-effect free I think, but Cast(CastKind::Misc, _, _)
could remove a ptr-int cast or int-ptr cast. NullaryOp(NullOp::SizeOf, ty)
only needs to ensure that layout_of
doesn't error on the type.
Boxing values
* I believe this lowers to a call to the global allocator which means you could observe this _not_ happening via a custom allocator.
Yes, it lowers to the exchange_malloc
lang item, which uses Global.alloc
:
Line 225 in dd155df
match Global.alloc(layout) { |
Removing this allocation would be equivalent to any function in liballoc or libstd changing when and how much it allocates though, so I don't think anybody can depend on it anyway.
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
Outdated
Show resolved
Hide resolved
90732cf
to
bd99533
Compare
@@ -382,6 +382,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { | |||
} | |||
} | |||
} | |||
} else if let StatementKind::Assign(box (p, Rvalue::Discriminant(d))) = &stmt.kind { | |||
if !p.is_indirect() { | |||
trace!("skipping store of discriminant value {:?} to {:?}", d, p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This confused me at first, but basically this is treating certain initializers as not keeping the destination alive, right?
Something very important in these checks though: you need to make sure p.local
is local
otherwise it may be somewhere else in the statement (you shouldn't trust ctx
to let you know where it is, IMO).
Also, it would be nice if if let StatementKind::Assign(box (p,
was only once, and then the only check for the Rvalue
was whether we consider it to have side-effects.
Also, does this pass re-run itself to fixpoint? Because if you remove an assignment to a dead local, you remove uses of other locals also mentioned in that assignment, which may be their last.
You can't do this in one pass because e.g. in x = y
, y
might be unused only if x
is unused, and you can't know that ahead of time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basically this is treating certain initializers as not keeping the destination alive, right?
Yup, that's correct.
Something very important in these checks though: you need to make sure p.local is local otherwise it may be somewhere else in the statement (you shouldn't trust ctx to let you know where it is, IMO).
I'm struggling to think of a case where that would happen. Do you have an example in mind?
Also, does this pass re-run itself to fixpoint? Because if you remove an assignment to a dead local, you remove uses of other locals also mentioned in that assignment, which may be their last.
It doesn't currently. That would be a good improvement though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm struggling to think of a case where that would happen. Do you have an example in mind?
The point is to check instead of assuming, especially in this case where it's basically free.
If nothing else it serves as self-documenting code.
@bors r+ Please open issues for
|
📌 Commit bd99533f18134d6ab4b2dbebcf2844a351a22c45 has been approved by |
🌲 The tree is currently closed for pull requests below priority 500, this pull request will be tested once the tree is reopened |
@bors r- I still want the change for checking |
Allow the `SimplifyLocals` pass to remove reads of discriminants if the read is never used.
bd99533
to
75e2e8c
Compare
@bors r+ |
📌 Commit 75e2e8c has been approved by |
…ant_reads, r=oli-obk Remove unused discriminant reads from MIR bodies Allow the `SimplifyLocals` pass to remove reads of discriminants if the read is never used. Fixes rust-lang#70531 r? @oli-obk
Rollup of 7 pull requests Successful merges: - rust-lang#70487 (Stabilize float::to_int_unchecked) - rust-lang#70595 (Remove unused discriminant reads from MIR bodies) - rust-lang#70691 (Improve docs in `AllocRef`) - rust-lang#70694 (Use Self over specific type in return position) - rust-lang#70700 (Expand on platform details of `include_xxx` macros) - rust-lang#70708 (Fix typo in u8::to_ascii_uppercase and u8::to_ascii_lowercase) - rust-lang#70716 (Unerase regions in infer_placeholder_type) Failed merges: r? @ghost
…c_boogaloo, r=oli-obk [mir-opt] Run SimplifyLocals to a fixedpoint and handle most rvalues Follow up to review feedback left on rust-lang#70595.
Allow the
SimplifyLocals
pass to remove reads of discriminants if theread is never used.
Fixes #70531
r? @oli-obk