Skip to content

Commit 4fa23d9

Browse files
committed
Improve comments inside codegen_get_discr
1 parent d5bcfb3 commit 4fa23d9

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)