diff options
Diffstat (limited to 'compiler/int128.nim')
-rw-r--r-- | compiler/int128.nim | 107 |
1 files changed, 53 insertions, 54 deletions
diff --git a/compiler/int128.nim b/compiler/int128.nim index 8d3cd7113..74e581cd5 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -5,6 +5,9 @@ from std/math import trunc +when defined(nimPreviewSlimSystem): + import std/assertions + type Int128* = object udata: array[4, uint32] @@ -30,39 +33,35 @@ template high*(t: typedesc[Int128]): Int128 = Max proc `$`*(a: Int128): string proc toInt128*[T: SomeInteger | bool](arg: T): Int128 = - when T is bool: result.sdata(0) = int32(arg) - elif T is SomeUnsignedInt: - when sizeof(arg) <= 4: - result.udata[0] = uint32(arg) + {.noSideEffect.}: + result = Zero + when T is bool: result.sdata(0) = int32(arg) + elif T is SomeUnsignedInt: + when sizeof(arg) <= 4: + result.udata[0] = uint32(arg) + else: + result.udata[0] = uint32(arg and T(0xffffffff)) + result.udata[1] = uint32(arg shr 32) + elif sizeof(arg) <= 4: + result.sdata(0) = int32(arg) + if arg < 0: # sign extend + result.sdata(1) = -1 + result.sdata(2) = -1 + result.sdata(3) = -1 else: - result.udata[0] = uint32(arg and T(0xffffffff)) - result.udata[1] = uint32(arg shr 32) - elif sizeof(arg) <= 4: - result.sdata(0) = int32(arg) - if arg < 0: # sign extend - result.sdata(1) = -1 - result.sdata(2) = -1 - result.sdata(3) = -1 - else: - let tmp = int64(arg) - result.udata[0] = uint32(tmp and 0xffffffff) - result.sdata(1) = int32(tmp shr 32) - if arg < 0: # sign extend - result.sdata(2) = -1 - result.sdata(3) = -1 + let tmp = int64(arg) + result.udata[0] = uint32(tmp and 0xffffffff) + result.sdata(1) = int32(tmp shr 32) + if arg < 0: # sign extend + result.sdata(2) = -1 + result.sdata(3) = -1 template isNegative(arg: Int128): bool = arg.sdata(3) < 0 -template isNegative(arg: int32): bool = - arg < 0 - proc bitconcat(a, b: uint32): uint64 = (uint64(a) shl 32) or uint64(b) -proc bitsplit(a: uint64): (uint32, uint32) = - (cast[uint32](a shr 32), cast[uint32](a)) - proc toInt64*(arg: Int128): int64 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") @@ -173,6 +172,7 @@ proc addToHex*(result: var string; arg: Int128) = i -= 1 proc toHex*(arg: Int128): string = + result = "" result.addToHex(arg) proc inc*(a: var Int128, y: uint32 = 1) = @@ -208,37 +208,36 @@ proc `==`*(a, b: Int128): bool = if a.udata[3] != b.udata[3]: return false return true -proc inplaceBitnot(a: var Int128) = - a.udata[0] = not a.udata[0] - a.udata[1] = not a.udata[1] - a.udata[2] = not a.udata[2] - a.udata[3] = not a.udata[3] - proc bitnot*(a: Int128): Int128 = + result = Zero result.udata[0] = not a.udata[0] result.udata[1] = not a.udata[1] result.udata[2] = not a.udata[2] result.udata[3] = not a.udata[3] proc bitand*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] and b.udata[0] result.udata[1] = a.udata[1] and b.udata[1] result.udata[2] = a.udata[2] and b.udata[2] result.udata[3] = a.udata[3] and b.udata[3] proc bitor*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] or b.udata[0] result.udata[1] = a.udata[1] or b.udata[1] result.udata[2] = a.udata[2] or b.udata[2] result.udata[3] = a.udata[3] or b.udata[3] proc bitxor*(a, b: Int128): Int128 = + result = Zero result.udata[0] = a.udata[0] xor b.udata[0] result.udata[1] = a.udata[1] xor b.udata[1] result.udata[2] = a.udata[2] xor b.udata[2] result.udata[3] = a.udata[3] xor b.udata[3] proc `shr`*(a: Int128, b: int): Int128 = + result = Zero let b = b and 127 if b < 32: result.sdata(3) = a.sdata(3) shr b @@ -265,6 +264,7 @@ proc `shr`*(a: Int128, b: int): Int128 = result.sdata(0) = a.sdata(3) shr (b and 31) proc `shl`*(a: Int128, b: int): Int128 = + result = Zero let b = b and 127 if b < 32: result.udata[0] = a.udata[0] shl b @@ -288,6 +288,7 @@ proc `shl`*(a: Int128, b: int): Int128 = result.udata[3] = a.udata[0] shl (b and 31) proc `+`*(a, b: Int128): Int128 = + result = Zero let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0]) result.udata[0] = cast[uint32](tmp0) let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32) @@ -320,6 +321,7 @@ proc abs(a: int32): int = if a < 0: -a else: a proc `*`(a: Int128, b: uint32): Int128 = + result = Zero let tmp0 = uint64(a.udata[0]) * uint64(b) let tmp1 = uint64(a.udata[1]) * uint64(b) let tmp2 = uint64(a.udata[2]) * uint64(b) @@ -338,10 +340,11 @@ proc `*`*(a: Int128, b: int32): Int128 = if b < 0: result = -result -proc `*=`*(a: var Int128, b: int32): Int128 = - result = result * b +proc `*=`(a: var Int128, b: int32) = + a = a * b proc makeInt128(high, low: uint64): Int128 = + result = Zero result.udata[0] = cast[uint32](low) result.udata[1] = cast[uint32](low shr 32) result.udata[2] = cast[uint32](high) @@ -354,23 +357,10 @@ proc low64(a: Int128): uint64 = bitconcat(a.udata[1], a.udata[0]) proc `*`*(lhs, rhs: Int128): Int128 = - let - a = cast[uint64](lhs.udata[0]) - b = cast[uint64](lhs.udata[1]) - c = cast[uint64](lhs.udata[2]) - d = cast[uint64](lhs.udata[3]) - - e = cast[uint64](rhs.udata[0]) - f = cast[uint64](rhs.udata[1]) - g = cast[uint64](rhs.udata[2]) - h = cast[uint64](rhs.udata[3]) - - - let a32 = cast[uint64](lhs.udata[1]) - let a00 = cast[uint64](lhs.udata[0]) - let b32 = cast[uint64](rhs.udata[1]) - let b00 = cast[uint64](rhs.udata[0]) - + let a32 = uint64(lhs.udata[1]) + let a00 = uint64(lhs.udata[0]) + let b32 = uint64(rhs.udata[1]) + let b00 = uint64(rhs.udata[0]) result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00) result += toInt128(a32 * b00) shl 32 result += toInt128(a00 * b32) shl 32 @@ -381,6 +371,7 @@ proc `*=`*(a: var Int128, b: Int128) = import std/bitops proc fastLog2*(a: Int128): int = + result = 0 if a.udata[3] != 0: return 96 + fastLog2(a.udata[3]) if a.udata[2] != 0: @@ -392,6 +383,8 @@ proc fastLog2*(a: Int128): int = proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = assert(divisor != Zero) + result = (Zero, Zero) + let isNegativeA = isNegative(dividend) let isNegativeB = isNegative(divisor) @@ -441,17 +434,17 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = result.remainder = dividend proc `div`*(a, b: Int128): Int128 = - let (a, b) = divMod(a, b) + let (a, _) = divMod(a, b) return a proc `mod`*(a, b: Int128): Int128 = - let (a, b) = divMod(a, b) + let (_, b) = divMod(a, b) return b proc addInt128*(result: var string; value: Int128) = let initialSize = result.len if value == Zero: - result.add "0" + result.add '0' elif value == low(Int128): result.add "-170141183460469231731687303715884105728" else: @@ -472,6 +465,8 @@ proc addInt128*(result: var string; value: Int128) = j -= 1 proc `$`*(a: Int128): string = + # "-170141183460469231731687303715884105728".len == 41 + result = newStringOfCap(41) result.addInt128(a) proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 = @@ -556,24 +551,28 @@ proc toInt128*(arg: float64): Int128 = return res proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] result.udata[1] = arg.udata[1] result.udata[2] = 0 result.udata[3] = 0 proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] result.udata[1] = 0 result.udata[2] = 0 result.udata[3] = 0 proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] and 0xffff result.udata[1] = 0 result.udata[2] = 0 result.udata[3] = 0 proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} = + result = Zero result.udata[0] = arg.udata[0] and 0xff result.udata[1] = 0 result.udata[2] = 0 @@ -590,4 +589,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} = of 8: return maskUInt64(arg) else: - assert(false, "masking only implemented for 1, 2, 4 and 8 bytes") + raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes" |