Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ dprint.json
*.log
htmldocs
docs
nimble.develop
nimbledeps
4 changes: 2 additions & 2 deletions config.nims
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# begin Nimble config (version 1)
when fileExists("nimble.paths"):
# begin Nimble config (version 2)
when withDir(thisDir(), system.fileExists("nimble.paths")):
include "nimble.paths"
# end Nimble config
38 changes: 33 additions & 5 deletions stint/private/datatypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import
# Status lib
stew/bitops2
stew/[bitops2, staticfor],
std/macros

when sizeof(int) == 8 and not defined(Stint32):
type
Expand Down Expand Up @@ -115,8 +116,6 @@ func usedBitsAndWords*(a: openArray[Word]): tuple[bits, words: int] =
# Iterations
# --------------------------------------------------------

import std/macros

proc replaceNodes(ast: NimNode, what: NimNode, by: NimNode): NimNode =
# Replace "what" ident node by "by"
proc inspect(node: NimNode): NimNode =
Expand Down Expand Up @@ -145,6 +144,35 @@ macro staticFor*(idx: untyped{nkIdent}, start, stopEx: static int, body: untyped
body.replaceNodes(idx, newLit i)
)

const
staticForMaxBitSize = 4096
staticForMaxIterCount = staticForMaxBitSize div WordBitWidth

macro smartFor*(idx: untyped, slice: untyped, body: untyped): untyped =
result = newStmtList()

let
staticForSym = bindSym("staticFor")
maxIterCountSym = bindSym("staticForMaxIterCount")

result.add quote do:
when compiles(static(`slice`)):
const s = `slice`
when len(s) <= `maxIterCountSym`:
`staticForSym`(`idx`, s):
`body`
else:
for i in s.a .. s.b:
block:
let `idx` {.inject.} = i
`body`
else:
let s = `slice`
for i in s.a .. s.b:
block:
let `idx` {.inject.} = i
`body`

# Copy
# --------------------------------------------------------
{.push raises: [], inline, noinit, gcsafe.}
Expand All @@ -155,7 +183,7 @@ func copyWords*(
numWords: int) =
## Copy a slice of B into A. This properly deals
## with overlaps when A and B are slices of the same buffer.
for i in countdown(numWords-1, 0):
a[startA+i] = b[startB+i]
smartFor(i, 0 ..< numWords):
a[startA + (numWords - 1 - i)] = b[startB + (numWords - 1 - i)]

{.pop.}
6 changes: 3 additions & 3 deletions stint/private/uint_addsub.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import
func sum*(r: var StUint, a, b: StUint) =
## Addition for multi-precision unsigned int.
var carry = false
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
(r[i], carry) = carryingAdd(a[i], b[i], carry)
r.clearExtraBitsOverMSB()

Expand All @@ -31,7 +31,7 @@ func `+=`*(a: var StUint, b: StUint) =
func diff*(r: var StUint, a, b: StUint) =
## Substraction for multi-precision unsigned int.
var borrow = false
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
(r[i], borrow) = borrowingSub(a[i], b[i], borrow)
r.clearExtraBitsOverMSB()

Expand All @@ -42,7 +42,7 @@ func `-=`*(a: var StUint, b: StUint) =
func inc*(a: var StUint, w: Word = 1) =
var carry = false
(a.limbs[0], carry) = carryingAdd(a.limbs[0], w, carry)
for i in 1 ..< a.limbs.len:
smartFor(i, 1 ..< a.limbs.len):
(a.limbs[i], carry) = carryingAdd(a.limbs[i], 0, carry)
a.clearExtraBitsOverMSB()

Expand Down
14 changes: 7 additions & 7 deletions stint/private/uint_bitwise.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,34 @@ import
func bitnot*(r: var StUint, a: StUint) =
## Bitwise complement of unsigned integer a
## i.e. flips all bits of the input.
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
r[i] = not a[i]
r.clearExtraBitsOverMSB()

func bitor*(r: var StUint, a, b: StUint) =
## `Bitwise or` of numbers a and b.
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
r[i] = a[i] or b[i]

func bitand*(r: var StUint, a, b: StUint) =
## `Bitwise and` of numbers a and b.
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
r[i] = a[i] and b[i]

func bitxor*(r: var StUint, a, b: StUint) =
## `Bitwise xor` of numbers x and y.
for i in 0 ..< r.limbs.len:
smartFor(i, 0 ..< r.limbs.len):
r[i] = a[i] xor b[i]
r.clearExtraBitsOverMSB()

func countOnes*(a: StUint): int =
result = 0
for i in 0 ..< a.limbs.len:
smartFor(i, 0 ..< a.limbs.len):
result += countOnes(a[i])

func parity*(a: StUint): int =
result = parity(a.limbs[0])
for i in 1 ..< a.limbs.len:
smartFor(i, 1 ..< a.limbs.len):
result = result xor parity(a.limbs[i])

func leadingZeros*(a: StUint): int =
Expand All @@ -56,7 +56,7 @@ func leadingZeros*(a: StUint): int =
# Adjust when we use only part of the word size
var extraBits = WordBitWidth * a.limbs.len - a.bits

for i in countdown(a.limbs.len-1, 0):
for i in countdown(a.limbs.high, 0):
let zeroCount = a.limbs[i].leadingZeros()
if extraBits > 0:
result += zeroCount - min(extraBits, WordBitWidth)
Expand Down
4 changes: 2 additions & 2 deletions stint/private/uint_div.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import
func shortDiv*(a: var Limbs, k: Word): Word =
## Divide `a` by k in-place and return the remainder.

for i in countdown(a.high, 0):
(a[i], result) = narrowingDiv(result, a[i], k)
smartFor(i, 1 ..< a.len + 1):
(a[^i], result) = narrowingDiv(result, a[^i], k)

func shlAddMod_multi(a: var openArray[Word], c: Word,
M: openArray[Word], mBits: int): Word =
Expand Down
16 changes: 8 additions & 8 deletions stint/private/uint_shift.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func shrSmall*(r: var Limbs, a: Limbs, k: SomeInteger) =
# instead of a[i-1] and a[i]
# is probably easier to parallelize for the compiler
# (antidependence WAR vs loop-carried dependence RAW)
for i in 0 ..< a.len - 1:
smartFor(i, 0 ..< a.len - 1):
r[i] = (a[i] shr k) or (a[i + 1] shl (WordBitWidth - k))
r[^1] = a[^1] shr k

Expand All @@ -35,23 +35,23 @@ func shrLarge*(r: var Limbs, a: Limbs, w, shift: SomeInteger) =
if w > Limbs.len:
return

for i in w ..< a.len - 1:
smartFor(i, w ..< a.len - 1):
r[i - w] = (a[i] shr shift) or (a[i + 1] shl (WordBitWidth - shift))
r[^(1 + w)] = a[^1] shr shift

func shrWords*(r: var Limbs, a: Limbs, w: SomeInteger) =
## Shift right by `w` word.
for i in 0 ..< Limbs.len - w:
smartFor(i, 0 ..< Limbs.len - w):
r[i] = a[i + w]
for i in Limbs.len - w ..< Limbs.len:
smartFor(i, Limbs.len - w ..< Limbs.len):
r[i] = 0

func shlSmall*(r: var Limbs, a: Limbs, k: SomeInteger) =
## Compute the `shift left` operation of `x` and `k`.
##
## `k` MUST be less than the base word size (2^32 or 2^64).
r[0] = a[0] shl k
for i in 1 ..< a.len:
smartFor(i, 1 ..< a.len):
r[i] = (a[i] shl k) or (a[i - 1] shr (WordBitWidth - k))

func shlLarge*(r: var Limbs, a: Limbs, w, shift: SomeInteger) =
Expand All @@ -61,14 +61,14 @@ func shlLarge*(r: var Limbs, a: Limbs, w, shift: SomeInteger) =
return

r[w] = a[0] shl shift
for i in 1 + w ..< r.len:
smartFor(i, 1 + w ..< r.len):
r[i] = (a[i - w] shl shift) or (a[i - w - 1] shr (WordBitWidth - shift))

func shlWords*(r: var Limbs, a: Limbs, w: SomeInteger) =
## Shift left by w word.
for i in 0 ..< w:
smartFor(i, 0 ..< w):
r[i] = 0
for i in 0 ..< Limbs.len - w:
smartFor(i, 0 ..< Limbs.len - w):
r[i + w] = a[i]

# Wrappers
Expand Down
8 changes: 4 additions & 4 deletions stint/uintops.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export StUint

func setZero*(a: var StUint) =
## Set `a` to 0.
for i in 0 ..< a.limbs.len:
smartFor(i, 0 ..< a.limbs.len):
a.limbs[i] = 0

func setSmallInt(a: var StUint, k: Word) =
## Set `a` to k.
a.limbs[0] = k
for i in 1 ..< a.limbs.len:
smartFor(i, 1 ..< a.limbs.len):
a.limbs[i] = 0

func setOne*(a: var StUint) =
Expand All @@ -47,7 +47,7 @@ func one*[bits: static[int]](T: typedesc[StUint[bits]]): T {.inline.} =
result.setOne()

func high*[bits](_: typedesc[StUint[bits]]): StUint[bits] {.inline.} =
for i in 0 ..< result.limbs.len:
smartFor(i, 0 ..< result.limbs.len):
result[i] = high(Word)
result.clearExtraBitsOverMSB()

Expand Down Expand Up @@ -84,7 +84,7 @@ func `<`*(a, b: StUint): bool {.inline.} =
## Unsigned `less than` comparison.
var diff: Word
var borrow: bool
for i in 0 ..< a.limbs.len:
smartFor(i, 0 ..< a.limbs.len):
(diff, borrow) = borrowingSub(a[i], b[i], borrow)
return borrow

Expand Down
Loading