diff options
| author | bors <bors@rust-lang.org> | 2021-08-25 02:17:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-08-25 02:17:41 +0000 |
| commit | e5484cec0e3f60b2a0010505cd355639f75a2973 (patch) | |
| tree | 25a26fad7e088f2c98dc4a268f8ce0351ea469d9 /compiler/rustc_target | |
| parent | faa0a10406319264e81086fe88fd426cbfa09021 (diff) | |
| parent | f17e384a43dd8ca0aefb36bfcd8a69d9ad7f12cf (diff) | |
| download | rust-e5484cec0e3f60b2a0010505cd355639f75a2973.tar.gz rust-e5484cec0e3f60b2a0010505cd355639f75a2973.zip | |
Auto merge of #88242 - bonega:allocation_range, r=oli-obk
Use custom wrap-around type instead of RangeInclusive Two reasons: 1. More memory is allocated than necessary for `valid_range` in `Scalar`. The range is not used as an iterator and `exhausted` is never used. 2. `contains`, `count` etc. methods in `RangeInclusive` are doing very unhelpful(and dangerous!) things when used as a wrap-around range. - In general this PR wants to limit potentially confusing methods, that have a low probability of working. Doing a local perf run, every metric shows improvement except for instructions. Max-rss seem to have a very consistent improvement. Sorry - newbie here, probably doing something wrong.
Diffstat (limited to 'compiler/rustc_target')
| -rw-r--r-- | compiler/rustc_target/src/abi/mod.rs | 105 |
1 files changed, 71 insertions, 34 deletions
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 8ef6e142cae..d206df46120 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -677,32 +677,80 @@ impl Primitive { } } +/// Inclusive wrap-around range of valid values, that is, if +/// start > end, it represents `start..=MAX`, +/// followed by `0..=end`. +/// +/// That is, for an i8 primitive, a range of `254..=2` means following +/// sequence: +/// +/// 254 (-2), 255 (-1), 0, 1, 2 +/// +/// This is intended specifically to mirror LLVM’s `!range` metadata, +/// semantics. +#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic)] +pub struct WrappingRange { + pub start: u128, + pub end: u128, +} + +impl WrappingRange { + /// Returns `true` if `v` is contained in the range. + #[inline(always)] + pub fn contains(&self, v: u128) -> bool { + if self.start <= self.end { + self.start <= v && v <= self.end + } else { + self.start <= v || v <= self.end + } + } + + /// Returns `true` if zero is contained in the range. + /// Equal to `range.contains(0)` but should be faster. + #[inline(always)] + pub fn contains_zero(&self) -> bool { + self.start > self.end || self.start == 0 + } + + /// Returns `self` with replaced `start` + #[inline(always)] + pub fn with_start(mut self, start: u128) -> Self { + self.start = start; + self + } + + /// Returns `self` with replaced `end` + #[inline(always)] + pub fn with_end(mut self, end: u128) -> Self { + self.end = end; + self + } +} + +impl fmt::Debug for WrappingRange { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{}..={}", self.start, self.end)?; + Ok(()) + } +} + /// Information about one scalar component of a Rust type. #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(HashStable_Generic)] pub struct Scalar { pub value: Primitive, - /// Inclusive wrap-around range of valid values, that is, if - /// start > end, it represents `start..=MAX`, - /// followed by `0..=end`. - /// - /// That is, for an i8 primitive, a range of `254..=2` means following - /// sequence: - /// - /// 254 (-2), 255 (-1), 0, 1, 2 - /// - /// This is intended specifically to mirror LLVM’s `!range` metadata, - /// semantics. // FIXME(eddyb) always use the shortest range, e.g., by finding // the largest space between two consecutive valid values and // taking everything else as the (shortest) valid range. - pub valid_range: RangeInclusive<u128>, + pub valid_range: WrappingRange, } impl Scalar { pub fn is_bool(&self) -> bool { - matches!(self.value, Int(I8, false)) && self.valid_range == (0..=1) + matches!(self.value, Int(I8, false)) + && matches!(self.valid_range, WrappingRange { start: 0, end: 1 }) } /// Returns the valid range as a `x..y` range. @@ -715,8 +763,8 @@ impl Scalar { let bits = self.value.size(cx).bits(); assert!(bits <= 128); let mask = !0u128 >> (128 - bits); - let start = *self.valid_range.start(); - let end = *self.valid_range.end(); + let start = self.valid_range.start; + let end = self.valid_range.end; assert_eq!(start, start & mask); assert_eq!(end, end & mask); start..(end.wrapping_add(1) & mask) @@ -971,14 +1019,14 @@ impl Niche { let max_value = !0u128 >> (128 - bits); // Find out how many values are outside the valid range. - let niche = v.end().wrapping_add(1)..*v.start(); + let niche = v.end.wrapping_add(1)..v.start; niche.end.wrapping_sub(niche.start) & max_value } pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> { assert!(count > 0); - let Scalar { value, valid_range: ref v } = self.scalar; + let Scalar { value, valid_range: v } = self.scalar.clone(); let bits = value.size(cx).bits(); assert!(bits <= 128); let max_value = !0u128 >> (128 - bits); @@ -988,24 +1036,14 @@ impl Niche { } // Compute the range of invalid values being reserved. - let start = v.end().wrapping_add(1) & max_value; - let end = v.end().wrapping_add(count) & max_value; - - // If the `end` of our range is inside the valid range, - // then we ran out of invalid values. - // FIXME(eddyb) abstract this with a wraparound range type. - let valid_range_contains = |x| { - if v.start() <= v.end() { - *v.start() <= x && x <= *v.end() - } else { - *v.start() <= x || x <= *v.end() - } - }; - if valid_range_contains(end) { + let start = v.end.wrapping_add(1) & max_value; + let end = v.end.wrapping_add(count) & max_value; + + if v.contains(end) { return None; } - Some((start, Scalar { value, valid_range: *v.start()..=end })) + Some((start, Scalar { value, valid_range: v.with_end(end) })) } } @@ -1212,9 +1250,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { { let scalar_allows_raw_init = move |s: &Scalar| -> bool { if zero { - let range = &s.valid_range; // The range must contain 0. - range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0 + s.valid_range.contains_zero() } else { // The range must include all values. `valid_range_exclusive` handles // the wrap-around using target arithmetic; with wrap-around then the full |
