@@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue};
99use rustc_middle:: ty:: Ty ;
1010use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
1111use rustc_middle:: { bug, span_bug} ;
12+ use rustc_session:: config:: OptLevel ;
1213use tracing:: { debug, instrument} ;
1314
1415use super :: place:: { PlaceRef , PlaceValue } ;
@@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
496497 _ => ( tag_imm, bx. cx ( ) . immediate_backend_type ( tag_op. layout ) ) ,
497498 } ;
498499
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+
499512 let relative_max = niche_variants. end ( ) . as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) ;
500513
501514 // We have a subrange `niche_start..=niche_end` inside `range`.
@@ -528,6 +541,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
528541 bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ;
529542 ( is_niche, tagged_discr, 0 )
530543 } 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+
531559 // The special cases don't apply, so we'll have to go with
532560 // the general algorithm.
533561 let relative_discr = bx. sub ( tag, bx. cx ( ) . const_uint_big ( tag_llty, niche_start) ) ;
0 commit comments