diff --git a/stint/private/datatypes.nim b/stint/private/datatypes.nim index 86760e0..987af07 100644 --- a/stint/private/datatypes.nim +++ b/stint/private/datatypes.nim @@ -82,26 +82,26 @@ iterator leastToMostSig*(limbs: var Limbs): var Word = iterator leastToMostSig*(aLimbs, bLimbs: Limbs): (Word, Word) = ## Iterate from least to most significant word when cpuEndian == littleEndian: - for i in 0 ..< limbs.len: + for i in 0 ..< aLimbs.len: yield (aLimbs[i], bLimbs[i]) else: - for i in countdown(limbs.len-1, 0): + for i in countdown(aLimbs.len-1, 0): yield (aLimbs[i], bLimbs[i]) iterator leastToMostSig*(aLimbs: var Limbs, bLimbs: Limbs): (var Word, Word) = ## Iterate from least to most significant word when cpuEndian == littleEndian: - for i in 0 ..< limbs.len: + for i in 0 ..< aLimbs.len: yield (aLimbs[i], bLimbs[i]) else: - for i in countdown(limbs.len-1, 0): + for i in countdown(aLimbs.len-1, 0): yield (aLimbs[i], bLimbs[i]) iterator leastToMostSig*(cLimbs: var Limbs, aLimbs: Limbs, bLimbs: Limbs): (var Word, Word, Word) = ## Iterate from least to most significant word when cpuEndian == littleEndian: - for i in 0 ..< limbs.len: + for i in 0 ..< aLimbs.len: yield (cLimbs[i], aLimbs[i], bLimbs[i]) else: - for i in countdown(limbs.len-1, 0): + for i in countdown(aLimbs.len-1, 0): yield (cLimbs[i], aLimbs[i], bLimbs[i]) diff --git a/stint/private/uint_addsub.nim b/stint/private/uint_addsub.nim index c4f11bc..135a1b2 100644 --- a/stint/private/uint_addsub.nim +++ b/stint/private/uint_addsub.nim @@ -7,36 +7,40 @@ # # at your option. This file may not be copied, modified, or distributed except according to those terms. -import ./conversion, ./initialization, - ./datatypes, - ./uint_comparison, - ./uint_bitwise_ops +import + ./datatypes, ./uint_comparison, ./uint_bitwise_ops, + ./primitives/addcarry_subborrow # ############ Addition & Substraction ############ # +{.push raises: [], inline, noInit, gcsafe.} -func `+`*(x, y: UintImpl): UintImpl {.inline.} - # Forward declaration - -func `+=`*(x: var UintImpl, y: UintImpl) {.inline.}= - ## In-place addition for multi-precision unsigned int - type SubTy = type x.lo - x.lo += y.lo - x.hi += (x.lo < y.lo).toSubtype(SubTy) + y.hi # This helps the compiler produce ADC (add with carry) - -func `+`*(x, y: UintImpl): UintImpl {.inline.}= +func `+`*(x, y: Limbs): Limbs = # Addition for multi-precision unsigned int - result = x - result += y + var carry = Carry(0) + for wr, wx, wy in leastToMostSig(result, x, y): + addC(carry, wr, wx, wy, carry) -func `-`*(x, y: UintImpl): UintImpl {.inline.}= +func `+=`*(x: var Limbs, y: Limbs) = + ## In-place addition for multi-precision unsigned int + var carry = Carry(0) + for wx, wy in leastToMostSig(x, y): + addC(carry, wx, wx, wy, carry) + +func `-`*(x, y: Limbs): Limbs = # Substraction for multi-precision unsigned int - type SubTy = type x.lo - result.lo = x.lo - y.lo - result.hi = x.hi - y.hi - (x.lo < y.lo).toSubtype(SubTy) # This might (?) help the compiler produce SBB (sub with borrow) + var borrow = Borrow(0) + for wr, wx, wy in leastToMostSig(result, x, y): + subB(borrow, wr, wx, wy, borrow) -func `-=`*(x: var UintImpl, y: UintImpl) {.inline.}= +func `-=`*(x: var Limbs, y: Limbs) = ## In-place substraction for multi-precision unsigned int - x = x - y + var borrow = Borrow(0) + for wx, wy in leastToMostSig(x, y): + subB(borrow, wx, wx, wy, borrow) -func inc*(x: var UintImpl){.inline.}= - x += one(type x) +func inc*(x: var Limbs, w: SomeUnsignedInt = 1) = + var carry = Carry(0) + when cpuEndian == littleEndian: + addC(carry, x[0], x[0], w, carry) + for i in 1 ..< x.len: + addC(carry, x[i], x[i], 0, carry) diff --git a/stint/private/uint_bitwise_ops.nim b/stint/private/uint_bitwise_ops.nim index 49e6088..0afff9f 100644 --- a/stint/private/uint_bitwise_ops.nim +++ b/stint/private/uint_bitwise_ops.nim @@ -9,27 +9,29 @@ import ./datatypes -func `not`*(x: Limbs): Limbs {.inline.}= +{.push raises: [], inline, noInit, gcsafe.} + +func `not`*(x: Limbs): Limbs = ## Bitwise complement of unsigned integer x for wr, wx in leastToMostSig(result, x): wr = not wx -func `or`*(x, y: Limbs): Limbs {.inline.}= +func `or`*(x, y: Limbs): Limbs = ## `Bitwise or` of numbers x and y for wr, wx, wy in leastToMostSig(result, x, y): wr = wx or wy -func `and`*(x, y: Limbs): Limbs {.inline.}= +func `and`*(x, y: Limbs): Limbs = ## `Bitwise and` of numbers x and y for wr, wx, wy in leastToMostSig(result, x, y): wr = wx and wy -func `xor`*(x, y: Limbs): Limbs {.inline.}= +func `xor`*(x, y: Limbs): Limbs = ## `Bitwise xor` of numbers x and y for wr, wx, wy in leastToMostSig(result, x, y): wr = wx xor wy -func `shr`*(x: Limbs, k: SomeInteger): Limbs {.inline.} = +func `shr`*(x: Limbs, k: SomeInteger): Limbs = ## Shift right by k. ## ## k MUST be less than the base word size (2^32 or 2^64) @@ -46,7 +48,7 @@ func `shr`*(x: Limbs, k: SomeInteger): Limbs {.inline.} = result[i] = (x[i] shr k) or (x[i-1] shl (WordBitWidth - k)) result[0] = x[0] shr k -func `shl`*(x: Limbs, k: SomeInteger): Limbs {.inline.}= +func `shl`*(x: Limbs, k: SomeInteger): Limbs = ## Compute the `shift left` operation of x and k when cpuEndian == littleEndian: result[0] = x[0] shl k diff --git a/stint/private/uint_comparison.nim b/stint/private/uint_comparison.nim index eafa9b0..48832da 100644 --- a/stint/private/uint_comparison.nim +++ b/stint/private/uint_comparison.nim @@ -11,16 +11,18 @@ import ./datatypes, ./primitives/addcarry_subborrow -func isZero*(n: SomeUnsignedInt): bool {.inline.} = +{.push raises: [], inline, noInit, gcsafe.} + +func isZero*(n: SomeUnsignedInt): bool = n == 0 -func isZero*(limbs: Limbs): bool {.inline.} = +func isZero*(limbs: Limbs): bool = for word in limbs: if not word.isZero(): return false return true -func `<`*(x, y: Limbs): bool {.inline.}= +func `<`*(x, y: Limbs): bool = # Lower comparison for multi-precision integers var diff: Word var borrow: Borrow @@ -28,25 +30,25 @@ func `<`*(x, y: Limbs): bool {.inline.}= subB(borrow, diff, wx, wy, borrow) return bool(borrow) -func `==`*(x, y: Limbs): bool {.inline.}= +func `==`*(x, y: Limbs): bool = # Equal comparison for multi-precision integers for wx, wy in leastToMostSig(x, y): if wx != wy: return false return true -func `<=`*(x, y: Limbs): bool {.inline.}= +func `<=`*(x, y: Limbs): bool = # Lower or equal comparison for multi-precision integers not(y < x) -func isEven*(x: SomeUnsignedInt): bool {.inline.} = +func isEven*(x: SomeUnsignedInt): bool = (x and 1) == 0 -func isEven*(x: Limbs): bool {.inline.}= +func isEven*(x: Limbs): bool = x.leastSignificantWord.isEven -func isOdd*(x: SomeUnsignedInt): bool {.inline.} = +func isOdd*(x: SomeUnsignedInt): bool = not x.isEven -func isOdd*(x: Limbs): bool {.inline.}= +func isOdd*(x: Limbs): bool = not x.isEven