@@ -517,8 +517,52 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
517
517
bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ;
518
518
( is_niche, tagged_discr, 0 )
519
519
} else {
520
- // The special cases don't apply, so we'll have to go with
521
- // the general algorithm.
520
+ // With multiple niched variants we'll have to actually compute
521
+ // the variant index from the stored tag.
522
+ //
523
+ // However, there's still one small optimization we can often do for
524
+ // determining *whether* a tag value is a natural value or a niched
525
+ // variant. The general algorithm involves a subtraction that often
526
+ // wraps in practice, making it tricky to analyse. However, in cases
527
+ // where there are few enough possible values of the tag that it doesn't
528
+ // need to wrap around, we can instead just look for the contiguous
529
+ // tag values on the end of the range with a single comparison.
530
+ //
531
+ // For example, take the type `enum Demo { A, B, Untagged(bool) }`.
532
+ // The `bool` is {0, 1}, and the two other variants are given the
533
+ // tags {2, 3} respectively. That means the `tag_range` is
534
+ // `[0, 3]`, which doesn't wrap as unsigned (nor as signed), so
535
+ // we can test for the niched variants with just `>= 2`.
536
+ //
537
+ // That means we're looking either for the niche values *above*
538
+ // the natural values of the untagged variant:
539
+ //
540
+ // niche_start niche_end
541
+ // | |
542
+ // v v
543
+ // MIN -------------+---------------------------+---------- MAX
544
+ // ^ | is niche |
545
+ // | +---------------------------+
546
+ // | |
547
+ // tag_range.start tag_range.end
548
+ //
549
+ // Or *below* the natural values:
550
+ //
551
+ // niche_start niche_end
552
+ // | |
553
+ // v v
554
+ // MIN ----+-----------------------+---------------------- MAX
555
+ // | is niche | ^
556
+ // +-----------------------+ |
557
+ // | |
558
+ // tag_range.start tag_range.end
559
+ //
560
+ // With those two options and having the flexibility to choose
561
+ // between a signed or unsigned comparison on the tag, that
562
+ // covers most realistic scenarios. The tests have a (contrived)
563
+ // example of a 1-byte enum with over 128 niched variants which
564
+ // wraps both as signed as unsigned, though, and for something
565
+ // like that we're stuck with the general algorithm.
522
566
523
567
let tag_range = tag_scalar. valid_range ( & dl) ;
524
568
let tag_size = tag_scalar. size ( & dl) ;
0 commit comments