Failure with `lshr_int` (intrinsic for >>) on UInt256 type

Basically lshr_int works as expected when called directly, but not when wrapped in a function. I need to understand better the failure to find a proper fix in BitIntegers. Here is a demo:

julia> using BitIntegers; x = rand(UInt256)
0xbe970fced92b8fcef396a1f5b40c63a86071b8f0330f43290f1d5d748262565f

julia> x >> 4
0x0be970fced92b8fcef396a1f5b40c63a86071b8f0330f43290f1d5d748262565

julia> x >> 0x4
0x0000000000000000000000000000000000000000000000000000000000000000

julia> x >> 0x0004
0x0be970fced92b8fcef396a1f5b40c63a86071b8f0330f43290f1d5d748262565

julia> Base.lshr_int(x, 0x4)
0x0be970fced92b8fcef396a1f5b40c63a86071b8f0330f43290f1d5d748262565

julia> f(x, y) = Base.lshr_int(x, y); f(x, 0x04)
0x0000000000000000000000000000000000000000000000000000000000000000

To what extent is it “safe” to use these intrinsics, and is it possible to change Julia to make the example above work?

Interestingly, on nightly, I get this:

julia> using BitIntegers; x = rand(UInt256)
[ Info: Precompiling BitIntegers [c3b6d118-76ef-56ca-8cc7-ebb389d030a1]
0x00000000000000000000000000000000000000000000000000000000000000a1

So everything rand generates, except for the last 8 bits somehow is always zero.

Edit: It’s not just rand:

julia> uint256"0xbe970fced92b8fcef396a1f5b40c63a86071b8f0330f43290f1d5d748262565f"
0x000000000000000000000000000000000000000000000000000000000000005f

Actually what you observe is a consequence of the OP, and it’s how I was made aware of it from https://github.com/JuliaLang/julia/pull/36470#issuecomment-703036745:

125/126> rand(UInt256)
0x00000000000000000000000000000000000000000000000000000000000000d2

127> string(big(ans), base=16)
"28fecc917ccc6d1bbf9b54c500c26d0c8dea1d23520b8d4d87e9377ddf6099d2"
2 Likes

It looks like it’s an LLVM bug:

julia> primitive type UInt256 256 end

julia> x = reinterpret(UInt256, rand(UInt128, 2))[]
UInt256(0x48805fdfb72d71fadaf8daa563cf816383f755d9d9e70d703fa348f556c717ad)

julia> f(x) = Base.lshr_int(x, 0x8)
f (generic function with 1 method)

julia> @code_llvm optimize=false f(x)
;  @ REPL[22]:1 within `f'
define void @julia_f_392(i256* noalias nocapture sret %0, i256 %1) {
top:
  %2 = call {}*** @julia.ptls_states()
  %3 = bitcast {}*** %2 to {}**
  %4 = getelementptr inbounds {}*, {}** %3, i64 4
  %5 = bitcast {}** %4 to i64**
  %6 = load i64*, i64** %5
  %7 = lshr i256 %1, 8
  %8 = select i1 true, i256 0, i256 %7
  store i256 %8, i256* %0, align 8
  ret void
}

julia> @code_llvm optimize=true f(x)
;  @ REPL[22]:1 within `f'
define void @julia_f_394(i256* noalias nocapture sret %0, i256 %1) {
top:
  store i256 0, i256* %0, align 8
  ret void
}

Would you mind opening an issue on GitHub?

2 Likes

Ah, so it just prints wrong

Ah great, thank you! Issue opened https://github.com/JuliaLang/julia/issues/37880.

Yes, sorry that I was not more clear.

3 Likes