-
Notifications
You must be signed in to change notification settings - Fork 13.4k
add visit_operand
to const prop
#74507
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -582,6 +582,34 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | |
Some(()) | ||
} | ||
|
||
fn propagate_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { | ||
match *operand { | ||
Operand::Copy(l) | Operand::Move(l) => { | ||
if let Some(value) = self.get_const(l) { | ||
if self.should_const_prop(value) { | ||
// FIXME(felix91gr): this code only handles `Scalar` cases. | ||
// For now, we're not handling `ScalarPair` cases because | ||
// doing so here would require a lot of code duplication. | ||
// We should hopefully generalize `Operand` handling into a fn, | ||
// and use it to do const-prop here and everywhere else | ||
// where it makes sense. | ||
if let interpret::Operand::Immediate(interpret::Immediate::Scalar( | ||
ScalarMaybeUninit::Scalar(scalar), | ||
)) = *value | ||
{ | ||
*operand = self.operand_from_scalar( | ||
scalar, | ||
value.layout.ty, | ||
self.source_info.unwrap().span, | ||
); | ||
} | ||
} | ||
} | ||
} | ||
Operand::Constant(ref mut ct) => self.visit_constant(ct, location), | ||
} | ||
} | ||
|
||
fn const_prop( | ||
&mut self, | ||
rvalue: &Rvalue<'tcx>, | ||
|
@@ -905,6 +933,16 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | |
} | ||
} | ||
|
||
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { | ||
// Only const prop copies and moves on `mir_opt_level=3` as doing so | ||
// currently increases compile time. | ||
if self.tcx.sess.opts.debugging_opts.mir_opt_level < 3 { | ||
self.super_operand(operand, location) | ||
} else { | ||
self.propagate_operand(operand, location) | ||
} | ||
} | ||
|
||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { | ||
trace!("visit_constant: {:?}", constant); | ||
self.super_constant(constant, location); | ||
|
@@ -1072,18 +1110,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | |
} | ||
} | ||
} | ||
TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => { | ||
if let Some(value) = self.eval_operand(&discr, source_info) { | ||
if self.should_const_prop(value) { | ||
if let ScalarMaybeUninit::Scalar(scalar) = | ||
self.ecx.read_scalar(value).unwrap() | ||
{ | ||
*discr = self.operand_from_scalar(scalar, switch_ty, source_info.span); | ||
} | ||
} | ||
} | ||
TerminatorKind::SwitchInt { ref mut discr, .. } => { | ||
// FIXME: This is currently redundant with `visit_operand`, but sadly | ||
// always visiting operands currently causes a perf regression, so | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could be worth mentioning the perf regression is not due to the cost of actually visiting the operands but the changes it causes to MIR code |
||
// `visit_operand` currently only runs for propagates places for `mir_opt_level=3`. | ||
self.propagate_operand(discr, location) | ||
} | ||
// None of these have Operands to const-propagate | ||
// None of these have Operands to const-propagate. | ||
TerminatorKind::Goto { .. } | ||
| TerminatorKind::Resume | ||
| TerminatorKind::Abort | ||
|
@@ -1096,61 +1129,16 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | |
| TerminatorKind::FalseEdge { .. } | ||
| TerminatorKind::FalseUnwind { .. } | ||
| TerminatorKind::InlineAsm { .. } => {} | ||
// Every argument in our function calls can be const propagated. | ||
TerminatorKind::Call { ref mut args, .. } => { | ||
let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; | ||
// Constant Propagation into function call arguments is gated | ||
// under mir-opt-level 2, because LLVM codegen gives performance | ||
// regressions with it. | ||
if mir_opt_level >= 2 { | ||
for opr in args { | ||
/* | ||
The following code would appear to be incomplete, because | ||
the function `Operand::place()` returns `None` if the | ||
`Operand` is of the variant `Operand::Constant`. In this | ||
context however, that variant will never appear. This is why: | ||
|
||
When constructing the MIR, all function call arguments are | ||
copied into `Locals` of `LocalKind::Temp`. At least, all arguments | ||
that are not unsized (Less than 0.1% are unsized. See #71170 | ||
to learn more about those). | ||
|
||
This means that, conversely, all `Operands` found as function call | ||
arguments are of the variant `Operand::Copy`. This allows us to | ||
simplify our handling of `Operands` in this case. | ||
*/ | ||
if let Some(l) = opr.place() { | ||
if let Some(value) = self.get_const(l) { | ||
if self.should_const_prop(value) { | ||
// FIXME(felix91gr): this code only handles `Scalar` cases. | ||
// For now, we're not handling `ScalarPair` cases because | ||
// doing so here would require a lot of code duplication. | ||
// We should hopefully generalize `Operand` handling into a fn, | ||
// and use it to do const-prop here and everywhere else | ||
// where it makes sense. | ||
if let interpret::Operand::Immediate( | ||
interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar( | ||
scalar, | ||
)), | ||
) = *value | ||
{ | ||
*opr = self.operand_from_scalar( | ||
scalar, | ||
value.layout.ty, | ||
source_info.span, | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// Every argument in our function calls have already been propagated in `visit_operand`. | ||
// | ||
// NOTE: because LLVM codegen gives performance regressions with it, so this is gated | ||
// on `mir_opt_level=3`. | ||
TerminatorKind::Call { .. } => {} | ||
} | ||
|
||
// We remove all Locals which are restricted in propagation to their containing blocks and | ||
// which were modified in the current block. | ||
// Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const` | ||
// Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. | ||
let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); | ||
for &local in locals.iter() { | ||
Self::remove_const(&mut self.ecx, local); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,13 +64,25 @@ | |
+ // mir::Constant | ||
+ // + span: $DIR/array_index.rs:5:18: 5:33 | ||
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } | ||
+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 | ||
+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 | ||
+ // ty::Const | ||
+ // + ty: bool | ||
+ // + val: Value(Scalar(0x01)) | ||
+ // mir::Constant | ||
+ // + span: $DIR/array_index.rs:5:18: 5:33 | ||
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } | ||
+ // ty::Const | ||
+ // + ty: usize | ||
+ // + val: Value(Scalar(0x00000004)) | ||
+ // mir::Constant | ||
+ // + span: $DIR/array_index.rs:5:18: 5:33 | ||
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000004)) } | ||
+ // ty::Const | ||
+ // + ty: usize | ||
+ // + val: Value(Scalar(0x00000002)) | ||
+ // mir::Constant | ||
+ // + span: $DIR/array_index.rs:5:18: 5:33 | ||
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh god these comments are really annoying 😆 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i really wish there rwas a way to suppress all the comments in MIR dumps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
bb1: { | ||
|
Uh oh!
There was an error while loading. Please reload this page.