@@ -134,28 +134,25 @@ impl Timespec {
134
134
}
135
135
136
136
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
+
137
143
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.
151
144
let ( secs, nsec) = if self . tv_nsec . as_inner ( ) >= other. tv_nsec . as_inner ( ) {
152
145
(
153
- ( self . tv_sec - other. tv_sec ) as u64 ,
146
+ sub_ge_to_unsigned ( self . tv_sec , other. tv_sec ) ,
154
147
self . tv_nsec . as_inner ( ) - other. tv_nsec . as_inner ( ) ,
155
148
)
156
149
} 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 ) ;
157
154
(
158
- ( self . tv_sec - other. tv_sec - 1 ) as u64 ,
155
+ sub_ge_to_unsigned ( self . tv_sec - 1 , other. tv_sec ) ,
159
156
self . tv_nsec . as_inner ( ) + ( NSEC_PER_SEC as u32 ) - other. tv_nsec . as_inner ( ) ,
160
157
)
161
158
} ;
0 commit comments