Closed
Description
When calling .rem_euclid(n)
on a signed integer type, it fails to apply the optimization for powers of 2, where it should do a bitwise AND operation instead.
Missed optimization
pub fn rem(n: i32) -> i32 {
n.rem_euclid(2)
}
example::rem:
mov eax, edi
shr eax, 31
add eax, edi
and eax, -2
sub edi, eax
mov eax, 1
cmovns eax, edi
ret
How it should be optimized
pub fn rem(n: i32) -> i32 {
n & 1
}
example::rem:
mov eax, edi
and eax, 1
ret
Testing the optimization:
n = 2
?play
let mut passed = true;
for i in (std::i16::MIN..=std::i16::MAX) {
if (i&1) != (i.rem_euclid(2)) {
passed = false;
break
}
}
println!("{passed}");
true
n = 1
?play
let mut passed = true;
for i in (std::i16::MIN..=std::i16::MAX) {
if (i&0) != (i.rem_euclid(1)) {
passed = false;
break
}
}
println!("{passed}");
true
n = 4
?play
let mut passed = true;
for i in (std::i16::MIN..=std::i16::MAX) {
if (i&3) != (i.rem_euclid(4)) {
passed = false;
break
}
}
println!("{passed}");
true
Curiously, the optimization is applied to unsigned integers just fine
pub fn rem(n: u32) -> u32 {
n.rem_euclid(2)
}
example::rem:
mov eax, edi
and eax, 1
ret