@@ -845,14 +845,166 @@ widemul(x::Bool,y::Number) = x * y
845845widemul (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
8581010for op in (:+ , :- , :* , :& , :| , :xor )
0 commit comments