@@ -517,8 +517,52 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
517517 bx. cx ( ) . const_uint ( cast_to, niche_variants. start ( ) . as_u32 ( ) as u64 ) ;
518518 ( is_niche, tagged_discr, 0 )
519519 } 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.
522566
523567 let tag_range = tag_scalar. valid_range ( & dl) ;
524568 let tag_size = tag_scalar. size ( & dl) ;
0 commit comments