Repository: JuliaLang/julia
File: base/hashing.jl (Julia)

Code before:
                load_le_array(UInt64, arr, firstidx + pos + 8) ⊻ seed
            )
            if i > 32
                seed = hash_mix(
                    load_le_array(UInt64, arr, firstidx + pos + 16) ⊻ secret[3],
                    load_le_array(UInt64, arr, firstidx + pos + 24) ⊻ seed
                )
            end
        end

        a = load_le_array(UInt64, arr, firstidx + n - 16) ⊻ i
        b = load_le_array(UInt64, arr, firstidx + n - 8)
    end

    a = a ⊻ secret[2]
    b = b ⊻ seed
    b, a = mul_parts(a, b)
    return hash_mix(a ⊻ secret[4], b ⊻ secret[2] ⊻ i)
end


# Helper function to concatenate two UInt64 values with a byte shift
# Returns the result of shifting 'low' right by 'shift_bytes' bytes and
# filling the high bits with the low bits of 'high'
@inline function concat_shift(low::UInt64, high::UInt64, shift_bytes::Int)
    shift_bits = shift_bytes * 8
    return (low >> shift_bits) | (high << (64 - shift_bits))
end

@eval @inline function read_uint64_from_uint8_iter(iter, state)
    value = zero(UInt64)
    bytes_read = 0
    shift = 0

    for _ in 1:8
        next_result = iterate(iter, state)
        next_result === nothing && break
        byte, state = next_result
        value |= UInt64(byte) << shift
        shift += 8
        bytes_read += 1
        $(Expr(:loopinfo, (Symbol("llvm.loop.disable_nonforced"))))
        $(Expr(:loopinfo, (Symbol("llvm.loop.vectorize.enable"), false)))
    end

    return value, state, bytes_read
end

@eval @inline function read_uint64_from_uint8_iter(iter)
    next_result = iterate(iter)
    next_result === nothing && return nothing

Review comment (suggestion):
```suggestion
    shift_bits = (shift_bytes * 8) & 63
```

looks like it helps a little bit, a la https://github.com/JuliaLang/julia/issues/30674

on a length-10 generator I see like 12ns vs 10ns

Code after:
                load_le_array(UInt64, arr, firstidx + pos + 8) ⊻ seed
            )
            if i > 32
                seed = hash_mix(
                    load_le_array(UInt64, arr, firstidx + pos + 16) ⊻ secret[3],
                    load_le_array(UInt64, arr, firstidx + pos + 24) ⊻ seed
                )
            end
        end

        a = load_le_array(UInt64, arr, firstidx + n - 16) ⊻ i
        b = load_le_array(UInt64, arr, firstidx + n - 8)
    end

    a = a ⊻ secret[2]
    b = b ⊻ seed
    b, a = mul_parts(a, b)
    return hash_mix(a ⊻ secret[4], b ⊻ secret[2] ⊻ i)
end


# Helper function to concatenate two UInt64 values with a byte shift
# Returns the result of shifting 'low' right by 'shift_bytes' bytes and
# filling the high bits with the low bits of 'high'
@inline function concat_shift(low::UInt64, high::UInt64, shift_bytes::UInt8)
    shift_bits = (shift_bytes * 0x8) & 0x3f
    return (low >> shift_bits) | (high << (0x40 - shift_bits))
end

@inline function read_uint64_from_uint8_iter(iter, state)
    value = zero(UInt64)
    @nexprs 8 i -> begin
        next_result = iterate(iter, state)
        next_result === nothing && return value, state, UInt8(i - 1)
        byte, state = next_result
        value |= UInt64(byte) << ((i - 1) * 8)
    end
    return value, state, 0x8
end

@inline function read_uint64_from_uint8_iter(iter)
    next_result = iterate(iter)
    next_result === nothing && return nothing
    byte, state = next_result
    value = UInt64(byte)
    @nexprs 7 i -> begin
        next_result = iterate(iter, state)
        next_result === nothing && return value, state, UInt8(i)
        byte, state = next_result
        value |= UInt64(byte::UInt8) << (i * 8)
    end