Skip to content

Improvements to dataflow const-prop #115612

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

Merged
merged 9 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/consts/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ impl ScalarInt {
}
}

#[inline]
pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
Self::try_from_uint(i, tcx.data_layout.pointer_size)
}

#[inline]
pub fn assert_bits(self, target_size: Size) -> u128 {
self.to_bits(target_size).unwrap_or_else(|size| {
Expand Down
83 changes: 50 additions & 33 deletions compiler/rustc_mir_transform/src/dataflow_const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,47 +193,64 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
rvalue: &Rvalue<'tcx>,
state: &mut State<Self::Value>,
) -> ValueOrPlace<Self::Value> {
match rvalue {
Rvalue::Cast(
kind @ (CastKind::IntToInt
| CastKind::FloatToInt
| CastKind::FloatToFloat
| CastKind::IntToFloat),
operand,
ty,
) => match self.eval_operand(operand, state) {
FlatSet::Elem(op) => match kind {
CastKind::IntToInt | CastKind::IntToFloat => {
self.ecx.int_to_int_or_float(&op, *ty)
}
CastKind::FloatToInt | CastKind::FloatToFloat => {
self.ecx.float_to_float_or_int(&op, *ty)
}
_ => unreachable!(),
let val = match rvalue {
Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self
.ecx
.int_to_int_or_float(&op, *ty)
.map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
.map(|result| ValueOrPlace::Value(self.wrap_immediate(result)))
.unwrap_or(ValueOrPlace::TOP),
_ => ValueOrPlace::TOP,
},
}
Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self
.ecx
.float_to_float_or_int(&op, *ty)
.map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
}
Rvalue::Cast(CastKind::Transmute, operand, _) => {
match self.eval_operand(operand, state) {
FlatSet::Elem(op) => self.wrap_immediate(*op),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
}
Comment on lines +248 to +252
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FlatSet should probably have a map method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case is so rare, I'm not sure it's worth it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not important, just saw 3 occurrences of this code snippet ^^

}
Rvalue::BinaryOp(op, box (left, right)) => {
// Overflows must be ignored here.
let (val, _overflow) = self.binary_op(state, *op, left, right);
ValueOrPlace::Value(val)
val
}
Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
FlatSet::Elem(value) => self
.ecx
.unary_op(*op, &value)
.map(|val| ValueOrPlace::Value(self.wrap_immty(val)))
.unwrap_or(ValueOrPlace::Value(FlatSet::Top)),
FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom),
FlatSet::Top => ValueOrPlace::Value(FlatSet::Top),
FlatSet::Elem(value) => {
self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val))
}
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
},
Rvalue::Discriminant(place) => {
ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map()))
Rvalue::NullaryOp(null_op, ty) => {
let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
return ValueOrPlace::Value(FlatSet::Top);
};
let val = match null_op {
NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
NullOp::OffsetOf(fields) => layout
.offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index()))
.bytes(),
_ => return ValueOrPlace::Value(FlatSet::Top),
};
ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
}
_ => self.super_rvalue(rvalue, state),
}
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
_ => return self.super_rvalue(rvalue, state),
};
ValueOrPlace::Value(val)
}

fn handle_constant(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
- // MIR for `concrete` before DataflowConstProp
+ // MIR for `concrete` after DataflowConstProp

fn concrete() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug x => _1;
let _3: usize;
scope 2 {
debug y => _3;
let _5: usize;
scope 3 {
debug z0 => _5;
let _7: usize;
scope 4 {
debug z1 => _7;
}
}
}
}

bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
}

bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
}

bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
- // MIR for `concrete` before DataflowConstProp
+ // MIR for `concrete` after DataflowConstProp

fn concrete() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug x => _1;
let _3: usize;
scope 2 {
debug y => _3;
let _5: usize;
scope 3 {
debug z0 => _5;
let _7: usize;
scope 4 {
debug z1 => _7;
}
}
}
}

bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
}

bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
}

bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
}

bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
}

bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
- // MIR for `generic` before DataflowConstProp
+ // MIR for `generic` after DataflowConstProp

fn generic() -> () {
let mut _0: ();
let _1: usize;
let mut _2: usize;
let mut _4: usize;
let mut _6: usize;
let mut _8: usize;
scope 1 {
debug gx => _1;
let _3: usize;
scope 2 {
debug gy => _3;
let _5: usize;
scope 3 {
debug dx => _5;
let _7: usize;
scope 4 {
debug dy => _7;
}
}
}
}

bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = OffsetOf(Gamma<T>, [0]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
}

bb2: {
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Delta<T>, [1]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 0_usize;
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Delta<T>, [2]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 2_usize;
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
}

bb4: {
StorageDead(_8);
_0 = const ();
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);
StorageDead(_1);
return;
}
}

Loading