Inconsistent shift behavior when shifting by 32
Hugobros3 opened this issue · 1 comments
While trying to isolate other issues I'm having with Impla (it randomly segfaults when building my bvh builder, will make another issue once I narrow down the problem), I found out the shift right behavior is inconsistent when shifting a 32-bit value by 32 places to the right. One would expect that to produce a zero, and that was what my logic assumed, but I know this is undefined behavior in some languages. Trick is, here it's undefined behavior depending on context, which is extra gnarly. I managed to isolate three cases:
- The result of such a shift is 1, the default case in an empty example
- The result of such a shift is zero, if you have an indefinite array initialized before
- The result is the original number, untouched, if the 32 value is obtained at runtime (here with an extern C function)
The issue is here no matter if signed or unsigned values are used
extern "C" {
fn unknown_at_compile_time_but_its_32_really() -> i32;
}
extern fn buggy_shift() -> () {
//let uncomment_this_and_the_result_is_zero = ~[1:i32];
// uncomment that and the result is 507
//let shift_by = unknown_at_compile_time_but_its_32_really();
let shift_by = 32;
print_value(shift_by, "shifting by...");
fn @shift(i: i32) -> i32 {
i >> shift_by as i32
}
fn @shift_unsigned(i: u32) -> u32 {
i >> (shift_by as u32)
}
print_value(shift(507),"result");
print_value(shift_unsigned(507_u32) as i32,"result for unsigned");
}
I believe this is not actually meant to be undefined behavior, and/or should be documented clearly (I lost quite a bit of time to this).
As you know, the backend of Thorin uses LLVM to generate code. The semantics of the right shift instruction of LLVM (same as in C) is that the behaviour is undefined for shifts larger than the bitwidth. This means anything can happen, including inconsistent results for different execution orders or what you are seeing here.