Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent shift behavior when shifting by 32 #83

Open
Hugobros3 opened this issue Jul 21, 2019 · 1 comment
Open

Inconsistent shift behavior when shifting by 32 #83

Hugobros3 opened this issue Jul 21, 2019 · 1 comment

Comments

@Hugobros3
Copy link
Contributor

Hugobros3 commented Jul 21, 2019

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).

@madmann91
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants