@@ -11,6 +11,7 @@ use crate::MemFlags;
1111
1212use rustc_ast as ast;
1313use rustc_ast:: { InlineAsmOptions , InlineAsmTemplatePiece } ;
14+ use rustc_data_structures:: fx:: FxHashMap ;
1415use rustc_hir:: lang_items:: LangItem ;
1516use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
1617use 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