Skip to content

Commit

Permalink
Auto merge of #119675 - cjgillot:set-no-discriminant, r=tmiasko
Browse files Browse the repository at this point in the history
Skip threading over no-op SetDiscriminant.

Fixes #119674
  • Loading branch information
bors committed Jan 7, 2024
2 parents d8b44d2 + 41eb9a4 commit 75c68cf
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 2 deletions.
22 changes: 20 additions & 2 deletions compiler/rustc_mir_transform/src/jump_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem};
use rustc_target::abi::{TagEncoding, Variants};

use crate::cost_checker::CostChecker;

Expand Down Expand Up @@ -391,8 +392,25 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
StatementKind::SetDiscriminant { box place, variant_index } => {
let discr_target = self.map.find_discr(place.as_ref())?;
let enum_ty = place.ty(self.body, self.tcx).ty;
let discr = discriminant_for_variant(enum_ty, *variant_index)?;
self.process_operand(bb, discr_target, &discr, state)?;
// `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant
// of a niche encoding. If we cannot ensure that we write to the discriminant, do
// nothing.
let enum_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?;
let writes_discriminant = match enum_layout.variants {
Variants::Single { index } => {
assert_eq!(index, *variant_index);
true
}
Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => true,
Variants::Multiple {
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
..
} => *variant_index != untagged_variant,
};
if writes_discriminant {
let discr = discriminant_for_variant(enum_ty, *variant_index)?;
self.process_operand(bb, discr_target, &discr, state)?;
}
}
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(
Expand Down
26 changes: 26 additions & 0 deletions tests/mir-opt/set_no_discriminant.f.JumpThreading.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
- // MIR for `f` before JumpThreading
+ // MIR for `f` after JumpThreading

fn f() -> usize {
let mut _0: usize;
let mut _1: isize;
let mut _2: E<char>;

bb0: {
_2 = E::<char>::A;
discriminant(_2) = 1;
_1 = discriminant(_2);
switchInt(_1) -> [0: bb1, otherwise: bb2];
}

bb1: {
_0 = const 0_usize;
return;
}

bb2: {
_0 = const 1_usize;
return;
}
}

26 changes: 26 additions & 0 deletions tests/mir-opt/set_no_discriminant.generic.JumpThreading.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
- // MIR for `generic` before JumpThreading
+ // MIR for `generic` after JumpThreading

fn generic() -> usize {
let mut _0: usize;
let mut _1: isize;
let mut _2: E<T>;

bb0: {
_2 = E::<T>::A;
discriminant(_2) = 1;
_1 = discriminant(_2);
switchInt(_1) -> [0: bb1, otherwise: bb2];
}

bb1: {
_0 = const 0_usize;
return;
}

bb2: {
_0 = const 1_usize;
return;
}
}

78 changes: 78 additions & 0 deletions tests/mir-opt/set_no_discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// `SetDiscriminant` does not actually write anything if the chosen variant is the untagged variant
// of a niche encoding. Verify that we do not thread over this case.
// unit-test: JumpThreading

#![feature(custom_mir)]
#![feature(core_intrinsics)]

use std::intrinsics::mir::*;

enum E<T> {
A,
B(T),
}

// EMIT_MIR set_no_discriminant.f.JumpThreading.diff
#[custom_mir(dialect = "runtime")]
pub fn f() -> usize {
// CHECK-LABEL: fn f(
// CHECK-NOT: goto
// CHECK: switchInt(
// CHECK-NOT: goto
mir!(
let a: isize;
let e: E<char>;
{
e = E::A;
SetDiscriminant(e, 1);
a = Discriminant(e);
match a {
0 => bb0,
_ => bb1,
}
}
bb0 = {
RET = 0;
Return()
}
bb1 = {
RET = 1;
Return()
}
)
}

// EMIT_MIR set_no_discriminant.generic.JumpThreading.diff
#[custom_mir(dialect = "runtime")]
pub fn generic<T>() -> usize {
// CHECK-LABEL: fn generic(
// CHECK-NOT: goto
// CHECK: switchInt(
// CHECK-NOT: goto
mir!(
let a: isize;
let e: E<T>;
{
e = E::A;
SetDiscriminant(e, 1);
a = Discriminant(e);
match a {
0 => bb0,
_ => bb1,
}
}
bb0 = {
RET = 0;
Return()
}
bb1 = {
RET = 1;
Return()
}
)
}

fn main() {
assert_eq!(f(), 0);
assert_eq!(generic::<char>(), 0);
}

0 comments on commit 75c68cf

Please sign in to comment.