|
| 1 | +use std::collections::BTreeSet; |
1 | 2 | use std::fmt::{self, Write};
|
2 | 3 | use std::ops::{Bound, Deref};
|
3 | 4 | use std::{cmp, iter};
|
4 | 5 |
|
5 | 6 | use rustc_hashes::Hash64;
|
6 | 7 | use rustc_index::Idx;
|
7 | 8 | use rustc_index::bit_set::BitMatrix;
|
8 |
| -use tracing::debug; |
| 9 | +use tracing::{debug, trace}; |
9 | 10 |
|
10 | 11 | use crate::{
|
11 | 12 | AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
|
@@ -766,30 +767,63 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
766 | 767 |
|
767 | 768 | let niche_filling_layout = calculate_niche_filling_layout();
|
768 | 769 |
|
769 |
| - let (mut min, mut max) = (i128::MAX, i128::MIN); |
770 | 770 | let discr_type = repr.discr_type();
|
771 |
| - let bits = Integer::from_attr(dl, discr_type).size().bits(); |
772 |
| - for (i, mut val) in discriminants { |
773 |
| - if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { |
774 |
| - continue; |
775 |
| - } |
776 |
| - if discr_type.is_signed() { |
777 |
| - // sign extend the raw representation to be an i128 |
778 |
| - val = (val << (128 - bits)) >> (128 - bits); |
779 |
| - } |
780 |
| - if val < min { |
781 |
| - min = val; |
782 |
| - } |
783 |
| - if val > max { |
784 |
| - max = val; |
785 |
| - } |
786 |
| - } |
787 |
| - // We might have no inhabited variants, so pretend there's at least one. |
788 |
| - if (min, max) == (i128::MAX, i128::MIN) { |
789 |
| - min = 0; |
790 |
| - max = 0; |
791 |
| - } |
792 |
| - assert!(min <= max, "discriminant range is {min}...{max}"); |
| 771 | + let discr_int = Integer::from_attr(dl, discr_type); |
| 772 | + let bits = discr_int.size().bits(); |
| 773 | + // Because we can only represent one range of valid values, we'll look for the |
| 774 | + // largest range of invalid values and pick everything else as the range of valid |
| 775 | + // values. |
| 776 | + |
| 777 | + // First we need to sort the possible discriminant values so that we can look for the largest gap: |
| 778 | + let valid_discriminants: BTreeSet<i128> = discriminants |
| 779 | + .filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited())) |
| 780 | + .map(|(_, val)| { |
| 781 | + if discr_type.is_signed() { |
| 782 | + // sign extend the raw representation to be an i128 |
| 783 | + (val << (128 - bits)) >> (128 - bits) |
| 784 | + } else { |
| 785 | + val |
| 786 | + } |
| 787 | + }) |
| 788 | + .collect(); |
| 789 | + trace!(?valid_discriminants); |
| 790 | + let discriminants = valid_discriminants.iter().copied(); |
| 791 | + //let next_discriminants = discriminants.clone().cycle().skip(1); |
| 792 | + let next_discriminants = |
| 793 | + discriminants.clone().chain(valid_discriminants.first().copied()).skip(1); |
| 794 | + // Iterate over pairs of each discriminant together with the next one. |
| 795 | + // Since they were sorted, we can now compute the niche sizes and pick the largest. |
| 796 | + let discriminants = discriminants.zip(next_discriminants); |
| 797 | + let largest_niche = discriminants.max_by_key(|&(start, end)| { |
| 798 | + trace!(?start, ?end); |
| 799 | + // If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between |
| 800 | + // the two end points is actually the size of the valid discriminants. |
| 801 | + let dist = if start > end { |
| 802 | + // Overflow can happen for 128 bit discriminants if `end` is negative. |
| 803 | + // But in that case casting to `u128` still gets us the right value, |
| 804 | + // as the distance must be positive if the lhs of the subtraction is larger than the rhs. |
| 805 | + let dist = start.wrapping_sub(end); |
| 806 | + if discr_type.is_signed() { |
| 807 | + discr_int.signed_max().wrapping_sub(dist) as u128 |
| 808 | + } else { |
| 809 | + discr_int.size().unsigned_int_max() - dist as u128 |
| 810 | + } |
| 811 | + } else { |
| 812 | + // Overflow can happen for 128 bit discriminants if `start` is negative. |
| 813 | + // But in that case casting to `u128` still gets us the right value, |
| 814 | + // as the distance must be positive if the lhs of the subtraction is larger than the rhs. |
| 815 | + end.wrapping_sub(start) as u128 |
| 816 | + }; |
| 817 | + trace!(?dist); |
| 818 | + dist |
| 819 | + }); |
| 820 | + trace!(?largest_niche); |
| 821 | + |
| 822 | + // `max` is the last valid discriminant before the largest niche |
| 823 | + // `min` is the first valid discriminant after the largest niche |
| 824 | + let (max, min) = largest_niche |
| 825 | + // We might have no inhabited variants, so pretend there's at least one. |
| 826 | + .unwrap_or((0, 0)); |
793 | 827 | let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
|
794 | 828 |
|
795 | 829 | let mut align = dl.aggregate_align;
|
|
0 commit comments