Skip to content

Commit fccc37f

Browse files
committed
Make all constants of primitive type deterministic.
1 parent 76ba04b commit fccc37f

13 files changed

+59
-32
lines changed

compiler/rustc_middle/src/mir/consts.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,11 @@ impl<'tcx> Const<'tcx> {
495495
/// Return true if any evaluation of this constant always returns the same value,
496496
/// taking into account even pointer identity tests.
497497
pub fn is_deterministic(&self) -> bool {
498+
if self.ty().is_primitive() {
499+
// Primitive types hold no provenance, so their result is deterministic.
500+
return true;
501+
}
502+
498503
// Some constants may generate fresh allocations for pointers they contain,
499504
// so using the same constant twice can yield two different results.
500505
// Notably, valtrees purposefully generate new allocations.

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -983,16 +983,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
983983
operand: &mut Operand<'tcx>,
984984
location: Location,
985985
) -> Option<VnIndex> {
986-
match *operand {
987-
Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)),
986+
let value = match *operand {
987+
Operand::Constant(ref constant) => self.insert_constant(constant.const_),
988988
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
989-
let value = self.simplify_place_value(place, location)?;
990-
if let Some(const_) = self.try_as_constant(value) {
991-
*operand = Operand::Constant(Box::new(const_));
992-
}
993-
Some(value)
989+
self.simplify_place_value(place, location)?
994990
}
991+
};
992+
if let Some(const_) = self.try_as_constant(value) {
993+
*operand = Operand::Constant(Box::new(const_));
995994
}
995+
Some(value)
996996
}
997997

998998
#[instrument(level = "trace", skip(self), ret)]
@@ -1763,14 +1763,30 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17631763

17641764
/// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
17651765
fn try_as_constant(&mut self, index: VnIndex) -> Option<ConstOperand<'tcx>> {
1766-
// This was already constant in MIR, do not change it. If the constant is not
1767-
// deterministic, adding an additional mention of it in MIR will not give the same value as
1768-
// the former mention.
1769-
if let Value::Constant { value, disambiguator: None } = self.get(index) {
1766+
let value = self.get(index);
1767+
1768+
// This was already an *evaluated* constant in MIR, do not change it.
1769+
if let Value::Constant { value, disambiguator: None } = value
1770+
&& let Const::Val(..) = value
1771+
{
1772+
debug_assert!(value.is_deterministic());
1773+
return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value });
1774+
}
1775+
1776+
if let Some(value) = self.try_as_evaluated_constant(index) {
1777+
return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value });
1778+
}
1779+
1780+
// We failed to provide an evaluated form, fallback to using the unevaluated constant.
1781+
if let Value::Constant { value, disambiguator: None } = value {
17701782
debug_assert!(value.is_deterministic());
17711783
return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value });
17721784
}
17731785

1786+
None
1787+
}
1788+
1789+
fn try_as_evaluated_constant(&mut self, index: VnIndex) -> Option<Const<'tcx>> {
17741790
let op = self.evaluated[index].as_ref()?;
17751791
if op.layout.is_unsized() {
17761792
// Do not attempt to propagate unsized locals.
@@ -1784,8 +1800,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17841800
// FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
17851801
assert!(!value.may_have_provenance(self.tcx, op.layout.size));
17861802

1787-
let const_ = Const::Val(value, op.layout.ty);
1788-
Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_ })
1803+
Some(Const::Val(value, op.layout.ty))
17891804
}
17901805

17911806
/// Construct a place which holds the same value as `index` and for which all locals strictly

tests/mir-opt/building/match/sort_candidates.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
// Check specific cases of sorting candidates in match lowering.
1+
//! Check specific cases of sorting candidates in match lowering.
2+
//@ compile-flags: -Zmir-opt-level=0
23

34
// EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
45
fn constant_eq(s: &str, b: bool) -> u32 {
56
// Check that we only test "a" once
67

78
// CHECK-LABEL: fn constant_eq(
89
// CHECK-NOT: const "a"
9-
// CHECK: {{_[0-9]+}} = const "a" as &[u8] (Transmute);
10+
// CHECK: eq({{.*}}, const "a")
1011
// CHECK-NOT: const "a"
1112
match (s, b) {
1213
("a", _) if true => 1,
@@ -23,11 +24,16 @@ fn disjoint_ranges(x: i32, b: bool) -> u32 {
2324
// other candidates.
2425

2526
// CHECK-LABEL: fn disjoint_ranges(
26-
// CHECK: debug b => _2;
27-
// CHECK: bb0: {
28-
// CHECK: switchInt(copy _2) -> [0: [[jump:bb.*]], otherwise: {{bb.*}}];
27+
// CHECK: debug b => [[b:_.*]];
28+
// CHECK: [[tmp:_.*]] = copy [[b]];
29+
// CHECK-NEXT: switchInt(move [[tmp]]) -> [0: [[jump:bb.*]], otherwise: {{bb.*}}];
2930
// CHECK: [[jump]]: {
31+
// CHECK-NEXT: StorageDead([[tmp]]);
32+
// CHECK-NEXT: goto -> [[jump3:bb.*]];
33+
// CHECK: [[jump3]]: {
3034
// CHECK-NEXT: _0 = const 3_u32;
35+
// CHECK-NEXT: goto -> [[jumpret:bb.*]];
36+
// CHECK: [[jumpret]]: {
3137
// CHECK-NEXT: return;
3238
match x {
3339
0..10 if b => 0,

tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
StorageLive(_20);
4848
StorageLive(_21);
4949
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
50-
_20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG);
50+
_20 = BitAnd(move _21, const 2097152_u32);
5151
StorageDead(_21);
5252
_4 = Ne(move _20, const 0_u32);
5353
StorageDead(_20);
@@ -72,7 +72,7 @@
7272
StorageLive(_22);
7373
StorageLive(_23);
7474
_23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
75-
_22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
75+
_22 = BitAnd(move _23, const 268435456_u32);
7676
StorageDead(_23);
7777
switchInt(move _22) -> [0: bb10, otherwise: bb11];
7878
}

tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
StorageLive(_20);
4848
StorageLive(_21);
4949
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
50-
_20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG);
50+
_20 = BitAnd(move _21, const 2097152_u32);
5151
StorageDead(_21);
5252
_4 = Ne(move _20, const 0_u32);
5353
StorageDead(_20);
@@ -72,7 +72,7 @@
7272
StorageLive(_22);
7373
StorageLive(_23);
7474
_23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
75-
_22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
75+
_22 = BitAnd(move _23, const 268435456_u32);
7676
StorageDead(_23);
7777
switchInt(move _22) -> [0: bb10, otherwise: bb11];
7878
}

tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
StorageLive(_20);
4848
StorageLive(_21);
4949
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
50-
_20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG);
50+
_20 = BitAnd(move _21, const 2097152_u32);
5151
StorageDead(_21);
5252
_4 = Ne(move _20, const 0_u32);
5353
StorageDead(_20);
@@ -72,7 +72,7 @@
7272
StorageLive(_22);
7373
StorageLive(_23);
7474
_23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
75-
_22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
75+
_22 = BitAnd(move _23, const 268435456_u32);
7676
StorageDead(_23);
7777
switchInt(move _22) -> [0: bb10, otherwise: bb11];
7878
}

tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
StorageLive(_20);
4848
StorageLive(_21);
4949
_21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
50-
_20 = BitAnd(move _21, const core::fmt::flags::SIGN_PLUS_FLAG);
50+
_20 = BitAnd(move _21, const 2097152_u32);
5151
StorageDead(_21);
5252
_4 = Ne(move _20, const 0_u32);
5353
StorageDead(_20);
@@ -72,7 +72,7 @@
7272
StorageLive(_22);
7373
StorageLive(_23);
7474
_23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32);
75-
_22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG);
75+
_22 = BitAnd(move _23, const 268435456_u32);
7676
StorageDead(_23);
7777
switchInt(move _22) -> [0: bb10, otherwise: bb11];
7878
}

tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
let mut _0: bool;
66

77
bb0: {
8-
_0 = Eq(const no_optimize::<T>::{constant#0}, const no_optimize::<T>::{constant#1});
8+
- _0 = Eq(const no_optimize::<T>::{constant#0}, const no_optimize::<T>::{constant#1});
9+
+ _0 = Eq(const no_optimize::<T>::{constant#0}, const true);
910
return;
1011
}
1112
}

tests/mir-opt/gvn_const_eval_polymorphic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn optimize_false<T>() -> bool {
5151
// EMIT_MIR gvn_const_eval_polymorphic.no_optimize.GVN.diff
5252
fn no_optimize<T>() -> bool {
5353
// CHECK-LABEL: fn no_optimize(
54-
// CHECK: _0 = Eq(const no_optimize::<T>::{constant#0}, const no_optimize::<T>::{constant#1});
54+
// CHECK: _0 = Eq(const no_optimize::<T>::{constant#0}, const true);
5555
// CHECK-NEXT: return;
5656
(const { type_name_contains_i32(&generic::<T>) }) == const { true }
5757
}

tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
1717

1818
bb0: {
1919
StorageLive(_3);
20-
_3 = Lt(copy _2, const core::num::<impl u32>::BITS);
20+
_3 = Lt(copy _2, const 32_u32);
2121
switchInt(move _3) -> [0: bb1, otherwise: bb2];
2222
}
2323

0 commit comments

Comments
 (0)