Skip to content

Commit 3a0d6cd

Browse files
committed
review updates - handling the case when Expect is not right before a switch
1 parent 990ba65 commit 3a0d6cd

File tree

1 file changed

+80
-13
lines changed
  • compiler/rustc_codegen_ssa/src/mir

1 file changed

+80
-13
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+80-13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::MemFlags;
1111

1212
use rustc_ast as ast;
1313
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
14+
use rustc_data_structures::fx::FxHashMap;
1415
use rustc_hir::lang_items::LangItem;
1516
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
1617
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
@@ -311,15 +312,91 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
311312
}
312313
}
313314

315+
fn get_expectation(
316+
&mut self,
317+
bb: mir::BasicBlock,
318+
discr: &mir::Operand<'tcx>,
319+
) -> Option<mir::ExpectKind> {
320+
// First do a quick test if there are any `expect` intrinsics in the BB.
321+
322+
let Some(discr) = discr.place() else {
323+
return None;
324+
};
325+
326+
let no_expect = self.mir[bb].statements.iter().all(|stmt| {
327+
let is_expect =
328+
if let mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::Expect(..)) =
329+
stmt.kind
330+
{
331+
true
332+
} else {
333+
false
334+
};
335+
!is_expect
336+
});
337+
if no_expect {
338+
return None;
339+
}
340+
341+
// There are `expect` intrinsics in the BB, so we need to do the full analysis.
342+
343+
// Groups of variables which have the same value
344+
let mut groups = Vec::new();
345+
// Map from variable to group index
346+
let mut map = FxHashMap::<mir::Place<'tcx>, usize>::default();
347+
348+
for stmt in &self.mir[bb].statements {
349+
match stmt.kind {
350+
// For `expect` intrinsic, mark the entire group as having the expected value.
351+
mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::Expect(
352+
mir::Operand::Copy(ref place),
353+
expect_kind,
354+
)) => {
355+
if let Some(index) = map.get(place) {
356+
groups[*index] = Some(expect_kind);
357+
} else {
358+
map.insert(*place, groups.len());
359+
groups.push(Some(expect_kind));
360+
}
361+
}
362+
363+
// For assignments:
364+
// - if we understand the RHS, add LHS to the same group
365+
// - if we don't understand the RHS, remove LHS from any group,
366+
// so that it doesn't have any expected value
367+
mir::StatementKind::Assign(box (ref lhs, mir::Rvalue::Use(ref op))) => {
368+
let Some(rhs) = op.place() else {
369+
map.remove(lhs);
370+
continue;
371+
};
372+
373+
if let Some(index) = map.get(&rhs) {
374+
map.insert(*lhs, *index);
375+
} else {
376+
map.insert(rhs, groups.len());
377+
map.insert(*lhs, groups.len());
378+
groups.push(None);
379+
}
380+
}
381+
382+
// Ignore all other statements
383+
_ => {}
384+
}
385+
}
386+
387+
// Return the expected value for the group that the discriminant belongs to.
388+
map.get(&discr).and_then(|index| groups[*index])
389+
}
390+
314391
fn codegen_switchint_terminator(
315392
&mut self,
316393
helper: TerminatorCodegenHelper<'tcx>,
317394
bx: &mut Bx,
318395
bb: mir::BasicBlock,
319-
discr: &mir::Operand<'tcx>,
396+
mir_discr: &mir::Operand<'tcx>,
320397
targets: &SwitchTargets,
321398
) {
322-
let discr = self.codegen_operand(bx, discr);
399+
let discr = self.codegen_operand(bx, mir_discr);
323400
let switch_ty = discr.layout.ty;
324401
let mut target_iter = targets.iter();
325402
if target_iter.len() == 1 {
@@ -329,17 +406,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
329406
let lltrue = helper.llbb_with_cleanup(self, target);
330407
let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
331408
if switch_ty == bx.tcx().types.bool {
332-
let expect = if let Some(stmt) = self.mir[bb].statements.last()
333-
&& let mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::Expect(
334-
op,
335-
expect_kind,
336-
)) = &stmt.kind
337-
&& self.codegen_operand(bx, op).immediate() == discr.immediate()
338-
{
339-
Some(*expect_kind)
340-
} else {
341-
None
342-
};
409+
let expect = self.get_expectation(bb, mir_discr);
343410

344411
// Don't generate trivial icmps when switching on bool.
345412
match test_value {

0 commit comments

Comments
 (0)