@@ -11,6 +11,7 @@ use crate::MemFlags;
11
11
12
12
use rustc_ast as ast;
13
13
use rustc_ast:: { InlineAsmOptions , InlineAsmTemplatePiece } ;
14
+ use rustc_data_structures:: fx:: FxHashMap ;
14
15
use rustc_hir:: lang_items:: LangItem ;
15
16
use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
16
17
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
@@ -311,15 +312,91 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
311
312
}
312
313
}
313
314
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
+
314
391
fn codegen_switchint_terminator (
315
392
& mut self ,
316
393
helper : TerminatorCodegenHelper < ' tcx > ,
317
394
bx : & mut Bx ,
318
395
bb : mir:: BasicBlock ,
319
- discr : & mir:: Operand < ' tcx > ,
396
+ mir_discr : & mir:: Operand < ' tcx > ,
320
397
targets : & SwitchTargets ,
321
398
) {
322
- let discr = self . codegen_operand ( bx, discr ) ;
399
+ let discr = self . codegen_operand ( bx, mir_discr ) ;
323
400
let switch_ty = discr. layout . ty ;
324
401
let mut target_iter = targets. iter ( ) ;
325
402
if target_iter. len ( ) == 1 {
@@ -329,17 +406,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
329
406
let lltrue = helper. llbb_with_cleanup ( self , target) ;
330
407
let llfalse = helper. llbb_with_cleanup ( self , targets. otherwise ( ) ) ;
331
408
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) ;
343
410
344
411
// Don't generate trivial icmps when switching on bool.
345
412
match test_value {
0 commit comments