@@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue};
9
9
use rustc_middle:: ty:: Ty ;
10
10
use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
11
11
use rustc_middle:: { bug, span_bug} ;
12
+ use rustc_session:: config:: OptLevel ;
12
13
use tracing:: { debug, instrument} ;
13
14
14
15
use super :: place:: { PlaceRef , PlaceValue } ;
@@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
496
497
_ => ( tag_imm, bx. cx ( ) . immediate_backend_type ( tag_op. layout ) ) ,
497
498
} ;
498
499
500
+ // Layout ensures that we only get here for cases where the discriminant
501
+ // value and the variant index match, since that's all `Niche` can encode.
502
+ // But for emphasis and debugging, let's double-check one anyway.
503
+ debug_assert_eq ! (
504
+ self . layout
505
+ . ty
506
+ . discriminant_for_variant( bx. tcx( ) , untagged_variant)
507
+ . unwrap( )
508
+ . val,
509
+ u128 :: from( untagged_variant. as_u32( ) ) ,
510
+ ) ;
511
+
499
512
let relative_max = niche_variants. end ( ) . as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) ;
500
513
501
514
// We have a subrange `niche_start..=niche_end` inside `range`.
@@ -528,6 +541,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
528
541
bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ;
529
542
( is_niche, tagged_discr, 0 )
530
543
} else {
544
+ // Thanks to parameter attributes and load metadata, LLVM already knows
545
+ // the general valid range of the tag. It's possible, though, for there
546
+ // to be an impossible value *in the middle*, which those ranges don't
547
+ // communicate, so it's worth an `assume` to let the optimizer know.
548
+ if niche_variants. contains ( & untagged_variant)
549
+ && bx. cx ( ) . sess ( ) . opts . optimize != OptLevel :: No
550
+ {
551
+ let impossible =
552
+ untagged_variant. as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) ;
553
+ let impossible = u128:: from ( impossible) . wrapping_add ( niche_start) ;
554
+ let impossible = bx. cx ( ) . const_uint_big ( tag_llty, impossible) ;
555
+ let ne = bx. icmp ( IntPredicate :: IntNE , tag, impossible) ;
556
+ bx. assume ( ne) ;
557
+ }
558
+
531
559
// The special cases don't apply, so we'll have to go with
532
560
// the general algorithm.
533
561
let relative_discr = bx. sub ( tag, bx. cx ( ) . const_uint_big ( tag_llty, niche_start) ) ;
0 commit comments