Skip to content

Commit

Permalink
fix/implement various 128-bit operations on 32-bit machines [#3283]
Browse files Browse the repository at this point in the history
TODO: we should really have div, rem and mod operations for 128-bit
integers on 32-bit machines that don't resort to using BigInts, but
this works and maybe LLVM will actually implement these intrinsics
at some point.
  • Loading branch information
StefanKarpinski committed Jun 6, 2013
1 parent c6139e8 commit b9441f0
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
21 changes: 14 additions & 7 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ convert(::Type{Int64}, n::BigInt) = int64(convert(Clong, n))
convert(::Type{Int32}, n::BigInt) = int32(convert(Clong, n))
convert(::Type{Int16}, n::BigInt) = int16(convert(Clong, n))
convert(::Type{Int8}, n::BigInt) = int8(convert(Clong, n))

function convert(::Type{Clong}, n::BigInt)
fits = ccall((:__gmpz_fits_slong_p, :libgmp), Int32, (Ptr{BigInt},), &n) != 0
if fits
Expand All @@ -64,6 +65,7 @@ convert(::Type{Uint64}, x::BigInt) = uint64(convert(Culong, x))
convert(::Type{Uint32}, x::BigInt) = uint32(convert(Culong, x))
convert(::Type{Uint16}, x::BigInt) = uint16(convert(Culong, x))
convert(::Type{Uint8}, x::BigInt) = uint8(convert(Culong, x))

function convert(::Type{Culong}, n::BigInt)
fits = ccall((:__gmpz_fits_ulong_p, :libgmp), Int32, (Ptr{BigInt},), &n) != 0
if fits
Expand All @@ -73,16 +75,21 @@ function convert(::Type{Culong}, n::BigInt)
end
end

if sizeof(Int32) == sizeof(Clong)
function convert(::Type{Uint128}, x::BigInt)
uint128(uint(x>>>96))<<96 +
uint128(uint((x>>>64) & typemax(Uint32)))<<64 +
uint128(uint((x>>>32) & typemax(Uint32)))<<32 +
uint128(uint(x & typemax(Uint32)))
end
end
if sizeof(Int64) == sizeof(Clong)
function convert(::Type{Int128}, x::BigInt)
ax = abs(x)
top = ax>>64
bot = ax - (top<<64)
n = int128(convert(Uint,top))<<64 + int128(convert(Uint,bot))
return x<0 ? -n : n
function convert(::Type{Uint128}, x::BigInt)
uint128(uint(ax>>>64))<<64 +
uint128(uint(ax & typemax(Uint64)))
end
convert(::Type{Uint128}, x::BigInt) = uint128(convert(Int128,x))
end
convert(::Type{Int128}, x::BigInt) = copysign(int128(uint128(abs(x))),x)

promote_rule{T<:Integer}(::Type{BigInt}, ::Type{T}) = BigInt

Expand Down
16 changes: 12 additions & 4 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,9 @@ if WORD_SIZE==32
t = u1*v0 + (w0>>>32)
w2 = t>>32
w1 = u0*v1 + (t&0xffffffff)
high = u1*v1 + w2 + (w1 >> 32)
hi = u1*v1 + w2 + (w1 >> 32)
lo = w0&0xffffffff + (w1 << 32)
int128(high)<<64 + int128(uint128(lo))
int128(hi)<<64 + int128(uint128(lo))
end

function widemul(u::Uint64, v::Uint64)
Expand All @@ -510,9 +510,9 @@ if WORD_SIZE==32
t = u1*v0 + (w0>>>32)
w2 = t>>>32
w1 = u0*v1 + (t&0xffffffff)
high = u1*v1 + w2 + (w1 >>> 32)
hi = u1*v1 + w2 + (w1 >>> 32)
lo = w0&0xffffffff + (w1 << 32)
int128(high)<<64 + int128(uint128(lo))
uint128(hi)<<64 + uint128(lo)
end

function *(u::Int128, v::Int128)
Expand All @@ -538,6 +538,14 @@ if WORD_SIZE==32
w1 = lohi + (t&0xffffffffffffffff)
(lolo&0xffffffffffffffff) + uint128(w1)<<64
end

div(x::Int128, y::Int128) = int128(div(BigInt(x),BigInt(y)))
div(x::Uint128, y::Uint128) = uint128(div(BigInt(x),BigInt(y)))

rem(x::Int128, y::Int128) = int128(rem(BigInt(x),BigInt(y)))
rem(x::Uint128, y::Uint128) = uint128(rem(BigInt(x),BigInt(y)))

mod(x::Int128, y::Int128) = int128(mod(BigInt(x),BigInt(y)))
else
widemul(u::Int64, v::Int64) = int128(u)*int128(v)
widemul(u::Uint64, v::Uint64) = uint128(u)*uint128(v)
Expand Down

0 comments on commit b9441f0

Please sign in to comment.