Closed
Description
The manual version:
use std::{
cmp::Ordering,
time::SystemTime,
};
#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq)]
enum Foo {
Zero,
One,
Two,
}
impl PartialOrd for Foo {
fn partial_cmp(&self, _rhs: &Foo) -> Option<Ordering> {
panic!()
}
fn le(&self, rhs: &Foo) -> bool {
*self as u32 <= *rhs as u32
}
}
fn main() {
let opaque = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as u32
% 3;
let foo = unsafe { *(&opaque as *const _ as *const Foo) };
if foo <= Foo::One {
println!("here");
}
}
The manual version ASM:
playground::main:
subq $88, %rsp
callq *std::time::SystemTime::now@GOTPCREL(%rip)
movq %rax, 56(%rsp)
movq %rdx, 64(%rsp)
leaq 8(%rsp), %rdi
leaq 56(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq *std::time::SystemTime::duration_since@GOTPCREL(%rip)
cmpq $1, 8(%rsp)
je .LBB4_4
movl 16(%rsp), %eax
movl $2863311531, %ecx
imulq %rax, %rcx
shrq $33, %rcx
leal (%rcx,%rcx,2), %ecx
subl %ecx, %eax
cmpl $1, %eax
ja .LBB4_3
leaq .L__unnamed_2(%rip), %rax
movq %rax, 8(%rsp)
movq $1, 16(%rsp)
movq $0, 24(%rsp)
leaq .L__unnamed_3(%rip), %rax
movq %rax, 40(%rsp)
movq $0, 48(%rsp)
leaq 8(%rsp), %rdi
callq *std::io::stdio::_print@GOTPCREL(%rip)
The derived version:
use std::{
cmp::Ordering,
time::SystemTime,
};
#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd)]
enum Foo {
Zero,
One,
Two,
}
fn main() {
let opaque = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as u32
% 3;
let foo = unsafe { *(&opaque as *const _ as *const Foo) };
if foo <= Foo::One {
println!("here");
}
}
The derived version ASM:
playground::main:
subq $88, %rsp
callq *std::time::SystemTime::now@GOTPCREL(%rip)
movq %rax, 56(%rsp)
movq %rdx, 64(%rsp)
leaq 8(%rsp), %rdi
leaq 56(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq *std::time::SystemTime::duration_since@GOTPCREL(%rip)
cmpq $1, 8(%rsp)
je .LBB4_4
movl 16(%rsp), %eax
movl $2863311531, %ecx
imulq %rax, %rcx
shrq $33, %rcx
leal (%rcx,%rcx,2), %ecx
xorl %edx, %edx
subl %ecx, %eax
setne %dl
xorl %ecx, %ecx
cmpl $1, %eax
leaq -1(%rdx,%rdx), %rax
cmovneq %rax, %rcx
addq $1, %rcx
cmpq $1, %rcx
ja .LBB4_3
leaq .L__unnamed_2(%rip), %rax
movq %rax, 8(%rsp)
movq $1, 16(%rsp)
movq $0, 24(%rsp)
leaq .L__unnamed_3(%rip), %rax
movq %rax, 40(%rsp)
movq $0, 48(%rsp)
leaq 8(%rsp), %rdi
callq *std::io::stdio::_print@GOTPCREL(%rip)
The diff is that while the manual version does:
subl %ecx, %eax
cmpl $1, %eax
...the derived version does:
xorl %edx, %edx
subl %ecx, %eax
setne %dl
xorl %ecx, %ecx
cmpl $1, %eax
leaq -1(%rdx,%rdx), %rax
cmovneq %rax, %rcx
addq $1, %rcx
cmpq $1, %rcx
All the other PartialOrd
operators are optimized properly.