@@ -134,28 +134,25 @@ impl Timespec {
134134 }
135135
136136 pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
137+ // When a >= b, the difference fits in u64.
138+ fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
139+ debug_assert!(a >= b);
140+ a.wrapping_sub(b).cast_unsigned()
141+ }
142+
137143 if self >= other {
138- // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
139- // to optimize it into a branchless form (see also #75545):
140- //
141- // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
142- // in both branches, i.e. the `else` must have its `- 1`
143- // subtraction after the common one, not interleaved with it
144- // (it used to be `self.tv_sec - 1 - other.tv_sec`)
145- //
146- // 2. the `Duration::new` call (or any other additional complexity)
147- // is outside of the `if`-`else`, not duplicated in both branches
148- //
149- // Ideally this code could be rearranged such that it more
150- // directly expresses the lower-cost behavior we want from it.
151144 let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() {
152145 (
153- (self.tv_sec - other.tv_sec) as u64 ,
146+ sub_ge_to_unsigned (self.tv_sec, other.tv_sec),
154147 self.tv_nsec.as_inner() - other.tv_nsec.as_inner(),
155148 )
156149 } else {
150+ // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow.
151+ debug_assert!(self.tv_nsec < other.tv_nsec);
152+ debug_assert!(self.tv_sec > other.tv_sec);
153+ debug_assert!(self.tv_sec > i64::MIN);
157154 (
158- (self.tv_sec - other.tv_sec - 1) as u64 ,
155+ sub_ge_to_unsigned (self.tv_sec - 1, other.tv_sec) ,
159156 self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(),
160157 )
161158 };
0 commit comments