From a7ad899f9dbce1b4a0beb56650bc72732f204d24 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Aug 2020 02:41:41 +0300 Subject: [PATCH] std/sys/unix/time: make it easier for LLVM to optimize `Instant` subtraction. --- library/std/src/sys/unix/time.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 6707f790cab0a..f2a9cb5a0e879 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -20,17 +20,29 @@ impl Timespec { fn sub_timespec(&self, other: &Timespec) -> Result { if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) + // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM + // to optimize it into a branchless form (see also #75545): + // + // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression + // in both branches, i.e. the `else` must have its `- 1` + // subtraction after the common one, not interleaved with it + // (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`) + // + // 2. the `Duration::new` call (or any other additional complexity) + // is outside of the `if`-`else`, not duplicated in both branches + // + // Ideally this code could be rearranged such that it more + // directly expresses the lower-cost behavior we want from it. + let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec { + ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32) } else { - Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, + ( + (self.t.tv_sec - other.t.tv_sec - 1) as u64, self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, ) - }) + }; + + Ok(Duration::new(secs, nsec)) } else { match other.sub_timespec(self) { Ok(d) => Err(d),