Skip to content

Commit 98494ba

Browse files
topolarityKristofferC
authored andcommitted
Revert "remove hand-coded methods for (U)Int128 on 32 bit systems (#53867)" (#59211)
We need to revert this for now. Resolves #58911 It seems that the back-end LLVM emits this libcall a lot less often than it used to, but it still happens sometimes and 32-bit Windows has no implementation of `__divti3`.
1 parent 9462405 commit 98494ba

File tree

1 file changed

+158
-6
lines changed

1 file changed

+158
-6
lines changed

base/int.jl

Lines changed: 158 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -845,14 +845,166 @@ widemul(x::Bool,y::Number) = x * y
845845
widemul(x::Number,y::Bool) = x * y
846846

847847

848-
# Int128 multiply and divide
849-
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)
848+
## wide multiplication, Int128 multiply and divide ##
849+
850+
if Core.sizeof(Int) == 4
851+
function widemul(u::Int64, v::Int64)
852+
local u0::UInt64, v0::UInt64, w0::UInt64
853+
local u1::Int64, v1::Int64, w1::UInt64, w2::Int64, t::UInt64
854+
855+
u0 = u & 0xffffffff; u1 = u >> 32
856+
v0 = v & 0xffffffff; v1 = v >> 32
857+
w0 = u0 * v0
858+
t = reinterpret(UInt64, u1) * v0 + (w0 >>> 32)
859+
w2 = reinterpret(Int64, t) >> 32
860+
w1 = u0 * reinterpret(UInt64, v1) + (t & 0xffffffff)
861+
hi = u1 * v1 + w2 + (reinterpret(Int64, w1) >> 32)
862+
lo = w0 & 0xffffffff + (w1 << 32)
863+
return Int128(hi) << 64 + Int128(lo)
864+
end
865+
866+
function widemul(u::UInt64, v::UInt64)
867+
local u0::UInt64, v0::UInt64, w0::UInt64
868+
local u1::UInt64, v1::UInt64, w1::UInt64, w2::UInt64, t::UInt64
869+
870+
u0 = u & 0xffffffff; u1 = u >>> 32
871+
v0 = v & 0xffffffff; v1 = v >>> 32
872+
w0 = u0 * v0
873+
t = u1 * v0 + (w0 >>> 32)
874+
w2 = t >>> 32
875+
w1 = u0 * v1 + (t & 0xffffffff)
876+
hi = u1 * v1 + w2 + (w1 >>> 32)
877+
lo = w0 & 0xffffffff + (w1 << 32)
878+
return UInt128(hi) << 64 + UInt128(lo)
879+
end
880+
881+
function *(u::Int128, v::Int128)
882+
u0 = u % UInt64; u1 = Int64(u >> 64)
883+
v0 = v % UInt64; v1 = Int64(v >> 64)
884+
lolo = widemul(u0, v0)
885+
lohi = widemul(reinterpret(Int64, u0), v1)
886+
hilo = widemul(u1, reinterpret(Int64, v0))
887+
t = reinterpret(UInt128, hilo) + (lolo >>> 64)
888+
w1 = reinterpret(UInt128, lohi) + (t & 0xffffffffffffffff)
889+
return Int128(lolo & 0xffffffffffffffff) + reinterpret(Int128, w1) << 64
890+
end
891+
892+
function *(u::UInt128, v::UInt128)
893+
u0 = u % UInt64; u1 = UInt64(u>>>64)
894+
v0 = v % UInt64; v1 = UInt64(v>>>64)
895+
lolo = widemul(u0, v0)
896+
lohi = widemul(u0, v1)
897+
hilo = widemul(u1, v0)
898+
t = hilo + (lolo >>> 64)
899+
w1 = lohi + (t & 0xffffffffffffffff)
900+
return (lolo & 0xffffffffffffffff) + UInt128(w1) << 64
901+
end
902+
903+
function _setbit(x::UInt128, i)
904+
# faster version of `return x | (UInt128(1) << i)`
905+
j = i >> 5
906+
y = UInt128(one(UInt32) << (i & 0x1f))
907+
if j == 0
908+
return x | y
909+
elseif j == 1
910+
return x | (y << 32)
911+
elseif j == 2
912+
return x | (y << 64)
913+
elseif j == 3
914+
return x | (y << 96)
915+
end
916+
return x
917+
end
850918

851-
div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
852-
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)
919+
function divrem(x::UInt128, y::UInt128)
920+
iszero(y) && throw(DivideError())
921+
if (x >> 64) % UInt64 == 0
922+
if (y >> 64) % UInt64 == 0
923+
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
924+
q64, x64 = divrem(x % UInt64, y % UInt64)
925+
return UInt128(q64), UInt128(x64)
926+
else
927+
# this implies y>x, so
928+
return zero(UInt128), x
929+
end
930+
end
931+
n = leading_zeros(y) - leading_zeros(x)
932+
q = zero(UInt128)
933+
ys = y << n
934+
while n >= 0
935+
# ys == y * 2^n
936+
if ys <= x
937+
x -= ys
938+
q = _setbit(q, n)
939+
if (x >> 64) % UInt64 == 0
940+
# exit early, similar to above fast path
941+
if (y >> 64) % UInt64 == 0
942+
q64, x64 = divrem(x % UInt64, y % UInt64)
943+
q |= q64
944+
x = UInt128(x64)
945+
end
946+
return q, x
947+
end
948+
end
949+
ys >>>= 1
950+
n -= 1
951+
end
952+
return q, x
953+
end
853954

854-
rem(x::Int128, y::Int128) = checked_srem_int(x, y)
855-
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
955+
function div(x::Int128, y::Int128)
956+
(x == typemin(Int128)) & (y == -1) && throw(DivideError())
957+
return Int128(div(BigInt(x), BigInt(y)))::Int128
958+
end
959+
div(x::UInt128, y::UInt128) = divrem(x, y)[1]
960+
961+
function rem(x::Int128, y::Int128)
962+
return Int128(rem(BigInt(x), BigInt(y)))::Int128
963+
end
964+
965+
function rem(x::UInt128, y::UInt128)
966+
iszero(y) && throw(DivideError())
967+
if (x >> 64) % UInt64 == 0
968+
if (y >> 64) % UInt64 == 0
969+
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
970+
return UInt128(rem(x % UInt64, y % UInt64))
971+
else
972+
# this implies y>x, so
973+
return x
974+
end
975+
end
976+
n = leading_zeros(y) - leading_zeros(x)
977+
ys = y << n
978+
while n >= 0
979+
# ys == y * 2^n
980+
if ys <= x
981+
x -= ys
982+
if (x >> 64) % UInt64 == 0
983+
# exit early, similar to above fast path
984+
if (y >> 64) % UInt64 == 0
985+
x = UInt128(rem(x % UInt64, y % UInt64))
986+
end
987+
return x
988+
end
989+
end
990+
ys >>>= 1
991+
n -= 1
992+
end
993+
return x
994+
end
995+
996+
function mod(x::Int128, y::Int128)
997+
return Int128(mod(BigInt(x), BigInt(y)))::Int128
998+
end
999+
else
1000+
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)
1001+
1002+
div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
1003+
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)
1004+
1005+
rem(x::Int128, y::Int128) = checked_srem_int(x, y)
1006+
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
1007+
end
8561008

8571009
# issue #15489: since integer ops are unchecked, they shouldn't check promotion
8581010
for op in (:+, :-, :*, :&, :|, :xor)

0 commit comments

Comments
 (0)